Development record
cmd record-lint and scaffold-sync resolve the repo root with an unscrubbed git rev-parse so an inherited GIT_WORK_TREE redirects the lint or release gate
cmd record-lint and scaffold-sync resolve the repo root with an unscrubbed git rev-parse so an inherited GIT_WORK_TREE redirects the lint or release gate
Evidence
cmd/record-lint/main.go:100 and cmd/scaffold-sync/main.go:64 — exec.Command("git","rev-parse","--show-toplevel") with no cmd.Env. An inherited GIT_WORK_TREE/GIT_DIR from a subdirectory redirects discovery; record-lint (and --release-gate) then lints the wrong tree. Identical shape to the fixed capture.discoverRepoRoot (internal/core/capture/roots.go:67, IsolatedEnv with an explanatory comment). scaffold-sync landed in v0.5.0 as a verbatim copy AFTER the principles doc declared the git-subprocess sweep "audited clean".
Adversarial verdict: CONFIRMED (nitpick)
Reachability real (empirically GIT_WORK_TREE=/x git rev-parse --show-toplevel returns /x, and record-lint loads that tree's config). Dev-only tools, fail-closed if the redirected tree lacks the config — hence nitpick. Fix: cmd.Env = gitutil.IsolatedEnv() on both (both already fall back to os.Getwd, so no CI regression). Also corrects two overstated "sweep finished / audited clean" sentences in the principles note. Not prior art: iss-45 (surface-boundary duplication, no env angle), iss-264 (output sanitisation).
Frontmatter
| id | iss-311 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | nitpick |
.abcd/work/issues/resolved/iss-311-cmd-record-lint-and-scaffold-sync.md
open on GitHub ↗ · commit history ↗
mentions4
- dcn-26082000000000032026-08-20 — Bug-hunt round 1 (hunt A), landed late: the round ran 2026-08-19 on a branch that
- iss-45surface-layer boundary leaks: slug derivation — business logic every front door needs — lives in the CLI surface (internal/surface/cli/cli.go:623) so each future front door must reimplement it; cmd/record-lint is a second binary front door duplicating abcd docs lint --config --root, and as a CI gate it has no tests; skills/consult and skills/ingest bypass the abcd binary entirely, their engine being unversioned scripts in the user home (converges with iss-27 corpus-tooling absorption and the script-first-mvp bounds). Detector: a transport-agnostic-core boundary check — decisions live below the surface, front doors only format; one binary front door per capability. Acceptance corpus: the three leaks above.
- iss-264cmd/record-lint prints Finding.File and Finding.Message raw — no termsafe.Sanitize and no path scrub on the findings path (its scrubPaths covers only the two error exits), so any rule echoing repo content lets a hostile clone inject terminal escapes into CI logs, and any finding message embedding an os error can leak absolute paths. The abcd CLI surface sanitizes at its findings renderer; the standalone binary does not. Found by the spc-27 security review, which also caught (and the change fixed) the one in-diff instance.
- iss-2609090947359464discoverRepoRoot is the unhardened twin of the rules-root resolver that was hardened in the same batch. Its git call is properly isolated, and its own comment explains why: an inherited GIT_WORK_TREE or GIT_DIR would redirect discovery at a different tree. The fallback beneath that call has neither guard the sibling grew. Where git will not answer, the loop walks upward accepting any directory whose git entry merely exists, with no shape check of the kind plausibleRepository performs and no ownership check of the kind foreignOwnerRefusal performs, so an empty directory named for the marker in a shared ancestor, or a real repository another uid laid there, would bound the ledger root exactly as it bounded the rules root before that fix.