feat(runtime): controlled test/build/run command executor (#1387)#1546
Merged
oscharko merged 1 commit intoJun 26, 2026
Conversation
Implements the governed command runner for Issue #1387: a closed catalog of test/build/run tasks discovered from package scripts, executed through the single governed spawn boundary (keiko-tools runCommand) with workspace containment, output byte caps, timeout, cancellation, content-free evidence, and dual-layer secret redaction. Reuses the ADR-0043/ADR-0006 spawn boundary and the ADR-0018 terminal manager pattern rather than adding a second execution path; a run names a discovered task id, never free-form argv. - contracts: command-runner wire contract (catalog, run request/result, events, COMMAND_TASK_RULES allowlist) + hand-rolled validators; adds the additive "command-run" EvidenceTaskType - server: CommandRunnerManager (package-script discovery + governed execution composing runCommand) + routes (/api/commands/catalog|runs|events) + content-free run evidence, wired into deps/routes - ui: CommandsWidget task surface + commands-api client + window registration - tests: contracts/server/ui unit + integration coverage and an e2e browser smoke for catalog discovery, run, and structured result - docs: command-runner security notes Refs #1387 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
8be49af
into
feat/keiko-agent-native-editor-foundation-and-runtime
12 checks passed
2 tasks
oscharko
added a commit
that referenced
this pull request
Jun 26, 2026
Addresses review findings on PR #1546 (security audit + verifier + PR review): - contracts: cap taskId (<=256) and requestId (<=128, token charset) at the parse boundary so an oversized/non-token id cannot reach the manager, audit ledger, or SSE fan-out (the 16 KB body cap was the only prior backstop) + tests - server: document the per-run catalog re-discovery as an intentional untrusted-taskId re-validation; add a test proving a throwing SSE subscriber does not block fan-out to other subscribers - routes: assert Layer-2 redaction is applied to every SSE event frame - ui: render the project path as the Tasks window subtitle (connectionUtils) - e2e: deterministically mock the SSE channel and assert a run lifecycle event reaches the bounded events log - docs: correct the audit-evidence note (the standard manifest workspaceRoot path is retained; argv values, output bytes, and secrets are excluded) Refs #1387 Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
73 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the governed test/build/run command executor for Issue #1387. Keiko can run a closed catalog of workspace tasks (discovered from
package.jsonscripts) through governed local processes with cancellation, output caps, and audit metadata. A run names a discovered task id — never free-form argv — and executes through the single governed spawn boundary (keiko-toolsrunCommand, ADR-0043 D2), inheriting no-shell execution, name-allowlisted env, ephemeral HOME, workspace-contained cwd, byte-capped + redacted output, timeout (SIGTERM→SIGKILL), and AbortController cancellation.Refs #1387
Scope
Reuse And No-Duplication
Reuse / gap rationale: the runner reuses
runCommand(the only spawn boundary, ADR-0043 D2),DEFAULT_SANDBOX_POLICY,readWorkspaceFile+ path containment (keiko-workspace),EvidenceStore(keiko-evidence),deepRedactStrings, and mirrors the ADR-0018TerminalExecutionManager/routes/evidence pattern. The genuine gap — absent today — is a task-oriented layer: package-script discovery, a separate narrow executor allowlist (COMMAND_TASK_RULES, distinct fromDEFAULT_COMMAND_RULES/TERMINAL_COMMAND_RULES), discovered-task-id validation (closes thenpm run <untrusted-name>RCE), and a structured result withfailureReason. The read-only terminal surface is an arbitrary-operand inspection tool and does not satisfy this scope.Acceptance criteria mapping
COMMAND_TASK_RULES+ discovered-task-id validation; unknown id →TASK_NOT_FOUNDbefore spawn (command-runner.ts, tests)AbortControllerper run;DELETE /api/commands/runs/:runId; UI Cancel armed via SSErun-started/requestId(manager + routes + widget tests)runCommandbyte cap +truncated; UI renders already-capped output (truncation test, e2e)CommandTaskRunResult(contract + tests)keiko-contracts; executor is the sharedCommandRunnerManagercomposingrunCommand(no second path)Deliverables
keiko-contracts/src/command-runner.tskeiko-server/src/command-runner.tskeiko-server/src/command-runner-routes.tskeiko-ui/.../CommandsWidget.tsx+lib/commands-api.tsdocs/command-runner/security-notes.mdVerification
Required:
Local verification:
Select only what applies:
docs/command-runner/security-notes.md).Not applicable rationale:
exportsentries (additiveindex.tsre-exports only).release:check: no release-path semantics changed.Review And Closure
Resolves #1387only when this PR should close the issue — kept asRefs #1387; the issue is closed manually after merge once every Definition-of-Done gate is satisfied.Risk Notes
npm run <script>argv; script bodies are the project's own trusted workspace content, run under the minimized env + containment ofrunCommand.runCommand; structural in the BFF for response and SSE frames); audit evidence is content-free (counts/enums only,taskType: "command-run").commandswindow is restorable (fs-reference) and holds only a project-path reference; no secrets persisted.🤖 Generated with Claude Code