Skip to content

fix(sandbox): mount GOMODCACHE read-only so air-gapped analysis resolves deps#26

Merged
svczero merged 1 commit into
mainfrom
fix/sandbox-mount-gomodcache
Jun 11, 2026
Merged

fix(sandbox): mount GOMODCACHE read-only so air-gapped analysis resolves deps#26
svczero merged 1 commit into
mainfrom
fix/sandbox-mount-gomodcache

Conversation

@svczero

@svczero svczero commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Problem

The Semantic Analysis check fails on every PR that touches the analysis engine (#21 and #24 were merged over it). It's a false-fail, not a code defect.

Root cause (confirmed empirically): the sandbox mounts GOROOT and GOCACHE read-only but forces GOPATH=/tmp/gopath, so the module cache is empty inside the air gap. With GOPROXY=off and sfw's hardened -mod=readonly, any file importing an external module (golang.org/x/tools/go/ssa, pebble, …) can't build SSA, so sfw diff errors on it. The CI's vendoring workaround never took effect because GetHardenedEnv() strips inherited GOFLAGS and force-sets -mod=readonly, which ignores vendor/.

Fix

Mirror the existing GOCACHE handling for GOMODCACHE: bind-mount the host module cache read-only at /gomodcache and point GOMODCACHE at it. GetHardenedEnv() preserves the inherited GOMODCACHE, so packages.Load resolves dependencies from the mounted cache while GOPROXY=off keeps the air gap intact. This completes the GOMODCACHE handling that resolveGoToolchain's doc comment already promised.

  • internal/sandbox/manager.go — resolve + mount GOMODCACHE read-only; reserve /gomodcache.
  • internal/sandbox/manager_test.go — assert the mount + env appear in the generated spec.
  • .github/workflows/semantic_analysis.yml — drop the now-dead vendoring + GOFLAGS=-mod=vendor; prime the base worktree's module graph so go.mod-changing PRs resolve on both sides.

Validation

  • Reproduced the failure locally (empty cache → failed to build SSA; vendoring does not rescue it).
  • go build ./..., go vet ./..., go test ./internal/sandbox/ all pass.
  • Self-validating: this PR builds sfw with the fix, so its own Semantic Analysis run exercises the corrected sandbox.

Security

No reduction in isolation — the module cache is mounted read-only, the GOPROXY=off air gap is preserved, and there is no new network or write surface. Same posture as the existing GOCACHE mount.

The Semantic Analysis check failed on every PR for two reasons:

1. setup-go installed Go 1.24, but go.mod requires 1.26.3, and sfw runs the
   loader with GOTOOLCHAIN=local -- so `go list` refused: "go.mod requires
   go >= 1.26.3 (running go 1.24.13; GOTOOLCHAIN=local)". Use
   go-version-file: go.mod so CI installs exactly what go.mod requires.

2. BLOCKER mode (fail on ANY semantic change) was applied to every pull_request,
   so intentional feature changes failed with "Logic change detected in safe
   refactor!". BLOCKER is now opt-in via a 'semantic-safe' label; all other PRs
   run in 'check' mode (report the diff, don't fail).

Also drop the dead vendoring + GOFLAGS=-mod=vendor (GetHardenedEnv strips GOFLAGS
and forces -mod=readonly, so vendoring never took effect), and print sfw's actual
error on failure instead of swallowing it.
@svczero svczero force-pushed the fix/sandbox-mount-gomodcache branch from 8d9f3e8 to c6f9f56 Compare June 11, 2026 19:39
@svczero svczero merged commit e9192a5 into main Jun 11, 2026
2 checks passed
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.

1 participant