Skip to content

Chore/toolchain independence enhancement#61

Merged
fredbi merged 2 commits into
go-openapi:masterfrom
fredbi:chore/toolchain-independence-enhancement
Jul 16, 2026
Merged

Chore/toolchain independence enhancement#61
fredbi merged 2 commits into
go-openapi:masterfrom
fredbi:chore/toolchain-independence-enhancement

Conversation

@fredbi

@fredbi fredbi commented Jul 15, 2026

Copy link
Copy Markdown
Member

Change type

Please select: 🆕 New feature or enhancement|🔧 Bug fix'|📃 Documentation update

Short description

Fixes

Full description

Checklist

  • I have signed all my commits with my name and email (see DCO. This does not require a PGP-signed commit
  • I have rebased and squashed my work, so only one commit remains
  • I have added tests to cover my changes.
  • I have properly enriched go doc comments in code.
  • I have properly documented any breaking change.

fredbi and others added 2 commits July 15, 2026 12:04
…face

Replace the go/types builder tower (NewInterfaceType/NewFunc/NewSignatureType)
introduced by go-openapi#60 with mustIfaceFromSource, which type-checks a one-line
`type T interface{ MarshalText() ([]byte, error) }` snippet under a nil importer.
The snippet imports nothing (its result types []byte and error are Universe
types), so the type-checker never consults an importer: same zero-runtime-
resolution guarantee as the synthesized interface, but readable and extensible
to other stdlib interfaces (json.Marshaler, fmt.Stringer) by editing a string.

Guard the scope lookup so a snippet that type-checks but declares no interface T
panics wrapping ErrInternal instead of nil-dereferencing, matching the sibling
Must* assertions. Cover the helper contract with TestMustIfaceFromSource.

Also drop a stray empty doc-comment line before `package godoclink` (gofmt).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
Add a bespoke build-once / run-in-a-foreign-environment CI matrix
(.github/workflows/toolchain-independence.yml), separate from the shared
go-test workflow, that locks the property go-openapi#60 fixed: IsTextMarshaler must not
depend on a working build-time toolchain/GOROOT at runtime.

- job A builds the resolvers + integration test binaries on `stable`.
- job B (pinpoint) runs the resolvers binary under `env -i` — no Go present at
  all — proving the interface resolution resolves nothing at runtime.
- job C (full workflow) runs the integration binary on `oldstable` with the
  build-time GOROOT removed and GOROOT unset, so the old go/importer path would
  fail while packages.Load still self-locates on PATH.

TestToolchainIndependence_FullScan backs job C: a self-check that the baked
runtime.GOROOT() is absent (fails loudly on masking) plus a full-scan symptom
assertion that TextMarshaler fields still render as strings. It skips unless
CODESCAN_TC_JOBC=1, so a normal `go test ./...` is unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
@fredbi

fredbi commented Jul 15, 2026

Copy link
Copy Markdown
Member Author

@KT-Doan Kevin this is the follow-up I've been talking about:

  • the synthetic interface is resolved by parsing a code snippet without import
  • a full CI integration test simulates your bug report, with tests being built and run with different go minor versions

@codecov

codecov Bot commented Jul 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 81.63%. Comparing base (391fff1) to head (d420f3f).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##           master      #61      +/-   ##
==========================================
+ Coverage   81.60%   81.63%   +0.03%     
==========================================
  Files          84       84              
  Lines        8513     8528      +15     
==========================================
+ Hits         6947     6962      +15     
  Misses       1146     1146              
  Partials      420      420              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR strengthens codescan’s resilience to Go toolchain/build-vs-run environment divergence by making encoding.TextMarshaler detection independent of go/importer and by adding CI + integration coverage to prevent regressions when the runtime toolchain/GOROOT differs from the build-time one.

Changes:

  • Replace encoding.TextMarshaler interface resolution with a toolchain-independent go/types type-check of a synthetic interface snippet.
  • Add targeted unit tests and a bespoke CI workflow to validate behavior with no Go toolchain and with divergent build/run toolchains.
  • Add an integration guard that runs only under the dedicated CI job to validate end-to-end scan output.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
internal/builders/resolvers/assertions.go Switches TextMarshaler interface resolution to a synthetic, type-checked interface.
internal/builders/resolvers/resolvers_test.go Adds tests for the new mustIfaceFromSource helper and its panic/error contract.
internal/integration/coverage_toolchain_independence_test.go Adds an integration test that enforces correctness under a build!=run toolchain divergence scenario.
/.github/workflows/toolchain-independence.yml Introduces a dedicated workflow with “no Go present” and “divergent toolchain” jobs.
internal/builders/godoclink/godoclink.go Minor comment formatting change.

fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "iface.go", src, 0)
if err != nil {
panic(fmt.Errorf("parsing synthetic interface source %q: %w: %w", src, err, ErrInternal))
// nil importer: the snippet imports nothing, so the type-checker never invokes it.
pkg, err := new(types.Config).Check("p", fset, []*ast.File{f}, nil)
if err != nil {
panic(fmt.Errorf("type-checking synthetic interface source %q: %w: %w", src, err, ErrInternal))
Comment on lines +86 to +88
// The importer reads stdlib export data out of the GOROOT the binary was built against:
// when GOTOOLCHAIN selects a different toolchain at runtime — or the callgin binary simply runs on a machine where
// Go installation lives at a different path than the build machine's — the lookup fails, and the error is silently
@fredbi
fredbi merged commit 0c2878c into go-openapi:master Jul 16, 2026
24 checks passed
@fredbi
fredbi deleted the chore/toolchain-independence-enhancement branch July 16, 2026 11:25
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.

2 participants