Skip to content

feat(cli): wire execution permission controls - #1531

Draft
B-A-M-N wants to merge 13 commits into
CodebuffAI:mainfrom
B-A-M-N:security/1450-cli-integration-review-r2
Draft

B-A-M-N wants to merge 13 commits into
CodebuffAI:mainfrom
B-A-M-N:security/1450-cli-integration-review-r2

Conversation

@B-A-M-N

@B-A-M-N B-A-M-N commented Oct 17, 2026 •

Copy link
Copy Markdown

CLI execution permission controls and shell approval queue

Wires the SDK execution-permission controls into the CLI and adds a correlated shell-approval lifecycle. The CLI parses and forwards --no-shell, --ask-shell, --project-only, and --read-only. The approval bridge serializes concurrent requests FIFO and resolves active or queued requests as denied on timeout, abort, or UI shutdown.

PR branch and scope

  • Target base: upstream main
  • Head branch: security/1450-cli-integration-review-r2
  • Head: ce39e6c2cb002927b73616e79fbc6ea69f74823b
  • Depends on #1506 and #1530.
  • Incremental diff from patch head 6611d08c6d6a1017f9a7fa9e12b48d5183883fac: 8 files, +540 / -2. Commits: 2bf7c3abd CLI wiring, 772958459 flag tests, and ce39e6c2c approval timeout/abort handling.
  • Incremental compare.

GitHub does not support stacked pull requests across forks, so this follow-up targets upstream main; its displayed diff includes the prerequisite SDK and apply_patch changes until #1506 and #1530 are merged. The incremental compare above shows this follow-up's scope.

Verification

The complete stacked suite passed 98 tests across 9 files: 52 SDK tests, 35 CLI tests, and 11 common tests. The CLI regression files were run from the repository root because package-local startup references the absent cli/test/setup-scm-loader.ts preload. No typecheck diagnostic was reported in changed files.

Inference for this contribution was provided by FreeInference.org. FreeInference did not review, direct, approve, or otherwise participate in this work; all implementation, testing, and publication decisions are the contributor's own. If you find this useful, consider donating to FreeInference.org — they provide a useful and vital service.

@codebuff-team

Copy link
Copy Markdown
Contributor

The core idea here is reasonable: wiring --no-shell/--ask-shell/--project-only/--read-only through to the SDK, and building a correlated shell-approval bridge (common/src/utils/shell-approval-bridge.ts) to fix the real bug that AskUserBridge silently drops concurrent requests. The bridge's FIFO/timeout/abort handling and its test coverage are solid work on their own.

But this PR is not reviewable as posted. The body says the actual contribution here is 8 files / +540/-2 (cli-args.ts, use-ask-user-bridge.ts, index.tsx, codebuff-client.ts, parsed-args.ts, and the bridge test), yet the diff GitHub shows is +2028/-15 across 16 files because it drags in the full sdk/src/permissions/execution-policy.ts module and its adversarial test suite from the still-unmerged #1506/#1530. That's over 1400 lines of security-sensitive sandboxing/symlink-resolution/path-containment code (isContainedPath, canonicalizePath, guardFileSystem) that a reviewer here can't evaluate independently of those PRs, and that this mirror can't safely accept standalone - the CLI flags here reference SDK options (noShell, shellApproval, etc.) that don't exist yet in this repo's SDK.

Concretely, as submitted:

Please resubmit just the CLI-side diff (cli-args.ts, use-ask-user-bridge.ts, index.tsx, parsed-args.ts, codebuff-client.ts, and the shell-approval-bridge) once the SDK PRs it depends on are merged, so the diff matches what you describe as the actual change set. As-is this is too large and too entangled with unmerged work for a maintainer to safely port.

@codebuff-team codebuff-team added bot:triaged Classified by the community triage bot pr:needs-work Right idea, not mergeable as written labels Oct 18, 2026
canonicalizePath now walks up only for genuinely-missing paths (ENOENT/ENOTDIR) and rethrows permission errors and symlink loops. Replace the root-unsafe slice with path.basename. guardFileSystem refuses strict confinement when a custom adapter lacks a compatible canonicalizer. handleToolCall resolves file-path targets again and refuses an unverifiable mutating target under --project-only. Exempt the audited CLI ask_user UI override from the external-tool gate while keeping MCP/custom name collisions external. Document that projectOnly is not an OS boundary.

Tests cover root-boundary canonicalization, fail-closed realpath errors, the adapter refusal, and ask_user under all four permission modes.
Add a top-level regression that goes through CodebuffClient.run with a restricted policy, spawns a child through the real spawn_agents handler, and proves the child's inherited requestToolCall denies shell and writes. This is the end-to-end inheritance check requested in review, beyond the handler-level unit tests.
Exercise the nested apply_patch target check in project-only mode: in-project paths dispatch, out-of-project and symlink-escape paths are rejected, and a malformed target with no path fails closed. The write override is explicitly trusted so the test isolates target confinement from host trust.
Route a submitted decision to the request id captured when the form was shown instead of looking up whatever approval is active at click time, so a delayed answer for a timed-out command can no longer approve the next one. The shell prompt now shows the exact command, working directory, and sync/background mode, with control characters escaped for display only. Adds an A-timeout/B-activation/stale-A regression test.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:triaged Classified by the community triage bot pr:needs-work Right idea, not mergeable as written

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants