Repository navigation
[FOU-588] Build the Go module graph of a go.work workspace - #843
Conversation
vet built no module graph for a module that a go.work workspace uses, because the go command builds such a module with the build list of the workspace, and no single go.mod holds it. So each Go finding of a workspace stayed unknown with no graph. vet itself is such a workspace. vet now passes the go.work that it finds to modgraph, which gives the build list of the workspace. Another module of the workspace is local code, so it passes its imports on. A module that only the workspace adds is no package of this go.mod, and it passes its imports on too. A reached module that go.mod requires and that maps to no package still gives no graph. A relative GOWORK gives no graph, because the go command refuses it. safedep/code is pinned to the head of its branch claude/go-work-graph. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PFQbqPqd9xn1fT6hBsyoUm
A review of safedep/code#56 found six inputs where the build list of a workspace differed from the go command. The fixed head follows readModGraph and the vendor rules of the go command. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PFQbqPqd9xn1fT6hBsyoUm
SafeDep Report SummaryPackage Details
This report is generated by SafeDep GitHub App |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
…pace (#842) * [FOU-586] Read the Go module graph of a go.mod from the code on the disk A go.mod lists the modules of a build, but not which module imports which. So each Go vulnerability finding of a module that the code does not import stayed unknown with the cause no-graph. vet could not say unused or imported via X, and could not prove not-called. The codeusage enricher now builds the graph of each go.mod with safedep/code modgraph. modgraph reads the import blocks of the Go files of the main module and of each module of the build list in vendor, in a local replacement inside the target or in the module cache. It runs no go command and downloads nothing. The engine asks a new plugin.Grapher for the graph of a manifest with none, during the extraction, and stores it with the manifest. A module with no source on the disk is open: it may import any module. model.Graph keeps the open nodes, and the scan file stores them. The reach rules read them: a path of known edges gives imported via X, a path that only an open module gives is unknown with the cause no-dependency-source, and no path is unused. One diagnostic counts the open modules and says to run go mod download. Scalibr lists the target of a replace directive in place of the module. The go.mod extractor now records the module that it replaces, as Package.Replaces. The code usage and the graph map a replaced module by it, so its imports count. vet builds no graph for a module that a go.work uses, or for a go.mod below go 1.17. Its findings keep no-graph. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PFQbqPqd9xn1fT6hBsyoUm * [FOU-586] Take imports from the roots of the Go module graph A review of the Go module graph found false unused results. The reach rules took the imported packages from the code usage, which covers the whole target and skips the build, target and dist directories. So a module that only a skipped directory imports read as unused. A module that only another go.mod of the target imports gave paths into this go.mod. The standard library has no import path, so it read as unused. The module graph of a go.mod now marks itself as a graph of imports, and the scan file keeps the mark. For such a graph the reach rules take the imported packages from its roots, which are the imports of the code of that module. The standard library is always imported. A reached module that maps to no package of the manifest hid its imports, for example when two replace directives name one target. Now that module gives no graph. vet also reads GOWORK as the go command does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PFQbqPqd9xn1fT6hBsyoUm * [FOU-586] Resolve links in GOWORK and refuse a relative GOWORK A review found two inputs that gave a module graph for a module of a workspace. vet compared a use path in the spelling of GOWORK with the canonical scan root, so a GOWORK through a link never matched the module. On macOS each target under /tmp or /var is such a link. vet also read a relative GOWORK from its own directory, but the go command refuses a relative GOWORK. vet now resolves the links of both paths before it compares them. A relative GOWORK counts as a workspace that holds the module, so the module gets no graph. The docs say that vet does not read a GOWORK that go env -w sets. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PFQbqPqd9xn1fT6hBsyoUm * [FOU-586] Find a go.work above the scan root and bump codeusage The search for a go.work stopped at the scan root. The go command searches each parent directory, so a scan of one module of a workspace missed the workspace and built a graph from go.mod alone. That graph can give a false unused. The search now goes up to the root of the file system. A go.work outside the scan root is named by its full path. The mapping of a replaced Go module changed the data of the codeusage enricher, so its Version goes from 11 to 12. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PFQbqPqd9xn1fT6hBsyoUm * [FOU-586] docs: Say that the module graph runs no build The doc comment of Graph said that it runs no go command. To find the module cache, vet can run go env once for each process. The comment now says that the graph runs no build and downloads nothing, as docs/output.md says. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PFQbqPqd9xn1fT6hBsyoUm * [FOU-586] Pin safedep/code to the head of main safedep/code#54 merged, so vet no longer needs the head of its branch. The pin moves to the head of main, which holds the same tree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PFQbqPqd9xn1fT6hBsyoUm * [FOU-588] Build the Go module graph of a go.work workspace (#843) * [FOU-588] Build the Go module graph of a go.work workspace vet built no module graph for a module that a go.work workspace uses, because the go command builds such a module with the build list of the workspace, and no single go.mod holds it. So each Go finding of a workspace stayed unknown with no graph. vet itself is such a workspace. vet now passes the go.work that it finds to modgraph, which gives the build list of the workspace. Another module of the workspace is local code, so it passes its imports on. A module that only the workspace adds is no package of this go.mod, and it passes its imports on too. A reached module that go.mod requires and that maps to no package still gives no graph. A relative GOWORK gives no graph, because the go command refuses it. safedep/code is pinned to the head of its branch claude/go-work-graph. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PFQbqPqd9xn1fT6hBsyoUm * [FOU-588] Pin safedep/code to the fixed head of claude/go-work-graph A review of safedep/code#56 found six inputs where the build list of a workspace differed from the go command. The fixed head follows readModGraph and the vendor rules of the go command. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PFQbqPqd9xn1fT6hBsyoUm --------- Co-authored-by: Claude <noreply@anthropic.com> * [FOU-588] Pin safedep/code to the head of main safedep/code#56 merged, so vet no longer needs the head of its branch. The head of main holds the same tree as the reviewed branch head, fe48e4f, which also makes the paths of Discover absolute. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PFQbqPqd9xn1fT6hBsyoUm * [FOU-588] Add an acceptance script for a workspace with no graph docs/output.md says that vet builds no module graph for a workspace whose build list it cannot know, and that its findings keep unknown with the cause no-graph. No acceptance script held that guarantee. The new script covers a go.mod of the build list that is not on the disk, a workspace module outside the target, and an exclude directive. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PFQbqPqd9xn1fT6hBsyoUm --------- Co-authored-by: Claude <noreply@anthropic.com>




What was wrong
vet built no module graph for a module that a
go.workworkspace uses. The go command builds such a module with the build list of the workspace, which no singlego.modholds. So each Go finding of a workspace stayedunknown · no graph. vet itself is such a workspace.What this changes
go.workthat it finds tomodgraph.Discover(feat(modgraph): the build list of a go.work workspace code#56), which gives that build list.go.work. It readsGOWORK, and else searches the parents of the module directory, as the go command does. A relativeGOWORKgives no graph, because the go command refuses it.go.mod, so an import of them passes on the imports of their code:go.modrequires. Such a module that maps to no package still gives no graph.Discoverfails, and vet keeps no graph, when:go.modthat the build list needs is not on the diskgo.modhas anexcludedirectivedocs/output.mddescribes workspaces, and the glossary entry of the dependency graph names them.reach/import/go-workspace-graphand its catalog row are new.Field run
Go vulnerability findings of the root
go.mod:.and./scripts)Known gap
A finding gives the version that its
go.modrequires. The workspace can build a higher version, and the reach then describes the code of that version.docs/output.mdsays so.Tests
codeusage:GOWORKwith a path, through a link, and relativego.moddoes not require, which passes its imports onreach/import/go-workspace-graphcovers an import through another workspace module, an import through a module of the module cache, andunused. It fails on the base branch.make checkpasses.Order
This pull request stacks on #842 and targets its branch. safedep/code is pinned to the head of safedep/code#56. Once both merge, I retarget this pull request to
v2and pin safedep/code tomain.Generated by Claude Code