Skip to content

Add command authorization planner without shell wrapper reuse#84118

Closed
jesse-merhi wants to merge 1 commit into
mainfrom
jesse/command-auth-planner-no-wrapper-reuse
Closed

Add command authorization planner without shell wrapper reuse#84118
jesse-merhi wants to merge 1 commit into
mainfrom
jesse/command-auth-planner-no-wrapper-reuse

Conversation

@jesse-merhi

Copy link
Copy Markdown
Member

Summary

  • Add the command authorization planner contract and planner-backed POSIX command analysis for direct commands, pipelines, and chains.
  • Route exec allowlist evaluation and allow-always persistence through the planner while keeping shell-wrapper inline payloads prompt-only.
  • Preserve exact-command durable allow-always fallback, so the same approved shell-wrapper command can rerun without deriving reusable inner-command trust.
  • Remove the legacy POSIX chain/pipeline/heredoc parser from exec approval analysis; Windows remains on the existing analyzer path.

Out of scope

  • No derived shell-wrapper reuse in this PR: sh -c 'echo ok' does not persist /bin/echo and does not auto-run from an /bin/echo allowlist entry.
  • No positional-carrier pinning or shell-wrapper inner payload rendering. Those are intended for a follow-up PR.

Verification

  • Not run for this exploratory split PR. The split commit was created in a Codex worktree; the repo commit helper hit the local Node 20 vs pnpm Node 22 requirement before tests were run.

Real Behavior Proof

Behavior addressed: planner-backed exec approval analysis without shell-wrapper reusable trust.
Real environment tested: not tested after this split.
Exact steps or command run after this patch: not run.
Evidence after fix: not collected.
Observed result after fix: not verified.
What was not tested: unit tests, typecheck, changed checks, and live exec approval behavior.

Copilot AI review requested due to automatic review settings May 19, 2026 12:18
@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime agents Agent runtime and tooling size: XL maintainer Maintainer-authored PR labels May 19, 2026
@clawsweeper

clawsweeper Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor

Codex review: found issues before merge. Reviewed June 15, 2026, 2:41 AM ET / 06:41 UTC.

Summary
The PR adds a planner-backed POSIX command authorization path, rewires exec allowlist and allow-always persistence through it, and removes most legacy POSIX shell parsing while leaving Windows on the existing analyzer.

PR surface: Source +165, Tests +154. Total +319 across 23 files.

Reproducibility: yes. for the blocking PR defect by source inspection: the PR builds and broadcasts the approval event with commandAnalysis set to null, then mutates only the in-memory record after delivery paths have already consumed the event. The broader planner behavior was not executed in this read-only review.

Review metrics: none identified.

Stored data model
Persistent data-model change detected: serialized state: src/infra/exec-approvals-allow-always.test.ts, vector/embedding metadata: src/infra/exec-approvals-analysis.test.ts. Confirm migration or upgrade compatibility proof before merge.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🌊 off-meta tidepool
Patch quality: 🧂 unranked krab
Result: blocked by patch quality or review findings.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P2] Preserve commandAnalysis in the delivered approval payload or emit a consumed update event before real clients need it.
  • Have maintainers choose between repairing this split branch and using the newer planner PR after its remaining blocker is fixed.
  • Run focused exec approval, allowlist, allow-always, and system-run validation on the chosen branch.

Risk before merge

  • [P1] Merging this branch as-is would deliver exec approval requests with commandAnalysis set to null, hiding inline-eval and command-risk warnings from clients and forwarded approval messages.
  • [P1] The PR replaces large parts of POSIX exec allowlist and allow-always analysis, so existing durable approval and shell-wrapper trust behavior needs compatibility proof before it can safely land.
  • [P1] The branch is protected and conflicting, and it overlaps with the newer open planner branch at fix(exec): rebuild command authorization on the Tree-sitter command planner #84172, so maintainers need to choose the canonical path before merge.

Maintainer options:

  1. Use the canonical planner branch after repair (recommended)
    Pause this split branch while maintainers repair and review the newer planner PR, then close or supersede this branch only after that path is safe.
  2. Repair this split branch before merge
    Await command analysis before building and broadcasting the request event, then rerun focused gateway, allowlist, allow-always, and system-run validation.
  3. Accept the narrower trust shape explicitly
    Maintainers may intentionally keep the no-wrapper-reuse split, but the durable approval and shell-wrapper compatibility tradeoff should be recorded before merge.

Next step before merge

  • [P2] This protected, conflicting security-boundary PR overlaps with a newer open planner branch, so the next action is maintainer choice rather than an automated repair job.

Security
Needs attention: Needs attention because the diff changes the exec approval trust boundary and currently drops command-analysis warning context from delivered approval requests.

Review findings

  • [P1] Send command analysis before broadcasting approvals — src/gateway/server-methods/exec-approval.ts:326
Review details

Best possible solution:

Use the newer planner PR after its own blocker is fixed, or refresh this branch only if maintainers explicitly want the narrower no-wrapper-reuse shape with delivered command analysis preserved and focused exec approval validation.

Do we have a high-confidence way to reproduce the issue?

Yes for the blocking PR defect by source inspection: the PR builds and broadcasts the approval event with commandAnalysis set to null, then mutates only the in-memory record after delivery paths have already consumed the event. The broader planner behavior was not executed in this read-only review.

Is this the best way to solve the issue?

No as written. The planner direction may be the right architecture, but this branch must preserve commandAnalysis at delivery time and prove compatibility, or defer to the newer planner PR once that branch is fixed.

Full review comments:

  • [P1] Send command analysis before broadcasting approvals — src/gateway/server-methods/exec-approval.ts:326
    commandAnalysis is now set to null in the request payload and filled later by mutating the record. handlePendingApprovalRequest broadcasts and forwards the already-built event, so real clients lose command-analysis warnings even though the new test can observe the later in-memory mutation.
    Confidence: 0.92

Overall correctness: patch is incorrect
Overall confidence: 0.88

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against bcb016a528b1.

Label changes

Label justifications:

  • P2: This is a substantial exec approval authorization improvement PR with limited pre-merge blast radius, not a live production outage.
  • merge-risk: 🚨 compatibility: The diff removes the legacy POSIX parser path and changes allowlist/allow-always persistence behavior for existing exec approval setups.
  • merge-risk: 🚨 security-boundary: The diff changes command approval trust analysis and currently suppresses warning context from delivered approval requests.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🌊 off-meta tidepool and patch quality is 🧂 unranked krab.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Not applicable: The external-contributor proof gate does not apply to this MEMBER-authored, maintainer-labeled PR, though the PR body explicitly says no tests or real behavior proof were run.
Evidence reviewed

PR surface:

Source +165, Tests +154. Total +319 across 23 files.

View PR surface stats
Area Files Added Removed Net
Source 14 1163 998 +165
Tests 9 709 555 +154
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 23 1872 1553 +319

Security concerns:

  • [medium] Delivered approvals lose warning analysis — src/gateway/server-methods/exec-approval.ts:326
    Approval clients and forwarded approval messages depend on request.request.commandAnalysis for warning lines, but the PR sends null and mutates the record only after delivery.
    Confidence: 0.92

What I checked:

  • Repository policy read: Root AGENTS.md and scoped gateway/agents guides were read; the protected-label, security-boundary, compatibility, and deeper-than-diff review guidance affected this verdict. (AGENTS.md:1, bcb016a528b1)
  • Live PR state: Live metadata shows this PR is open, MEMBER-authored per provided GitHub context, labeled maintainer, mergeStateStatus DIRTY/mergeable CONFLICTING, and head f9b550a. (f9b550ad4eba)
  • Blocking patch regression: On the PR head, the request payload sets commandAnalysis to null and only mutates record.request.commandAnalysis after requestEvent has already been constructed. (src/gateway/server-methods/exec-approval.ts:326, f9b550ad4eba)
  • Current-main delivery contract: Current main broadcasts the already-built requestEvent before calling deliverRequest, so later record mutation does not update delivered client, forwarder, or push payloads. (src/gateway/server-methods/approval-shared.ts:417, bcb016a528b1)
  • Current-main warning consumers: Forwarded approval messages read request.request.commandAnalysis.warningLines from the delivered request payload, making a null delivered value user-visible for command-risk warnings. (src/infra/exec-approval-forwarder.ts:248, bcb016a528b1)
  • Current-main baseline: Current main computes commandAnalysis before putting it on the approval request object, and the adjacent test asserts the broadcast payload already contains inline-eval warning analysis. (src/gateway/server-methods/exec-approval.ts:273, bcb016a528b1)

Likely related people:

  • steipete: Recent history shows repeated exec approval, wrapper trust, safe-bin, command-analysis, and gateway approval refactors in the central files touched by this PR. (role: feature-history owner; confidence: high; commits: 524185a68ea2, bd0e10a2f68f, 3f7e6eebc2f5; files: src/infra/exec-approvals-analysis.ts, src/infra/exec-approvals-allowlist.ts, src/gateway/server-methods/exec-approval.ts)
  • vincentkoc: History shows shared approval registration work in the gateway handler and adjacent exec safe-bin/import-cycle work in the approval analyzer surface. (role: adjacent approval/gateway contributor; confidence: medium; commits: 56eadf36d019, c9e481ac48e5, 230a39797aea; files: src/gateway/server-methods/exec-approval.ts, src/infra/exec-approvals-analysis.ts, src/infra/exec-approvals-allowlist.ts)
  • jesse-merhi: Beyond this PR, prior merged history shows work on exec approval highlighting and removal of skill-prelude exec allowlist behavior in the same authorization area. (role: recent exec approval contributor; confidence: medium; commits: e964987cd20e, 79c2ed9065d0, 297a16453661; files: src/infra/exec-approvals-allowlist.ts, src/gateway/server-methods/exec-approval.ts, src/infra/exec-approvals-analysis.ts)
  • pgondhi987: History shows multiple wrapper, safe-bin, requester-metadata, and truncated-command hardening changes adjacent to this PR's authorization boundary. (role: prior exec approval security hardening contributor; confidence: medium; commits: 386d321634b3, 50f4440c9663, 9ac4272b35e9; files: src/gateway/server-methods/exec-approval.ts, src/infra/exec-approvals-analysis.ts, src/infra/exec-approvals-allowlist.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

Copilot AI 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.

Pull request overview

Replaces the legacy POSIX shell parser used by exec approval analysis with a new command authorization planner. The planner produces a typed plan (analyzable / prompt-only / unanalyzable) that drives allowlist evaluation, allow-always persistence, and safe-bin / enforced shell-command rendering for non-Windows hosts, while Windows remains on the existing analyzer. The path that derived reusable trust from shell-wrapper inner payloads is intentionally removed; exact-command durable approval remains.

Changes:

  • Introduces src/infra/command-authorization (types.ts, plan.ts, index.ts) and corpus tests; wires evaluateShellAllowlist, persistAllowAlwaysPatterns, analyzeCommandForPolicy, and resolveCommandAnalysisSummaryForDisplay to be async planner-backed.
  • Deletes legacy POSIX heredoc/pipeline/chain parsing and buildSafeBinsShellCommand/splitCommandChain* from exec-approvals-analysis.ts; analyzeShellCommand and buildEnforcedShellCommand now only handle Windows.
  • Threads authorizationPlan through SystemRunAllowlistAnalysis, system-run policy phase, and gateway allowlist enforcement; gateway approval request now resolves command analysis asynchronously.

Reviewed changes

Copilot reviewed 23 out of 23 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/infra/command-authorization/types.ts New plan/unit/relationship types for the authorization planner.
src/infra/command-authorization/plan.ts Planner implementation using explainShellCommand; builds tree/units and renders enforced/safe-bins shell commands.
src/infra/command-authorization/index.ts Barrel exports for planner API and types.
src/infra/command-authorization/corpus.test.ts Corpus tests covering argv/POSIX shape, render modes, prompt-only and unanalyzable plans.
src/infra/exec-approvals-analysis.ts Removes POSIX shell parser/rebuilders; restricts analyzeShellCommand/buildEnforcedShellCommand to Windows.
src/infra/exec-approvals-analysis.test.ts Drops POSIX shell parsing/heredoc tests; renames Windows-only describe.
src/infra/exec-approvals-allowlist.ts evaluateShellAllowlist becomes async planner-backed; adds planner-based allow-always entry resolvers; drops inline-chain recursion.
src/infra/exec-approvals-allow-always.test.ts Migrates tests to planner-backed helper; updates chain expectations to first-missed binary.
src/infra/exec-approvals.ts persistAllowAlwaysPatterns becomes async; routes through planner when command text is available on non-Windows.
src/infra/exec-approvals-store.test.ts New planner-based persistence tests covering unit scoping.
src/infra/exec-approvals-safe-bins.test.ts Adjusts safe-bin tests to await async evaluateShellAllowlist.
src/infra/exec-approvals-parity.test.ts Reroutes shell-parser parity fixture through the planner.
src/infra/command-analysis/policy.ts analyzeCommandForPolicy becomes async; POSIX path uses planner via lazy import.
src/infra/command-analysis/explain.ts resolveCommandAnalysisSummaryForDisplay becomes async.
src/infra/command-analysis/explain.test.ts / explain.lazy.test.ts Awaits async API; lazy test now uses argv-host path.
src/node-host/invoke-system-run-allowlist.ts Threads planner through allowlist evaluation; safe-bins shell rebuild uses planner renderer.
src/node-host/invoke-system-run.ts Carries authorizationPlan through policy/execute phases; awaits async persistence with new analysisOk/commandText.
src/gateway/server-methods/exec-approval.ts Resolves command analysis asynchronously; broadcasts request with commandAnalysis: null then mutates record on resolve.
src/gateway/server-methods/server-methods.test.ts Adds vi.waitFor for the async analysis update.
src/agents/bash-tools.exec.ts rejectUnsafeControlShellCommand becomes async/planner-backed.
src/agents/bash-tools.exec-host-node-phases.ts Awaits async evaluateShellAllowlist.
src/agents/bash-tools.exec-host-gateway.ts Uses planner-backed enforced shell rendering and async persistAllowAlwaysPatterns.

Comment on lines 278 to +365
@@ -320,7 +323,7 @@ export function createExecApprovalHandlers(
security: p.security ?? null,
ask: p.ask ?? null,
warningText: warningText ? sanitizeExecApprovalWarningText(warningText) : null,
commandAnalysis,
commandAnalysis: null,
commandSpans,
allowedDecisions: resolveExecApprovalAllowedDecisions({ ask: p.ask ?? null }),
agentId: effectiveAgentId ?? null,
@@ -357,6 +360,9 @@ export function createExecApprovalHandlers(
createdAtMs: record.createdAtMs,
expiresAtMs: record.expiresAtMs,
};
void commandAnalysisPromise.then((commandAnalysis) => {
record.request.commandAnalysis = commandAnalysis;
});
Comment on lines +1173 to +1215
async function collectAllowAlwaysPatternsAsync(params: {
segment: ExecCommandSegment;
cwd?: string;
env?: NodeJS.ProcessEnv;
platform?: string | null;
strictInlineEval?: boolean;
depth: number;
out: AllowAlwaysPattern[];
}): Promise<void> {
if (params.depth >= 3) {
return;
}

const trustPlan = resolveExecWrapperTrustPlan(params.segment.argv);
if (trustPlan.policyBlocked) {
return;
}
const segment =
trustPlan.argv === params.segment.argv
? params.segment
: {
raw: trustPlan.argv.join(" "),
argv: trustPlan.argv,
resolution: resolveCommandResolutionFromArgv(trustPlan.argv, params.cwd, params.env),
};

const candidatePath = resolveExecutionTargetCandidatePath(segment.resolution, params.cwd);
if (!candidatePath) {
return;
}
if (isInterpreterLikeAllowlistPattern(candidatePath)) {
const effectiveArgv = segment.resolution?.effectiveArgv ?? segment.argv;
if (params.strictInlineEval !== true || detectInlineEvalArgv(effectiveArgv) !== null) {
return;
}
}
if (!trustPlan.shellWrapperExecutable) {
const argPattern = buildArgPatternFromArgv(segment.argv, params.platform);
addAllowAlwaysPattern(params.out, candidatePath, argPattern);
return;
}
return;
}
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels May 19, 2026
@clawsweeper clawsweeper Bot added P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. labels Jun 15, 2026
@jesse-merhi

Copy link
Copy Markdown
Member Author

Closing this as superseded by #84172.

What changed between the two branches:

Given that #84172 is the active fuller version and this branch is stale/conflicting, keeping #84118 open would just split review attention.

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

Labels

agents Agent runtime and tooling gateway Gateway runtime maintainer Maintainer-authored PR merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. P2 Normal backlog priority with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: XL status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants