Skip to content

Harden safety, executor & CI; dedup shell quoting#1

Open
meganfoster-dotcom wants to merge 2 commits into
masterfrom
fix/hardening-pass
Open

Harden safety, executor & CI; dedup shell quoting#1
meganfoster-dotcom wants to merge 2 commits into
masterfrom
fix/hardening-pass

Conversation

@meganfoster-dotcom

Copy link
Copy Markdown
Collaborator

Five targeted hardening fixes from the recent code review. No feature work or behavioral rewrites — each change is small and tested.

What's in here

  1. CI workflow (.github/workflows/ci.yml) — runs typecheck, lint, build, and the full test suite on Node 18/20/22 for every push and PR. The suite is fully offline, so no AI provider keys or credits are used in CI.
  2. Per-step timeout in the setup executorexecuteStep now passes a wall-clock timeout to runCommand, so a hung command (stuck install, a command waiting on stdin, an unreachable registry) can no longer block the run forever. Generous per-type defaults (10 min for installs/builds, 2 min otherwise), overridable via SETUPR_STEP_TIMEOUT_MS. Timeouts surface a clear "timed out … and was terminated" message.
  3. Safety dead-code + force normalization (src/agent/safety.ts) — removed the force ? "confirm" : "confirm" ternary; high risk now plainly always confirms and --force cannot bypass it. forceCanSkipConfirmation is normalized to risk === "medium" in both safety.ts and engine.ts so the two agree.
  4. Tighter secret detection — the old pattern matched bare words like auth/token/secret, raising false-positive confirmations on benign commands (e.g. npm i next-auth). It now matches inline KEY=value credential assignments and recognizable secret value literals (sk-…, ghp_…, AIza…, PEM private keys, etc.).
  5. Deduplicated shellQuote — extracted the helper that was copy-pasted in three files into src/util/shell.ts.

Plus a SECURITY.md threat-model section documenting that the safety layer is a best-effort, defense-in-depth denylist (not a sandbox) and redaction is best-effort.

Verification

  • npm run typecheck
  • npm run lint
  • npm run build
  • npm test ✅ — 186 passing (added 9 regression tests covering the secret-pattern fix, force rules, shellQuote, and the timeout helper)

🤖 Generated with Claude Code

meganfoster-dotcom and others added 2 commits June 9, 2026 21:01
Five targeted hardening fixes from the code review, no behavioral
rewrites:

- ci: add GitHub Actions workflow (typecheck, lint, build, test on
  Node 18/20/22). The suite is fully offline, so no API keys/credits
  are used.
- executor: wire a per-step wall-clock timeout into the setup path so a
  hung command (stuck install, stdin prompt, unreachable registry) can
  no longer block forever. Generous per-type defaults, overridable via
  SETUPR_STEP_TIMEOUT_MS; timeouts surface a clear terminated message.
- safety: remove dead-code ternary (force ? confirm : confirm) — high
  risk now plainly always confirms and --force cannot bypass it.
  Normalize forceCanSkipConfirmation to `risk === "medium"` in both
  safety.ts and engine.ts so the two agree.
- safety: tighten secret detection to match inline KEY=value credential
  assignments and recognizable secret value literals instead of bare
  words, removing false-positive confirmations (e.g. `npm i next-auth`).
- refactor: extract the duplicated shellQuote helper into
  src/util/shell.ts and import it in security, verification, and product.
- docs: document the safety threat model in SECURITY.md (best-effort
  denylist + best-effort redaction, not a sandbox).

Adds 9 regression tests (186 total). typecheck, lint, build, and the
full suite pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The vitest 4 / rolldown test toolchain imports `styleText` from
node:util, which only exists on Node 20+, so the test step fails on
Node 18. The published CLI bundle still targets Node 18; CI builds and
tests on the versions the dev toolchain supports.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.

1 participant