Skip to content

feat: isolated cwd_mode for untrusted launcher CWD (RM-13) - #33

Merged
AviBackToBlack merged 7 commits into
mainfrom
roadmap/RM-13-cwd-mode
Aug 20, 2026
Merged

feat: isolated cwd_mode for untrusted launcher CWD (RM-13)#33
AviBackToBlack merged 7 commits into
mainfrom
roadmap/RM-13-cwd-mode

Conversation

@AviBackToBlack

@AviBackToBlack AviBackToBlack commented Aug 20, 2026

Copy link
Copy Markdown
Owner

Why

Filed as a follow-up in issue #2 (split out of RM-12/issue #29's "Related finding" section,
because it changes a different mechanism — RunTool's project-root logic, not a new declared
mount). Confirmed real during RM-12's scoping: dockerrun.RunTool always treats the process's
CWD as, or as the basis for, a project. For an interactive CLI invocation (cd D:\my-project; npx eslint .) that's correct. For a background/GUI/MCP launcher that inherits an arbitrary CWD
it doesn't control — e.g. Claude Desktop launching an MCP server shim with
C:\Windows\System32 as the inherited working directory — it isn't: today that produces a real
bind mount of System32 into the container, plus (for a stateful tool) a project-scoped volume
keyed by a hash of that path.

What changed

New registry field cwd_mode, two values:

  • "project" (default, and an unset value is byte-for-byte identical to it) — unchanged
    behavior. This PR does not touch the default path's outcome, only how it's computed internally
    (see refactor note below).
  • "isolated" — skips project-root discovery entirely, never bind-mounts the host CWD, sets
    --workdir /root, and routes any argument path through the existing external /cb/mounts/N
    narrow-mount logic (no new mount mechanism — the same code path already used for any argument
    outside a project root). project_volumes on an isolated tool is a registry-load-time error;
    shared_volumes/host_mounts/env allowlisting are completely unaffected, which is exactly why
    RM-12's host_mounts and this feature are designed to compose (an isolated background tool
    gets its state via shared_volumes/host_mounts, never via a project-scoped volume).

RunTool was refactored into three functions along the way — resolveRunContext (computes
root/workspace/workdir), buildDockerArgs (pure argv construction, no Docker/daemon calls), and
ensureDockerVolumes (the volume side-effects) — so the isolated-mode branch and its test
coverage stay clean without duplicating the whole function.

Review depth

This touches the project's own documented "highest-risk area" (a silently-wrong-mount bug class,
not a crash), so it got the corresponding scrutiny: SWE-1.7 Max implement → GLM-5.2 blind verify.
Round 1 found one real gap — the default-mode regression test only called the pure argv-builder
with a hand-constructed context, never the refactored resolveRunContext itself, so the branch
handling a CWD nested under a discovered project root (rel != ".") had zero coverage despite
being exactly the kind of thing a refactor of this function could silently break. Fixed with
three targeted tests exercising resolveRunContext directly (no markers, nested-under-marker,
and an end-to-end default-mode argv pin), verified in a second GLM pass to confirm they're not
tautological — each asserts against independently-derived expected values, not values echoed
back from the function under test.

Independently re-validated at every stage (not just the implementer's reports) inside
golang:1.24:

gofmt -l . ; go vet ./... && go test -race ./...

Clean throughout.

Validation

MSYS_NO_PATHCONV=1 docker run --rm -v "D:\Work\GIT\container-bin:/src" -w /src -e GOFLAGS=-buildvcs=false golang:1.24 sh -c "gofmt -l . ; go vet ./... && go test -race ./..."

🤖 Generated with a multi-agent pipeline (SWE-1.7 Max implementer, GLM-5.2 High blind verifier, orchestrated by Claude Code)


Open in Devin Review

AviBackToBlack and others added 4 commits August 20, 2026 00:52
Add `cwd_mode` registry field. "project" (default/empty) preserves existing
byte-for-byte behavior; "isolated" skips project-root detection, sets
`--workdir /root`, and never bind-mounts the host CWD. Argument path mapping
still runs against a sentinel root so every path falls through to the existing
external `/cb/mounts/N` mount logic. `project_volumes` is rejected when
`cwd_mode = "isolated"` because a project-scoped volume requires a project
identity. `cb inspect` and `cb trace` expose the isolated mode behavior.

Registry, dockerrun, and CLI tests cover parsing, validation, the default-mode
regression (byte-for-byte unchanged argv), isolated-mode no-CWD-mount/workdir,
and the external path mapping. README documents the new field.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…13 r2)

GLM-5.2 flagged that the default-mode regression test only called
buildDockerArgs with a hand-built runContext, never exercising the
refactored resolveRunContext or the rel != "." branch. Add three tests:

- resolveRunContext with no project markers: root == cwd, found == false,
  workspaceRoot == "/workspace", containerWD == "/workspace"
- resolveRunContext with cwd nested under a .git marker: root == parent,
  found == true, containerWD == "/workspace/subdir"
- end-to-end default-mode argv: resolveRunContext -> buildDockerArgs equals
  the pre-refactor argv exactly

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds cwd_mode = "isolated" to prevent untrusted launcher CWDs from becoming project mounts.

Changes:

  • Adds and validates the registry setting.
  • Refactors Docker context, argument, and volume construction.
  • Updates diagnostics, documentation, and tests.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
README.md Documents isolated mode.
internal/registry/registry.go Parses and validates cwd_mode.
internal/registry/registry_test.go Tests registry behavior.
internal/dockerrun/dockerrun.go Implements isolated execution.
internal/dockerrun/dockerrun_test.go Tests Docker arguments and context resolution.
internal/cli/cli.go Updates inspect and trace output.
internal/cli/cli_test.go Tests isolated diagnostics.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread internal/cli/cli.go

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 6 potential issues.

Open in Devin Review

Comment thread internal/cli/cli.go
Comment thread internal/dockerrun/dockerrun.go
Comment thread internal/dockerrun/dockerrun.go
Comment thread internal/registry/registry.go
Comment thread internal/dockerrun/dockerrun.go
Comment thread internal/dockerrun/dockerrun_test.go
AviBackToBlack and others added 2 commits August 20, 2026 01:16
…-13 r3)

The python provider has its own project/compat venv split via
pathmap.PythonEnvID. With cwd_mode = "isolated", RunTool forces found=false,
which would make an isolated python tool silently use the shared
"cb-python-313-global" compat volume. Reject the combination at registry load
rather than patching every consumer (cli.Env, internal/state, self-test cleanup).

Also reject cwd_mode = "isolated" with a non-empty project_markers list,
because project_markers are dead configuration when project-root detection is
skipped.

Add tests for both rejections and a README sentence noting that cb expose
generated profiles do not inherit cwd_mode.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

Suppressed comments (2)

README.md:208

  • The documented compatibility rules omit two registry-load failures introduced here: isolated mode is also rejected for the python provider and whenever project_markers is declared. As written, users are told only project_volumes is incompatible and will get unexpected validation errors for otherwise documented profiles. List all three restrictions here.
under `/cb/mounts/N`. `cwd_mode = "isolated"` cannot be combined with
`project_volumes` (a project-scoped volume conceptually requires a project
identity), but `shared_volumes`, `host_mounts` and environment allowlisting work
exactly as they do in project mode. Exposed profiles created by `cb expose`
from an npm-shaped source profile do **not** inherit that source's `cwd_mode`.

internal/dockerrun/dockerrun_test.go:253

  • This test hand-constructs the isolated runContext, so it never exercises the new isolated branch in resolveRunContext. A regression there could restore the wrong workdir/root while this builder test stays green—the same gap the new default-mode resolver tests avoid. Resolve the context from the tool here and assert its isolated fields before building the argv.
	ctx := runContext{
		cwd:           cwd,
		root:          IsolatedRoot,
		workspaceRoot: "/root",
		containerWD:   "/root",

README's isolated-mode section only named project_volumes as incompatible,
not the python-provider and project_markers rejections added in the r3
commit. Listed all three.

TestBuildDockerArgsIsolatedNoCwdMount hand-built its runContext, the same
gap GLM caught for the default-mode tests in round 2 -- a regression in
resolveRunContext's isolated branch could restore a real root/workdir while
that builder-only test stayed green. Added TestResolveRunContextIsolated
calling resolveRunContext directly and chaining into buildDockerArgs,
mirroring the round-2 default-mode fix pattern.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@AviBackToBlack
AviBackToBlack merged commit b357e2b into main Aug 20, 2026
7 checks passed
@AviBackToBlack
AviBackToBlack deleted the roadmap/RM-13-cwd-mode branch August 20, 2026 00:30
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.

2 participants