Skip to content

v1.91.112.0 fix(cso): --paths scopes an audit and reports every skipped path (no more hand-trimmed copies) - #3230

Merged
capy-ai[bot] merged 9 commits into
mainfrom
capy/paths-scopes-an-audit
Oct 17, 2026
Merged

capy-ai[bot] merged 9 commits into
mainfrom
capy/paths-scopes-an-audit

Conversation

@garrytan

@garrytan garrytan commented Oct 16, 2026 •

Copy link
Copy Markdown
Owner

Fast-track fix from field list 2, item 12 (wrong security result). GBRA-120 reviewed gbrain security fix gbrain#6853 on a hand-trimmed copy of src/core and src/mcp, because gbrain is over /cso's 64 MiB source admission cap and the cap message said "run /cso on a smaller checkout". cso then treated the trimmed copy as the whole repository: snapshot-inputs coverage read assessed, and the verdict never said what was left out. So the tool's own advice produced a clean-looking verdict over partial input.

What changes

gstack-cso start --paths <prefix,prefix,...> lets cso narrow itself and disclose what it left out:

  • Every listed file outside the prefixes gets a manifest entry recorded from lstat only (originalHash: not-read, transformation withheld: outside the --paths audit scope, never excluded:). It isn't copied, assessed, or counted toward the 64 MiB cap. snapshot-inputs coverage becomes partial with one bounded gap per skipped path, and the evidence line names the prefixes and the skipped count. The race checks, the special-file rejection and the manifest validator are unchanged.

  • Validation rejects empty, . or .. segments, a leading - or /, backslashes and control characters, more than 32 prefixes or 1024 characters, and a prefix that matches no source file.

  • --diff fails closed. A changed, added or deleted path outside --paths refuses with INVALID_ARGUMENT and names those paths, including credential and agent configuration such as .npmrc, bunfig.toml and .claude/. Only host dependency trees (node_modules, vendor/bundle and similar), which are never read with or without --paths, are exempt. To support this, out-of-scope files are hashed in bounded 1 MiB chunks for changed-path detection only when a comparison base is set; without a base, no out-of-scope payload is ever opened. A refused --diff recheck says to start a new audit.

  • Git history is limited to the --paths prefixes, history-inputs coverage reads partial with a gap naming the limit, and history RUN PATH refuses an out-of-scope path. In-scope gaps are listed before skipped paths so the bounded list never hides them, and out-of-scope deletions are reported as skipped, not as in-scope deletions.

  • A --paths prefix that report persistence would rewrite (redaction or the CI run-id rewrite) is refused, so a run can't reject its own in-scope findings.

  • Findings and rechecks stay in scope. submit refuses a finding whose root cause is outside --paths. Recheck rebuilds --paths from the original policy, and recheck evidence that cites a withheld path is refused. Replay with --source rereads the scope from the run's report, where before it would have failed every scoped bundle's input-hash check.

  • Only sourceCapMessage now points to --paths (and warns against hand-trimmed copies). The manifest cap (16 MiB) and the entry limit still count one entry per file, so their guidance is unchanged. A gbrain-sized repo (11,570 tracked files) is well under both.

  • /cso skill: an Arguments row for --paths, plus a Phase 13 rule that a --paths run states partial snapshot-inputs coverage and summarizes the skipped paths. Four sentences were tightened and one duplicate was dropped to stay under the parity skeleton cap.

  • docs/troubleshooting.md: the cso-capacity entry now points to --paths for the source cap instead of "a smaller checkout".

Not in this PR: automatic scoping to the diff plus sibling call sites (the rest of item 12) is in the field-list-2 autoplan, behind a measurement spike.

Known limits: under --paths, the original-source hash ignores content changes outside the scope (replay still runs only the in-scope snapshot); out-of-scope files are hashed with no byte cap, only the time budget; --paths with --comprehensive runs on a trimmed tree; a recheck refuses if the audited directory was renamed.

Tests

New test/cso-audit-paths.test.ts (9 cases) covers: which cap advice each failure prints; a repo over the cap admitted with --paths, with exact withheld entries, gaps, partial snapshot and history coverage, out-of-scope history refusal and out-of-scope deletions; in-scope gaps ordered first; bounded-chunk hashing with a comparison base (mutation-checked); no out-of-scope payload opened without a base; invalid and redaction-altered values refused with no run left behind; the --diff refusal in both directions, including .npmrc and AGENTS.md (mutation-checked); recheck carrying --paths, including the --diff recheck refusal; and replay keeping the scope. At fbb96db: focused cso suites 169 pass, troubleshooting-anchors, parity and gen-skill-docs 656 pass, typecheck and format:cso:check clean.

Review: /review ran three rounds with adversarial passes; every finding above Low is fixed. The final adversarial pass (GPT, 66 launcher probes at dcf955d) found no P0/P1 and no new P2/P3. The remaining items are under Known limits.

E2E gate: 0 paid cases selected and run ($0.00); the planner deferred the 14 /cso behavior cases and 2 changed prompt files to scheduled/release runs, so this PR is not eval-verified.

Field list: GBRA-40's field list 2 plus the GBRA-108 addendum (item 12). Related: #2993.

Open in Capy

A repo over the 64 MiB cap was audited on hand-trimmed copies, so the
verdict read assessed over partial input. --paths records out-of-scope
files unread as snapshot-inputs gaps (coverage partial), keeps --diff
fail-closed, and carries the scope through submit, recheck and replay.
Field list 2 item 12; related #2993.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
@trunk-io

trunk-io Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

😎 This pull request was merged.

@github-actions

Copy link
Copy Markdown
Contributor

E2E Evals: ✅ PASS

[test:paid] VERDICT GREEN — lane gate/pr, attempt 1
  rule 0/0 · behavior 0/0 · judge 0/0 · quarantined 0 (0 failing the lane)
  SKIPPED 0 · INFRA 0 · INCOMPLETE 0 · unattributed 0 · ACTION REQUIRED 0
  wall 0m00s · cost $0.00

0 executed, 0 reused rule/judge records | 0 manual accepted (unscored; no score-cache credit) | $0 rule/judge cost | reconcile exit: 0

Profile: pr / mode pr; selected behaviors: 0, judges: 0. Deferred to scheduled/release coverage: 14 behaviors and 2 changed prompt files. Deferred checks did not run and receive no PR-pass credit.

Rule and judge shards
Shard Automated result Manual/unscored Executed Reused Status Cost
Fail-closed reconciliation
[test:paid] report: 1/1 slices, 0 planned shards, tier=gate, attempt 1
[test:paid] coverage: profile=pr mode=pr; selected E2E=0, judges=0
[test:paid] deferred: 14 broad behaviors, 2 changed prompts without quick live coverage; these are not PR passes
[test:paid] collector final outcomes: 0 executed, 0 reused; 0 passed, 0 failed, 0 manual accepted (unscored; no score-cache credit) (0 attempt records from 0 collectors; every record counts)
[test:paid] VERDICT GREEN — lane gate/pr, attempt 1
  rule 0/0 · behavior 0/0 · judge 0/0 · quarantined 0 (0 failing the lane)
  SKIPPED 0 · INFRA 0 · INCOMPLETE 0 · unattributed 0 · ACTION REQUIRED 0
  wall 0m00s · cost $0.00
[test:paid] report: every planned shard accounted and passed

Sliced lane: planner → duration-packed executors → fail-closed report. Behavior cases run a pre-registered 3-trial panel (PASS at 2/3 with no contract violation); a PASS 2/3 is shown with its failed trial, never as a clean pass. Reused results retain their original provenance and expiry.

garrytan and others added 6 commits October 16, 2026 23:30
- Comparison mode hashes out-of-scope files in bounded 1 MiB chunks and
  re-hashes them in both stability passes instead of reading whole files.
- --diff --paths refuses every changed path outside the scope except host
  dependency trees, including credential and agent configuration.
- --paths prefixes that report persistence would rewrite are refused.
- In-scope gaps sort first; out-of-scope files and deletions share the
  skipped tier and are dropped from transformations.
- History is limited to --paths, reported as partial, and history queries
  on out-of-scope paths are refused.
- A --diff recheck refused for out-of-scope changes says to start a new audit.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
…ed path (#3230)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
@github-actions github-actions Bot changed the title fix(cso): --paths scopes an audit and reports every skipped path (no more hand-trimmed copies) v1.91.112.0 fix(cso): --paths scopes an audit and reports every skipped path (no more hand-trimmed copies) Oct 17, 2026
…audit

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

# Conflicts:
#	CHANGELOG.md
#	VERSION
#	agents-digest/gstack-AGENTS.md
#	package.json
…audit

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

# Conflicts:
#	CHANGELOG.md
#	VERSION
#	agents-digest/gstack-AGENTS.md
#	package.json
@capy-ai
capy-ai Bot merged commit 299e051 into main Oct 17, 2026
68 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