Adopt `/v8` major version module path for Go module compliance
Summary
Concourse is currently at v8.x, but go.mod still declares the module path as github.com/concourse/concourse — without the required /v8 major version suffix. This violates Go's Import Compatibility Rule and causes a cascade of practical problems for downstream users, vulnerability scanners, and the Go ecosystem tooling.
This issue proposes updating the module path to github.com/concourse/concourse/v8 and rewriting all internal imports accordingly.
Draft PR: https://github.com/concourse/concourse/pull/9716
The Problem
Since go.mod was introduced in commit a7a7c12 (Sep 2018), the module path has remained github.com/concourse/concourse despite the project shipping v5, v6, v7, and v8 releases. Under Go's module rules, any module at v2+ must include the major version suffix in its module path.
Because this is missing, the Go toolchain rejects Concourse's v8 releases:
$ go install github.com/concourse/concourse/[email protected]
go: version "v8.2.5" invalid: go.mod has non-.../v8 module path
$ GOPROXY=proxy.golang.org go list -m github.com/concourse/[email protected]
go: github.com/concourse/[email protected]: invalid version: module contains a go.mod file,
so module path must match major version ("github.com/concourse/concourse/v8")The Go module proxy (pkg.go.dev) shows the latest valid version as v4.2.3 (the last release before go.mod was added) or v1.6.1-0.<timestamp>-<commit> pseudoversions. Every release from v5 through v8 is invisible to standard Go tooling.
Why This Matters Now
1. False-Positive CVE Reports
Because vulnerability databases and scanners (Go Vuln DB, Trivy, Grype, Snyk, Dependabot, GitHub's own security advisories) resolve Concourse through proxy.golang.org, they see the latest valid version as v4.2.3. Any CVEs fixed in v5–v8 are perpetually flagged as unpatched whenever downstream code or scanners evaluate the module. As @taylorsilva noted in PR #9701:
"This would probably help with a bunch of CVE's that get flagged sometimes since we're not following this pattern."
This is not a hypothetical — Issue #9560 ("Outdated Go dependencies with known CVEs") and Issue #8508 ("Dependency Dashboard") are direct consequences.
2. go install Is Broken for fly
Users cannot install fly via the standard Go toolchain:
$ go install github.com/concourse/concourse/[email protected]
# fails: go.mod has non-.../v8 module pathAs documented in Issue #9682 (fly: macOS binaries are unsigned):
"Note that
go install github.com/concourse/concourse/[email protected]does not work:go.modwas never migrated to the/v8module path, so no v2+ tag resolves. You have to clone at the tag andgo build ./fly."
3. Go Module Proxy and Package Index Are Broken
As reported in Issue #7109 by a FreeBSD port maintainer, the Go module index returns pseudoversions like v1.6.1-0.20210527214455. The Go team confirmed this is working as intended:
"concourse is using modules (go.mod) but not versioning in accordance with policy, so the version numbers are pseudoversions… closing as working as intended."
4. Downstream Consumers Can Already Import Packages via Commit SHA ("Preventing Imports" Is an Illusion)
A recurring justification for not adopting module versioning has been: "we don't want people importing the monorepo." But the Go toolchain does not enforce a barrier just because a /v8 suffix is missing. Anyone can already import any Concourse package in a Go project simply by specifying a git commit SHA:
go get github.com/concourse/concourse/fly@<commit-sha>The Go toolchain accepts this, but resolves it to an awkward, unpinned pseudoversion:
github.com/concourse/concourse v1.6.1-0.20220907210330-17dbb45a7667Using "we want to prevent people importing it" as an excuse is therefore invalid: people can already import Concourse packages, but are forced to use brittle commit-hash workarounds. Not versioning does not prevent imports—it only degrades the developer experience, breaks dependency resolution, and complicates downstream maintenance.
5. Go Documentation on pkg.go.dev Is Broken and Frozen in 2018
Because Concourse's go.mod lacks the /v8 major version suffix, the official Go package documentation index (pkg.go.dev) cannot index any release past v4.2.3. The result is a broken and misleading public presence:
- Legacy packages like
github.com/concourse/[email protected]+incompatibleorgithub.com/concourse/concourseare flagged with the+incompatiblebadge, frozen in late 2018, and still list archaic packages (code.google.com/p/go.crypto/ssh,bosh_utils). The modern v8 codebase is entirely invisible. - In contrast, properly versioned Go modules—including Concourse ecosystem projects such as Pix4D/cogito—enjoy clean, first-class documentation with README rendering, example blocks, navigable directory hierarchies, and verified version badges.
Adopting /v8 immediately brings Concourse back onto pkg.go.dev with accurate, modern documentation for fly, atc, and other packages.
Prior Discussion & Historical Context
This topic has been discussed multiple times. Here is a summary of the key threads and the evolution of the maintainers' position:
Key Issues
| Issue | Title | Date | Summary |
|---|---|---|---|
| #3952 | Improper Module Versioning | May 2019 | Original report. @vito explained the "primarily an application" stance. Closed Jan 2025 (Issue Bankruptcy). |
| #7109 | Go index servers show v1.6.1 | May 2021 | FreeBSD port maintainer unable to package Concourse. @taylorsilva stated "the main repo isn't designed as a go library/package at all." Closed Jan 2025 (Issue Bankruptcy). |
| #9682 | fly: macOS binaries unsigned | Aug 2026 | Documents that go install .../[email protected] is broken due to missing module path. |
| #9560 | Outdated Go dependencies with CVEs | May 2026 | Lists CVEs that scanners flag because module proxy sees only v4.2.3. |
| #9701 | Update Go to 1.27.1 | Sep 2026 | @taylorsilva acknowledged the need to "review prior discussion before making a decision" and opened the door to adopting /v8. |
Historical Concerns vs. Current Reality
| Concern (2019) | Original Reasoning (@vito) | Counter-Argument (2026) |
|---|---|---|
| "Concourse is primarily an application" | "We're not really intending to provide the whole repo as an importable package/module." (#3952) | Go module rules apply equally to applications and libraries. The rule exists so the Go toolchain can resolve, install, and audit the module — not just import it. go install, govulncheck, pkg.go.dev, and OS package managers all require valid module semantics. |
| "Prevent people from importing the monorepo" | "We're not really intending to provide the whole repo as an importable package/module." (#3952) | Not adopting /v8 does not prevent imports. Anyone can already import any Concourse package by pointing to a commit SHA (go get github.com/concourse/concourse/fly@<sha>). Withholding proper module versioning doesn't stop external consumption; it only forces users into awkward pseudoversions, breaks go install, and degrades Go tooling for everyone. |
| "Product versions, not API versions" | "The tags on the repo correspond to product versions, not an API version. I don't really want to wrangle all our import statements every time we ship a major version, since the version doesn't even really indicate any sort of Go interface compatibility." (#3952) | The /vN suffix is a Go module system requirement, not a semver compatibility promise to importers. Many large Go applications use it without implying a stable public API (see Precedent below). |
| "Too much code churn" | "It'd result in a lot of pointless internal code churn every time we do a major version bump." (#3952) | The entire rewrite is a mechanical 2-liner that can be scripted and committed to the repo (see Automation below). With AI-assisted development and standard unix tools, this is no longer a valid concern. |
| "Extract go-concourse instead" | "I think we should extract go-concourse and give it a proper versioning scheme." (#3952) |
This was proposed in 2019 and never happened. Adopting /v8 on the monorepo is far simpler than extracting and maintaining a separate module. |
Precedent: Other Go Applications Using /vN
Concourse is not unique in being a Go application (not a library) at a high major version. Several comparable CNCF/infrastructure projects — primarily applications, not libraries — correctly use the major version suffix:
| Project | Type | Module Path | Version |
|---|---|---|---|
| containerd | Container runtime (application) | github.com/containerd/containerd/v2 |
v2.x |
| Woodpecker CI | CI/CD system (application) — Drone fork | go.woodpecker-ci.org/woodpecker/v3 |
v3.x |
| Grafana Loki | Log aggregation (application) | github.com/grafana/loki/v3 |
v3.x |
| Coder | Remote dev environments (application) | github.com/coder/coder/v2 |
v2.x |
Notably, Woodpecker CI is a fork of Drone (itself a CI/CD system very similar to Concourse in purpose) and correctly uses /v3. containerd is a runtime that Concourse itself depends on and uses /v2.
These projects demonstrate that the "primarily an application" argument does not exempt a project from Go module best practices. The Go blog itself recommends find + sed for the import rewrite (Go Modules: v2 and Beyond):
$ find . -type f \
-name '*.go' \
-exec sed -i -e 's,github.com/my/project,github.com/my/project/v2,g' {} \;The Import Rewrite Is Fully Automatable
The main historical objection was that rewriting ~3,000 import lines across ~1,300 files is tedious churn. In practice, the entire operation is completely automatable with a short bash script:
#!/usr/bin/env bash
set -euo pipefail
OLD_VER="${1:-v8}"
NEW_VER="${2:-v9}"
echo "==> Bumping Concourse module path: ${OLD_VER} -> ${NEW_VER}"
# 1. Update go.mod
sed -i "s|module github.com/concourse/concourse/${OLD_VER}|module github.com/concourse/concourse/${NEW_VER}|" go.mod
# 2. Update config files (e.g. .deepsource.toml)
if [ -f .deepsource.toml ]; then
sed -i "s|github.com/concourse/concourse/${OLD_VER}|github.com/concourse/concourse/${NEW_VER}|g" .deepsource.toml
fi
# 3. Rewrite all internal Go imports
find . -type f -name "*.go" -not -path "./vendor/*" -exec \
sed -i "s|\"github.com/concourse/concourse/${OLD_VER}|\"github.com/concourse/concourse/${NEW_VER}|g" {} +
# 4. Regenerate counterfeiter fakes
echo "==> Regenerating counterfeiter fakes..."
go generate ./...
# 5. Tidy module dependencies
echo "==> Tidying go.mod and go.sum..."
go mod tidy
echo "==> Successfully bumped to ${NEW_VER}!"This can be committed as scripts/bump-major-version.sh in the repository.
Total wall-clock time: ~5–10 seconds (the find + sed rewrite across all 1,286 files takes less than 0.5 seconds). This is no longer a maintenance burden — it is an instantaneous, trivially scriptable one-time command per major release (once per year).
What This PR Changes
The draft PR contains a single commit that:
- Updates
go.mod:module github.com/concourse/concourse→module github.com/concourse/concourse/v8 - Rewrites all internal Go imports:
"github.com/concourse/concourse/..."→"github.com/concourse/concourse/v8/..."across ~1,283 files - Updates
.deepsource.toml: import path configuration
All counterfeiter-generated fakes are included with updated import paths. The change is purely mechanical — no logic, no behavior changes, no API modifications.
What This Fixes
Once merged and a new v8.x.x tag is pushed:
- ✅
go install github.com/concourse/concourse/v8/[email protected]works out of the box - ✅
pkg.go.dev/github.com/concourse/concourse/v8shows the real latest version and generates rich, modern package documentation and README examples (similar to Pix4D/cogito), replacing outdated+incompatiblev4.2.x artifacts - ✅ Vulnerability scanners resolve Concourse at its actual version, eliminating false-positive CVE reports
- ✅ OS package managers (FreeBSD ports, Homebrew, etc.) can resolve Concourse via the Go module proxy
- ✅ Downstream Go projects can cleanly import Concourse packages via semantic versions without resorting to commit SHA workarounds (
@<commit-sha>) - ✅ Future major bumps (v9, v10...) are scriptable in ~10 seconds with
scripts/bump-major-version.sh
References
Go Official Documentation
- Go Modules: v2 and Beyond — Official guide on major version module paths
- Keeping Your Modules Compatible — Compatibility best practices
- Import Compatibility Rule — Russ Cox's original design document
- Semantic Import Versioning — Go wiki
Concourse Prior Discussion
- Issue #3952 — Improper Module Versioning (2019–2025)
- Issue #7109 — Go index shows v1.6.1 (2021–2025)
- Issue #9682 — fly macOS binaries unsigned (2026)
- Issue #9560 — Outdated Go deps with CVEs (2026)
- PR #9701 — Discussion about adopting /v8 (2026)
- golang/go#46494 — Go team confirms pseudoversions are expected (2021)
Source: concourse/concourse