Skip to content

Raise the go directive floor to 1.25 - #40

Merged
norman-abramovitz merged 4 commits into
masterfrom
raise-go-floor
Jul 29, 2026
Merged

Raise the go directive floor to 1.25#40
norman-abramovitz merged 4 commits into
masterfrom
raise-go-floor

Conversation

@norman-abramovitz

Copy link
Copy Markdown
Contributor

Closes #38. Partially addresses #39 (the Fuzzing and Vulnerabilities checks).

Breaking change. The minimum Go version becomes 1.25, up from 1.18.
Consumers on an older toolchain stay on v1.22.0.

Why now

The 1.18 floor had stopped being a compatibility promise and become the thing
blocking maintenance. Every current release of the three dependencies declares
a directive above it:

Module Was Now Requires
golang.org/x/net v0.35.0 (2025-02-10) v0.57.0 go 1.25.0
golang.org/x/text v0.22.0 (2025-02-04) v0.40.0 go 1.25.0
github.com/onsi/gomega v1.27.10 v1.42.1 go 1.25.0

The frozen pins carried 16 known vulnerabilities between them — 15 in
x/net v0.35.0 and 1 in x/text v0.22.0, per OSV. All three modules now
report 0.

govulncheck was green the whole time and still is: it does reachability
analysis, and none of those were reachable from this package. Scanners that
report on presence rather than reachability disagreed, and consumers run those.
OpenSSF Scorecard is one — its Vulnerabilities check scored 0 with
"13 existing vulnerabilities detected".

1.25 is the lowest floor admitting all three upgrades, so it is the one that
costs consumers least.

Three things resolved themselves

  • .modrotignore is now empty. gomega v1.42.1 depends on the maintained
    go.yaml.in/yaml/v3 rather than the archived gopkg.in/yaml.v3. The
    exemption recorded "Revisit if gomega ever drops the dependency" as its
    removal condition — met, so the entry is gone and the archived-dependency
    gate now runs with no exemptions at all.
  • copyloopvar and intrange needed no config change. Both were already
    in the enable: list; golangci-lint was disabling them at runtime with
    "this linter is disabled because the Go version (1.18) of your project is
    lower than Go 1.22". They now run, and report nothing.
  • The Dependabot holds are removed. They existed only to describe this
    blockage. The replacement comment notes the remaining real hazard: a
    dependency raising its own directive above the floor is still a breaking
    change for consumers, so check the go line in any proposed bump.

Fuzzing (#39)

FuzzNew covers the VCAP_APPLICATION and VCAP_SERVICES parsing New
performs. Both documents originate with the platform and with bound brokers,
never with the app, so this package is the boundary that has to survive
whatever arrives.

The property: New returns an app or an error for any input and never panics,
and the accessors stay total on anything that decoded. Seeded with the shapes
already known to be awkward — nested credentials, volume mounts, a null
limits, empty strings. 9.7 million executions found nothing.

make test runs the seed corpus, since Go fuzz targets are also ordinary
tests. make fuzz searches; FUZZTIME raises the budget.

Verification

  • make check clean — including both newly-active linters
  • make test-race passes, coverage 93.6%
  • make govulncheck clean, make gosec clean
  • make modrot clean, with an empty ignore list
  • OSV queried directly for each upgraded module: 0 known vulnerabilities

Also carries the changelog.d sweep for the fragment v1.22.0 consumed.

The 1.18 floor had become the thing blocking dependency maintenance.
Every current release of x/net, x/text and gomega declares a directive
above it, so the pins were frozen at versions carrying 16 known
vulnerabilities between them -- 15 in x/net v0.35.0 and 1 in x/text
v0.22.0. All three are now current and OSV reports none.

govulncheck stayed green throughout, because it does reachability
analysis and none of those were reachable from this package. Scanners
that work from presence rather than reachability disagreed, and
consumers run those.

1.25 is the lowest floor that admits all three, so it is the one that
costs consumers least.

Two things fell out rather than needing separate work:

  - copyloopvar and intrange were already enabled in .golangci.yml but
    disabled at runtime by golangci-lint itself for being above the
    project's directive. They now run, and report nothing.
  - gomega v1.42.1 moved from the archived gopkg.in/yaml.v3 to the
    maintained go.yaml.in/yaml/v3, which is exactly the removal
    condition the .modrotignore entry recorded. That file is now empty.

The Dependabot holds documented the same blockage and go with it.
Both documents New parses originate with the platform and the brokers
bound to an app, never with the app itself, so this package is the
boundary that has to survive whatever arrives. The property is that New
returns an app or an error for any input and never panics, and that the
accessors stay total on anything that decoded.

Seeded with the shapes already known to be awkward: nested credentials,
volume mounts, a null limits object, and empty strings. `make test`
runs the seed corpus, since Go fuzz targets are also ordinary tests;
`make fuzz` searches.

9.7 million executions found nothing.
@norman-abramovitz
norman-abramovitz merged commit aa9a7eb into master Jul 29, 2026
6 checks passed
@norman-abramovitz
norman-abramovitz deleted the raise-go-floor branch July 29, 2026 10:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Raise the go directive floor to clear stale indirect dependencies

1 participant