feat(detector): inventory Go modules and audit Go configuration - #230
Merged
ashishkurmi merged 5 commits intoSep 30, 2026
Merged
Conversation
Add two optional enterprise telemetry sections, go_inventory and go_config_audit (schema_version 1), sent as full bounded snapshots on every run, independent of the npm/Python deltas. go_inventory statically collects go.mod/go.work declarations, alternate -modfile manifests, vendor/modules.txt, the module cache and binaries in the resolved GOBIN, with recorded (never verified) checksums from go.sum, go.work.sum, .ziphash and BuildInfo. go_config_audit reports an allowlist of Go env settings from the user go/env file, the verified process environment and GOROOT/go.env, redacted on the device, with findings go-001..go-006. The collector runs no commands, sources no shell and makes no network calls. Every read goes through guarded, bounded executor file methods (new opt-in ReadDirLimit), protected directories stay excluded even with include_tcc_protected, and any refusal, failure or limit marks the affected source partial so it never reads as absence.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Collection bounds, Windows path handling, archive validation, and nil-logger safety have unresolved correctness issues.
Review effort: Balanced
Findings: 2
Open (4)
What changed in this PR
Adds bounded Go module inventory and configuration auditing to enterprise telemetry.
Changes:
- Inventories projects, workspaces, vendor/cache modules, tools, and checksums.
- Audits and redacts Go environment configuration.
- Adds guarded directory limits, telemetry wiring, documentation, and tests.
| File | Description |
|---|---|
SCAN_COVERAGE.md |
Documents Go scan coverage and safety. |
README.md |
Advertises Go inventory and configuration auditing. |
go.mod |
Adds golang.org/x/mod. |
go.sum |
Records dependency checksums. |
internal/telemetry/telemetry.go |
Runs and emits the Go scan. |
internal/telemetry/telemetry_out_test.go |
Tests optional telemetry sections. |
internal/executor/executor.go |
Adds bounded directory reads. |
internal/executor/mock.go |
Implements bounded reads in the mock. |
internal/executor/mock_test.go |
Tests bounded executor reads. |
internal/executor/user_aware.go |
Delegates the new executor method. |
internal/safepath/reader.go |
Adds guarded bounded directory reads. |
internal/safepath/reader_test.go |
Tests limits and guard behavior. |
internal/model/model.go |
Defines Go telemetry contracts. |
internal/model/go_golden_test.go |
Validates schema vocabulary and references. |
internal/model/testdata/go_inventory_v1_golden.json |
Provides the schema golden fixture. |
internal/detector/goscan.go |
Implements Go evidence collection. |
internal/detector/goscan_test.go |
Exercises scanner behavior and limits. |
internal/detector/gometadata.go |
Parses Go manifests, caches, and build metadata. |
internal/detector/gometadata_test.go |
Tests metadata parsing and checksums. |
internal/detector/configaudit/goenv.go |
Audits and sanitizes Go configuration. |
internal/detector/configaudit/goenv_test.go |
Tests configuration safety and findings. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+53
to
+55
| func NewGoScanner(exec executor.Executor, log *progress.Logger) *GoScanner { | ||
| return &GoScanner{exec: exec, log: log, protection: configaudit.GoProtection} | ||
| } |
|
|
||
| // Record budget, in sorted order so the same records survive every run. | ||
| // Dropped rows always mark their owning source incomplete. | ||
| budget := maxGoRecords |
Comment on lines
+272
to
+273
| if !strings.HasPrefix(f.Name, prefix) { | ||
| return model.GoArtifactUnreadable |
Comment on lines
+455
to
+458
| // goPathWithin reports whether path is strictly below dir, lexically. | ||
| func goPathWithin(path, dir string) bool { | ||
| return len(path) > len(dir) && strings.HasPrefix(path, dir) && | ||
| (path[len(dir)] == filepath.Separator || strings.HasSuffix(dir, string(filepath.Separator))) |
Spend the Go record budget as records and sources are collected instead of trimming output in finish(): once it runs out nothing more is read, and the truncated source and every enclosing root are marked partial with record_limit. Compare filesystem paths case-insensitively on Windows and macOS for root dedup and overlap, workspace members, -modfile containment, the manifest lookup and vendor dedup. Module paths, emitted paths and source IDs keep their original case. Validate module ZIP entry paths as x/mod/zip's checkZip does.
6 of 9 tasks
ashishkurmi
approved these changes
Sep 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


What does this PR do?
Adds Go evidence to enterprise telemetry as two optional sections,
go_inventoryandgo_config_audit(eachschema_version: 1). Both are full bounded snapshots sent on every run, independent of the npm/Python deltas.go_inventory(static, no Go toolchain needed)go.mod/go.workfound by one bounded walk of the configured search roots. Requirements, replacements, excludes, tools and workspace membership, parsed withgolang.org/x/mod/modfile.-modfilefromGOFLAGS, split the same waycmd/gosplits it.vendor/modules.txt, counted only when a package directory exists on disk.module@versiondirectories andcache/downloadarchives. ZIP metadata is checked but never decompressed. Extraction completeness follows Go's.partial/.ziphashrules.GOPATH/bin), read viadebug/buildinfo.go.sum,go.work.sum, alternate.sum,.ziphashand BuildInfoSum. These attach only to existing evidence, and are alwaysnot_verified.go_config_auditgo/envfile, the process environment (only when the agent runs as the developer), andGOROOT/go.env.go-001..go-006: sumdb off,GOINSECURE, private proxy falling back to a public one, credentials in URLs,GOAUTHcommand, malformed or duplicate keys.Safety properties
UserAwareExecutor. Every read goes through guarded, bounded executor file methods.Executor.ReadDirLimit(boundedReadDir). ExistingReadDir/ReadFileare unchanged.include_tcc_protected. The only exception is the exact macOS default~/Library/Application Support/go/envfile.GOAUTHarguments and non-moduleGOFLAGSare dropped. BuildInfo settings are never read.partialwith a reason code, so it never reads as absence. Record and output caps (16 MiB for both sections) keep a status envelope.Wiring: a new
go_scanphase afterbrowser_extensions_scanreuses the resolved browser target user. Communityscanoutput is unchanged.golang.org/x/mod v0.39.0becomes a direct dependency, with no other module changes.Contract: the golden fixture
internal/model/testdata/go_inventory_v1_golden.jsonis strictly decoded and round-tripped. Tests also check reference integrity and coverage of the whole vocabulary. The same bytes are meant for the Agent API tests.Type of change
SCAN_COVERAGE.md,README.md)Testing
make smoke: 45/45)make lint(gofmt, vet, golangci-lint: 0 issues)make test(go test ./... -race -count=1)Also:
CGO_ENABLED=0builds for linux/amd64, darwin/arm64 and windows/amd64;go mod tidyshows no drift.os.OpeninReal.ReadDirLimit. It mirrors the existingReadDir/ReadFile.send-telemetry --telemetry-outruns with an isolated config and fake endpoint, reading the real home.go_scantook about 5 s.Not yet done (release checks):
Related Issues