fix(workspaceindex): skip git-ignored and build-cache dirs in Scan only - #1117
FabioLeitao wants to merge 1 commit into
Conversation
Scan has a fixed file budget, and build output (Cargo target/, Python virtualenvs, caches) could exhaust it before real source was reached: repo-map reported truncation and ranked fingerprint files above code. Inside a git work tree, Scan now asks git for the ignored set (`git status --porcelain=v1 -z --ignored=matching .`), so the repo's own .gitignore, nested ignore files, info/exclude and core.excludesFile all apply, including names no fixed list anticipates (.locust_env/). Outside a work tree, or when git is missing, older than 2.16, fails, or exceeds 5s, a fixed list of common build/cache directory names stands in. ShouldSkipDir is unchanged: glob, grep, list_directory and path autocomplete share it and must keep seeing target/, .venv/ and friends. The lookup runs with GIT_OPTIONAL_LOCKS=0 so a per-turn scan never takes .git/index.lock next to a concurrent git command. Fixes Twigpine#1108
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
📒 Files selected for processing (5)
Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 3 remain after this review. WalkthroughWorkspace scans now use Git’s ignored-path data when available. When Git data is unavailable, scans skip a fixed set of build and cache directory names. Tests cover repository scans, fallback behavior, and symlink traversal. ChangesWorkspace scan behavior
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~20 minutes Change: Bug fix · Severity of issue fixed: Medium Sequence Diagram(s)sequenceDiagram
participant Scan as workspaceindex.Scan
participant Lookup as gitIgnoredPaths
participant Git as git
participant FS as filesystem
Scan->>Lookup: Request ignored paths for scan root
Lookup->>Git: Get repository prefix and ignored status
Git-->>Lookup: Return command results
Lookup-->>Scan: Return relative ignored paths or unavailable status
Scan->>FS: Traverse workspace entries
Scan->>Scan: Filter ignored paths or apply fallback skips
Merge Risk: ⚪ Minimal · up to Workspace scans now skip Git-ignored paths and fall back to a fixed build/cache directory list when Git is unavailable. I found no concrete merge-blocking risk in the supplied changes. Security Architecture ReviewSecurity architecture risk: 🟡 Moderate · up to Automatic scanning now delegates to Git, whose configuration can enable executable helpers. The scan timeout also does not guarantee that helper processes terminate or that scanning returns promptly. Existing file-access controls remain intact, and exploitation would require control of effective Git configuration rather than merely a source file or ignore rule. Retained concerns
Security review detailsSecurity Blast Radius
Security Findings and Attack Paths
Trust Boundaries and Controls
Resilience and Maintainability Implications
Hardening Proposals
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Summary
Makes
workspaceindex.Scanskip git-ignored paths and common build-cache directories, so the scan budget (repo-map, MCP resources, the per-turn workspace seed) is spent on source instead oftarget/,.venv/or.locust_env/. This is the shape approved on the issue: everything new lives inScan, andShouldSkipDiris unchanged.What changes
ShouldSkipDiris untouched, soglob,grep,list_directoryand path autocomplete keep seeingtarget/,.venv/,__pycache__/and the rest.git status --porcelain=v1 -z --ignored=matching .. That covers nested.gitignorefiles,info/exclude,core.excludesFile, and names no list anticipates.target,__pycache__,.venv,venv,.pytest_cache,.terraform,.mypy_cache,.ruff_cache. It is a separate helper, notShouldSkipDir.targetis real source there, and git already knows what is build output.What the issue asked for
gitIgnoredPaths.status --ignored=<mode>landed in 2.16 and--porcelain=v1in 2.11. Older git rejects the arguments and takes the non-git path. The git-backed tests skip below 2.16 and say so.buildSystemPromptParts→workspaceSeedContext). Measured: 10ms on Zero itself (1,544 tracked files), 20ms warm / 120ms cold on a 2,411-file Python repo with a large virtualenv. Two short-lived processes (rev-parse --show-prefix, thenstatus) under the 5s bound.BuildFromWorkspace's doc comment said "It performs no git operations"; it now names the one read-only lookup.GIT_OPTIONAL_LOCKS=0(git 2.15; older git ignores it), so a per-turngit statusnever takes.git/index.locknext to agit commit.Edge cases covered by tests
.gitignore-only names (.locust_env/,*.db), an ignored file inside an untracked directory (ls-files --directorymisses it,statusdoes not), and a non-ASCII ignored directory (-z, no C-quoting).--show-prefixto Scan's relative paths.target/inside a repo is scanned.target/debug/.fingerprintfiles, the real source is reached andTruncatedstays false.PATH, even inside a repo: no error, the fixed list applies.ShouldSkipDirstill returns false for every name in the fixed list.GIT_OPTIONAL_LOCKS=1does not re-enable the lock.Tests are hermetic:
HOME,USERPROFILE,XDG_CONFIG_HOME,GIT_CONFIG_GLOBALandGIT_CONFIG_NOSYSTEMare redirected, andGIT_CEILING_DIRECTORIESkeeps aTMPDIRinside some repo from turning a "not a repo" fixture into one.Known limitation:
git statusdoes not descend into a nested independent repository or a submodule, so a build directory inside one is not reported as ignored.mainscans those today too, so this is not a regression; I left it out to keep the change focused.One unrelated fixture changed:
repomap's symlink test named its real directorytarget, which the non-git fallback now skips. It is renamed toreal-dir, with a comment.Linked issue
Fixes #1108
Checklist
issue-approvedlabel.go build ./...,go vet ./..., andgo test ./...pass locally (withumask 022 TMPDIR=/tmp TZ=UTC; see feat(providers): opt-in ZERO_RESPONSE_HEADER_TIMEOUT override for slow first-byte deployments #1106 for the workstation-only failures without them).gofmtclean.-racewhere relevant).Verification
On commit
6e57f7fb, based onmainat99721c76:make fmt-check,go vet ./...,go test -count=1 ./...,go test -raceonworkspaceindex,repomapandworkspaceseed,go run ./cmd/zero-release build,go run ./cmd/zero-release smoke,make vulncheck,git diff HEAD --check: pass.make lint-static: only the 4 findings already onmain(installtest,proxydialx2,web_fetch.go); none in changed files.Cross-compile (
go vet+go test -c) forwindows/amd64,darwin/amd64,darwin/arm64: pass. Tests were not run on macOS or Windows.Each new test fails when its part of the fix is reverted, one revert at a time:
GIT_OPTIONAL_LOCKS=0TestGitCommandDisablesOptionalLocksShouldSkipDir(the earlier draft)TestShouldSkipDirLeavesScanOnlyDirsVisibleToTools,TestScanKeepsTrackedBuildCacheNamedDirInsideGitRepoTestScanKeepsTrackedBuildCacheNamedDirInsideGitRepomain)TestScanHonorsRepoGitignore,…FromSubdirectoryRootTestScanSkipsBuildCacheDirsOutsideGit,TestScanFallsBackWhenGitUnavailablels-files --directoryinstead ofstatusTestScanHonorsRepoGitignore,…FromSubdirectoryRootgosecandsemgrep(p/golang): no new findings compared withmain.gitleakson the branch commit: clean.No dependency changes (
go.mod/go.sumuntouched).Notes
Prepared with AI assistance and reviewed by the human author (HITL), per the contribution guidelines.
Summary by CodeRabbit
New Features
Bug Fixes