Skip to content

damage-control batch 5: path resolution / cwd lane (#1132) - #1139

Merged
dotdevdotdev merged 11 commits into
mainfrom
dc-batch5-paths
Oct 19, 2026
Merged

dotdevdotdev merged 11 commits into
mainfrom
dc-batch5-paths

Conversation

@dotdevdotdev

Copy link
Copy Markdown
Owner

Batch 5 (path resolution / cwd lane) of the damage-control residual inventory. Every statically decidable shape in this lane is closed; the rest fails closed (ask, unverifiable, not demoted by bypass).

Behavior

  • Mission: Hierarchical Dashboard Refactor #15 false blocks removed: rsync writes only its destination (last operand, options may trail); <<$"EOF" is a quoted heredoc; a [a-z] character class no longer counts as a literal run in a glob (echo [a-z]*; echo hi | sh allows).
  • Mission: AgentWire MCP Server #16 cwd the scanner couldn't see: d=<dir>; cd $d && … (same-command literal, last assignment wins, $(…) makes it unknown), env -C/--chdir, patch -d, whitespace inside a prefix assignment (A=${x:-\n} cd …). An unresolvable cd (cd -, popd, cd $x) followed by a distinctive protected name the rest would write is an ask (core.control-plane-target); settings.json/config.yaml are deliberately not distinctive.
  • Connection-aware TTS routing for MCP speak() #17 patch / git apply / git am run in a protected dir ask (--dry-run/--check/--stat… stay allowed).
  • Voice Orchestrator + Worker Sessions (Complete Mission) #20 brace expansion past the cap in a command that names the control plane asks (kill-switch exempt). The inventory's repro was invalid: it tripped the .env zero-access rule, which hides the gap.
  • Add /desktop route with OS-like window manager UI #26 ln/link naming a protected file or dir on either side is refused (the old "source is a read" ruling reverses: a link is how a later write reaches the file). Every path word is realpath'd at hook time (symlink, symlinked dir, hardlink to a protected file) and judged as where it really goes.
  • Wrapper differential: sh -c '…' / ssh host '…' payloads are re-scanned as commands, so cwd resolution applies inside a wrapper (before: bash -c 'cd <dir> && touch <protected name>' allowed while the bare form blocked — a pre-existing gap, found by the differential).
  • Extract CLI and Portal docs from CLAUDE.md #21 perf (separate commit, no decision change): _GLOB_TOKEN retried from every offset of a long run. All three inventory shapes were that one regex, not _PATH_ODDITY/the brace walker: ../×7000 4.9s→0.6s, \×20000 2.1s→0.3s, {a,×7000 1.8s→0.5s; quoted and unquoted runs now double with the input.

Verification

  • New tests/unit/test_path_resolution_lane.py (13 tests, loops collect every offender); 17 mutations of the code under pin, all killed.
  • Differential vs origin/main over 5874 distinct real commands from the audit log: 5 decision changes, all block→ask/allow, all heredoc/prose bodies containing [a-z]*-style classes (the Mission: Hierarchical Dashboard Refactor #15 false block). No new blocks or asks on real traffic.
  • Glob scan fuzz-compared against the old regex (4000 strings, identical words).
  • Fast unit set green after merging origin/main; hooks regenerated (regen_damage_control_hooks.py).
  • Two existing pins moved on purpose: ln -s <protected> /tmp/link (allow→block) and <<-$"EOF" (now a real heredoc).

Docs: wiki updated with the exact new behavior; closed residuals deleted from the declared-residual text (<<$"EOF", glob+pipe, rsync source/dest, patch/apply, symlink/hardlink alias, brace cap, cd $dir/cd -/env -C, whitespace prefix, and the stale rm foo -rf / crontab-comment claims in the same paragraphs).

Not closed, said so: a cwd known only from the session; a project's protected-file directory (not enumerable) for patch/apply; an alias created and written through by the same command from a computed name; TOCTOU.

Closes #1132

Built by dotdev.dev

Closes the statically decidable ways of naming a protected file by
something other than its absolute path, and fixes three wrongful blocks.

- #15 rsync writes only its destination; `<<$"EOF"` is a quoted heredoc;
  a character class no longer counts as a literal run in a glob
- #16 same-command literal var into `cd`, `env -C`/`--chdir`, whitespace
  in an assignment prefix; an unresolvable `cd` (`cd -`, popd, `cd $x`)
  followed by a distinctive protected name is an unbypassable ask
- #17 patch / git apply / git am in a protected dir asks
- #20 brace expansion past the cap in a command naming the control plane
  asks (kill-switch exempt)
- #26 ln/link naming a protected file or dir on either side is refused;
  every path word is realpath'd (symlink, dir alias, hardlink) at hook time
- sh -c / ssh payloads are re-scanned as commands, so the cwd resolution
  applies inside a wrapper (decision == top level)

Built by dotdev.dev
Perf only, no decision change. `_GLOB_TOKEN` was one regex of the shape
`[^delims]*(?:mark)[^delims]*`, which retries from every offset of a long
run holding no glob mark: a 7000-fold `../` run cost 4.9s, 20000 `\` 2.1s,
7000 `{a,` 1.8s (the profile put 85-90% of each in `_glob_variants`).
`_glob_tokens` is one pass over the word runs and yields the same words
(fuzz-compared against the old regex); the shapes now take 0.6/0.3/0.5s and
double when the input doubles.

Built by dotdev.dev
…-segment diffs, wrapper gaps)

B1 unresolvable-cd ask uses control_plane_allowlist; B2 redirects after the
cd target; B3 patch/git apply read-only flags judged per command, verb by
basename; B4 wrapper payloads through timeout/sudo/env/--/ssh -t and \$ in
double quotes; env -iC clusters, nested env -C, unresolved relative cd.

Built by dotdev.dev
…cepts <&- (#1139 review)

_applies_diff takes the head through the shared _command_head helper (the
one wrapper table, also used by the payload rescan) instead of the first
word. _CD_REDIRECTS accepts <& duplications.

Built by dotdev.dev
Built by dotdev.dev
…te ladder's _command_head)

Built by dotdev.dev
…skipped per wrapper (#1139 review)

_wrapped_command_index knows which options of each prefix wrapper take a
separate value (nice -n 5, timeout -k 3, env -u V, sudo -u root, ...), so
attached forms (-n5, -uroot, --adjustment=5) no longer swallow the command.

Built by dotdev.dev
Built by dotdev.dev
Built by dotdev.dev
Built by dotdev.dev
@dotdevdotdev
dotdevdotdev marked this pull request as ready for review October 19, 2026 00:47
@dotdevdotdev
dotdevdotdev merged commit c2ae3b1 into main Oct 19, 2026
5 checks passed
@dotdevdotdev
dotdevdotdev deleted the dc-batch5-paths branch October 19, 2026 00:47
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.

damage-control batch 5: path resolution / cwd lane residuals

1 participant