Conversation
* fix(env): detect and refuse target-repo .env with sensitive keys (#1034) Bun auto-loads .env from subprocess CWD regardless of the clean env passed to Bun.spawn, silently overriding OAuth auth and billing the wrong API account. This adds a consent-based gate at registration time and a pre-spawn safety net in both Claude and Codex clients. Changes: - Add env-leak-scanner utility that checks 6 auto-loaded .env filenames for 7 sensitive keys (ANTHROPIC_API_KEY, OPENAI_API_KEY, etc.) - Add allow_env_keys boolean column to codebases table (migration 021) - Gate registerRepoAtPath to reject codebases with sensitive .env keys unless explicitly consented via allowEnvKeys flag - Add pre-spawn check in ClaudeClient and CodexClient sendQuery methods - Return 422 from POST /api/codebases on env leak detection - Surface env leak error in web UI with "Allow env keys" checkbox - Classify EnvLeakError as FATAL in workflow executor Fixes #1034 * fix: address review findings for env leak scanner PR - Fix FATAL_PATTERNS 'env leak' pattern that never matched EnvLeakError.message; now checks error.name === 'EnvLeakError' directly (immune to message rewording) - Fix pre-spawn consent lookup for worktree paths: add findCodebaseByPathPrefix() and use it as fallback when exact match returns null; prevents opt-in from being silently ineffective for workflow-based runs - Add allow_env_keys column to 000_combined.sql CREATE TABLE and idempotent ALTER section to fix fresh PostgreSQL installs - Remove non-existent --allow-env-keys CLI flag from error message; replace with web UI-only instruction - Narrow isEnvLeakError check from error.message.includes('env') to startsWith('Cannot add codebase') - Distinguish ENOENT (skip) from EACCES/other errors in scanner catch block; unreadable files now surface as findings to avoid silently bypassing the gate - Use cross-platform grep command instead of macOS-specific sed -i '' syntax - Add audit log (log.warn) when 422 EnvLeakError is returned from API - Add pre-spawn gate tests to claude.test.ts and codex.test.ts (4 tests each) - Add env leak gate tests to clone.test.ts (2 tests) - Add 422 and allowEnvKeys passthrough tests to api.codebases.test.ts * simplify: reduce complexity in changed files
… tool_results (#1037) * fix(sse): extend buffer TTL beyond reconnect grace to prevent dropped tool_results The SSE event buffer held events for only 3s, but the conversation reconnect grace period is 5s — meaning events emitted during a reconnect window could expire *before* the client even had a chance to reconnect. When a tool_result happened to land in that gap, the UI would show a perpetually spinning tool card with no recovery path. This is one of the remaining causes from the 'tool cards stuck running' investigation. The two biggest causes (Claude hook coverage and Codex tool_result emission) were already fixed in #1031 and #1032. This closes the last high-impact backend gap. Changes: - EVENT_BUFFER_TTL_MS: 3_000 → 60_000. Covers typical EventSource auto-reconnect delays on flaky networks (mobile, VPN, laptop sleep). - EVENT_BUFFER_MAX: 50 → 500. Events are small JSON strings; 500 bounds worst-case memory while giving real headroom for bursts. - Warn when buffer cap evicts oldest (previously silent). - Warn when events expire on TTL at replay time (previously silent). Both warnings give us observability if the new bounds are still ever insufficient. Note: a full Last-Event-ID resume protocol would be more principled but requires monotonic event IDs and client-side offset tracking — a larger change with its own risks. The TTL bump alone closes the vast majority of the window at near-zero cost. * fix(sse): throttle eviction warns, reset cleanup timer, enforce TTL invariant Address review feedback on the SSE buffer TTL bump: - Reset the buffer cleanup timer on each new event so the buffer is held for TTL past the most recent event, not the first one. With the 20x TTL bump this gap became meaningful — a fresh event could be wiped by a cleanup timer scheduled when the first (now-stale) event was buffered. - Throttle 'transport.buffer_evicted_oldest' warns to one per conversation per 5s. A runaway producer overflowing the cap by hundreds would otherwise flood logs. - Fail-fast at module load if EVENT_BUFFER_TTL_MS < RECONNECT_GRACE_MS. Locks in the invariant the comment already documents. - Add test covering the eviction-warn throttle.
* feat(cli): embed git commit hash in version output - Add BUNDLED_GIT_COMMIT constant to bundled-version.ts for binary builds - Read commit at runtime via git rev-parse (dev) or from bundled constant (binary) - Display Git commit: line in archon version output; falls back to "unknown" - Update build-binaries.sh to capture and embed short SHA at compile time - Update version tests to assert new Git commit: output line * fix: use @archon/git execFileAsync and add error logging in version command - Replace local child_process/promisify wrapper with execFileAsync from @archon/git (fixes CLAUDE.md violation; enables test mockability via spyOn) - Add 5s timeout to git rev-parse subprocess call to prevent indefinite hang - Log debug trace in catch block with comment explaining intentional fallback - Import createLogger from @archon/paths for structured logging - Update version.test.ts to spy on @archon/git execFileAsync for deterministic SHA - Add test case covering the git-unavailable fallback path (returns 'unknown') - Tighten git commit assertion to match exact value instead of label presence only Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Archon <archon@dynamous.ai> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…up (#1027) * Fix: detect squash-merged and PR-merged branches in isolation cleanup (#1026) `isolation cleanup --merged` only used `git branch --merged`, which misses squash-merged branches because the resulting commit has a different SHA. Bulk cleanup of task worktrees required a manual `gh pr list` per branch. Changes: - Add `isPatchEquivalent()` to `@archon/git` using `git cherry` to detect squash-merged branches - Add `getPrState()` to `@archon/isolation` for `gh`-based PR state lookup with per-invocation caching; soft-fails on missing gh / non-GitHub remotes - `cleanupMergedWorktrees()` now unions three signals (ancestry, patch equivalence, PR state); skips with a clear reason when PR is OPEN - Add `--include-closed` flag to `archon isolation cleanup --merged` to also remove worktrees whose PRs were closed without merging - Tests for all new code paths Fixes #1026 * fix: address review findings for squash-merge cleanup PR - branch.ts: add 'bad revision' to isPatchEquivalent expected errors so manually-deleted branches return false instead of throwing - pr-state.ts: add repoPath context to warn/debug log calls; capture ghStdout before try block to include in warn log for parse failures - pr-state.test.ts: remove redundant beforeEach reset (setupGhResponse already resets); add tests for non-ENOENT gh error and malformed JSON - cleanup-service.test.ts: add test for isPatchEquivalent unexpected throw → skipped with 'merge check failed' reason - isolation-operations.test.ts: add test for includeClosed: true forwarding through cleanupMergedEnvironments - docs: add --include-closed to all five affected docs (CLAUDE.md, reference/cli.md, book/isolation.md, book/quick-reference.md, getting-started/overview.md) - cli-internals.md: add isolation cleanup --merged flow diagram * simplify: remove redundant assignments and verbose filter in new code
…stream logger (#982) * fix(build): use build-time constants for binary detection and pretty stream logger Replaces runtime detection of compiled binaries (env sniffing via import.meta.dir / process.execPath) with a build-time BUNDLED_IS_BINARY constant in @archon/paths/bundled-build.ts, rewritten by scripts/build-binaries.sh and restored on EXIT via a trap. Also rewrites @archon/paths/logger.ts to use pino-pretty as a destination stream instead of a worker-thread transport. The formatter now runs on the main thread, eliminating the require.resolve('pino-pretty') lookup that crashes inside Bun's /\$bunfs/ virtual filesystem in compiled binaries. The same code path runs in dev and binaries — no environment detection in the logger at all. isBinaryBuild() in @archon/workflows is kept as a one-line wrapper around BUNDLED_IS_BINARY so existing spyOn-based test mocking in loader.test.ts continues to work without modification. Closes #960 Closes #961 Closes #979 Supersedes #962 Supersedes #963 Co-Authored-By: leex279 <leex279@users.noreply.github.com> * style(workflows): hoist BUNDLED_IS_BINARY import to top of file * fix(build,logger): harden pretty init and trap restore - logger: wrap pino-pretty init in try/catch and fall back to JSON so a broken TTY or missing peer can't crash module load. - build-binaries.sh: drop '2>/dev/null || true' from the EXIT trap so a failed bundled-build.ts restore is visible instead of silently leaving the dev tree with BUNDLED_IS_BINARY=true. - bundled-defaults: unmark isBinaryBuild() @deprecated and document why the wrapper is the intentional test seam (mock.module pollution in Bun). --------- Co-authored-by: leex279 <leex279@users.noreply.github.com>
* deploy: harden cloud-init with archon user, swap, and fixes - Create dedicated 'archon' user (sudo + docker groups, passwordless sudo, locked password) and copy SSH authorized_keys from default cloud user (with root fallback) so login works immediately. - Run docker pulls and the image build as the archon user via sudo -u. - Add 2GB swapfile to prevent OOM during docker build on small VPS (<2GB RAM). - Remove package_upgrade to speed up boot and avoid surprise kernel updates. - Drop redundant systemctl enable/start docker (get.docker.com handles it). - ufw allow 443/tcp for consistency with 22/80. - set -e before clone for fail-fast on network errors. - Update docs link to https://archon.diy/deployment/docker/. - SETUP_COMPLETE now instructs ssh archon@<server-ip>. - Header lists supported providers (incl. Hostinger) and notes the archon user + swap behavior. * deploy: address PR review feedback on cloud-init - Fix set -e regression: merge clone/cp/chown into single shell block so fail-fast actually applies (CodeRabbit). - Drop passwordless sudo from archon user — docker group only. Removes trivial privilege escalation path (Wirasm). - Remove non-existent 'docker' group from initial users.groups list; it is added via usermod later (CodeRabbit). - Restore package_upgrade: true to patch CVEs in the base image before anything else runs (Wirasm). - Add ufw allow 443/udp for HTTP/3 QUIC — Caddy exposes 443:443/udp in docker-compose (CodeRabbit). - Update SETUP_COMPLETE and header comment to note archon user has no sudo (use default cloud user / root for maintenance).
…ive consent (#973) (#983) * feat(env-leak-gate): polish sweep — CLI flag, config bypass, retroactive consent (#973) Closes the UX gaps left over from #1036: - CLI: --allow-env-keys flag for `archon workflow run` - Config: global `allow_target_repo_keys` in ~/.archon/config.yaml with per-repo `.archon/config.yaml` override; warn log on every load when active - API: PATCH /api/codebases/:id flips allow_env_keys with audit logs on grant and revoke - Web: Settings → Projects per-row "Allow/Revoke env keys" toggle + badge - Errors: context-aware messages (register-ui / register-cli / spawn-existing) - Startup: server scans registered codebases and warns for any that would be blocked at next spawn - Docs + CHANGELOG entries describing the four remediation paths * fix(env-leak-gate): address review feedback from PR #983 Critical: - Move loadConfig() before startup env-leak scan and skip the scan entirely when allow_target_repo_keys is true. Previously the scan spammed warnings on every boot for users who had set the global bypass. Important: - SettingsPage: add onError to toggleEnvKeysMutation so PATCH failures surface to the user instead of being silently swallowed. - env_leak_gate_disabled now logs at most once per process per source (global vs repo) instead of firing on every loadConfig() call. - PATCH /api/codebases/:id audit log includes scanStatus ('ok' | 'skipped') so reviewers can distinguish "scanned and empty" from "scan failed". - claude.ts / codex.ts pre-spawn loadConfig wrapped in try/catch — config load failures now log and fail-closed instead of escaping as opaque errors. - CLI --allow-env-keys grants now emit env_leak_consent_granted audit log in registerRepoAtPath with actor: 'user-cli'. Previously only the PATCH route logged grants, leaving CLI grants without an audit trail. - printUsage() now lists --allow-env-keys. - Outer startup scan catch promoted from warn to error level. Polish: - formatLeakError consent copy moved to an exhaustive switch with a never default — adding a new LeakErrorContext variant is now a compile error. - Comment / event-name normalization: 'migration_env_leak_gate_*' → 'startup_env_leak_*' to match the actual lifecycle (every boot, not one-time migration). Docs: - security.md: corrected "at startup" wording, documented scanStatus field, clarified scan-skipped-on-bypass behavior. - api.md: added PATCH /api/codebases/{id} entry and example. - cli.md: added --allow-env-keys row. - configuration.md: added allow_target_repo_keys to global + repo examples. - CLAUDE.md: added Codebases endpoint section and CLI example. - CHANGELOG: corrected "at startup" wording, added scanStatus and CLI audit-log notes. Tests: - claude.test.ts: added bypass test (allowTargetRepoKeys: true short- circuits scanner) and fail-closed test (loadConfig throws → scanner still runs). - clone.test.ts: updated allowEnvKeys=true expectation — scanner is now called for the audit-log payload but does not throw.
|
Caution Review failedPull request was closed or merged during review 📝 WalkthroughWalkthroughIntroduces environment-leak gate hardening across the system, scanning Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant CLI
participant Server
participant CodebaseDB
participant Scanner
participant Claude
participant Audit
User->>CLI: archon workflow run --cwd /repo --allow-env-keys
CLI->>Server: POST /register (allowEnvKeys=true, context='register-cli')
Server->>CodebaseDB: lookupCodebase(/repo)
CodebaseDB-->>Server: null (new)
Server->>Scanner: scanPathForSensitiveKeys(/repo)
Scanner-->>Server: { findings: [...] }
Note over Server: allowEnvKeys=true (bypass enabled)
Server->>Audit: log(env_leak_consent_granted, files, keys, actor=user-cli)
Audit-->>Server: ✓
Server->>CodebaseDB: createCodebase(..., allow_env_keys=true)
CodebaseDB-->>Server: Codebase(id=1, allow_env_keys=true)
Server-->>CLI: 200 OK
User->>Claude: sendQuery(cwd=/repo)
Claude->>CodebaseDB: findCodebaseByDefaultCwd(/repo)
CodebaseDB-->>Claude: Codebase(allow_env_keys=true)
Note over Claude: allow_env_keys=true, skip gate
Claude->>Claude: spawn subprocess
Claude-->>User: ✓ Success
sequenceDiagram
participant CLI
participant Cleanup
participant Git
participant GhCLI
participant Cache
participant WorktreeOps
User->>CLI: archon isolation cleanup --merged --include-closed
CLI->>Cleanup: cleanupMergedEnvironments(codebaseId, mainPath, {includeClosed:true})
Cleanup->>Cleanup: list merged branches
loop For each branch
Cleanup->>Git: isBranchMerged(branch, main)
Git-->>Cleanup: false (not ancestor)
Cleanup->>Git: isPatchEquivalent(branch, main)
Git-->>Cleanup: true (all commits marked with -)
Note over Cleanup: Squash merge detected ✓
Cleanup->>WorktreeOps: remove worktree & branch
WorktreeOps-->>Cleanup: ✓
end
loop For each closed PR branch
Cleanup->>Cache: getPrState(branch, cache)
Cache->>GhCLI: gh pr list --head branch --json state
GhCLI-->>Cache: {state: CLOSED}
Cache-->>Cleanup: 'CLOSED'
alt includeClosed=true
Cleanup->>WorktreeOps: remove(CLOSED branch)
WorktreeOps-->>Cleanup: ✓ removed
else includeClosed=false
Cleanup-->>Cleanup: skip with reason
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related issues
Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
ANTHROPIC_API_KEY was accepted at runtime as a tertiary auth fallback but not included in the startup credential check, causing misleading warnings for users who set only ANTHROPIC_API_KEY. Remove it entirely — users should use CLAUDE_API_KEY instead (same key format). Also resolve pre-existing merge conflict markers in api.ts. Fixes coleam00#985
ANTHROPIC_API_KEY was accepted at runtime as a tertiary auth fallback but not included in the startup credential check, causing misleading warnings for users who set only ANTHROPIC_API_KEY. Remove it entirely — users should use CLAUDE_API_KEY instead (same key format). Also resolve pre-existing merge conflict markers in api.ts. Fixes coleam00#985
Release 0.3.0
ANTHROPIC_API_KEY was accepted at runtime as a tertiary auth fallback but not included in the startup credential check, causing misleading warnings for users who set only ANTHROPIC_API_KEY. Remove it entirely — users should use CLAUDE_API_KEY instead (same key format). Also resolve pre-existing merge conflict markers in api.ts. Fixes coleam00#985
Release 0.3.0
Release 0.3.0
Env-leak gate hardening, SSE reliability fixes, isolation cleanup smarter merge detection, build/version improvements, and deploy hardening.
Added
.envkeys): scan auto-loaded.envfiles for sensitive keys and refuse to register or spawn into a codebase whose.envwould silently re-inject keys into Claude/Codex subprocesses. Fail-closed by default (bug: concurrent-run guard has TOCTOU race with pre-created pending rows #1036).--allow-env-keys, globalallow_target_repo_keysconfig,PATCH /api/codebases/:id, Settings → Projects per-row toggle, and startup env-leak scan for granting/revoking consent without delete-and-re-add (polish(env-leak-gate): CLI escape hatch, retroactive consent, context-aware errors, docs #973, feat(env-leak-gate): polish sweep — CLI flag, config bypass, retroactive consent (#973) #983).isolation cleanup --mergedviagit cherryandghPR state, plus--include-closedflag (bug(claude-client):hasExplicitTokensuses??instead of||, causing auth fallback to missCLAUDE_API_KEYwhenCLAUDE_CODE_OAUTH_TOKENis set to empty string #1027).archon versionoutput (archon setup --spawn fails on Windows when repo path contains spaces #1035).Changed
tool_resultevents during reconnect grace; cleanup timer resets per event (fix(setup): quote repo path in --spawn terminal commands (fixes #1035) #1037).BUNDLED_IS_BINARYconstant; logger usespino-prettyas a destination stream on the main thread, fixing$bunfscrash in compiled binaries (fix(build): use build-time constants for binary detection and pretty stream logger #982).archonuser, 2GB swapfile, 443/udp for HTTP/3, fail-fast on network errors (deploy: harden cloud-init with archon user, swap, and fixes #981).Fixed
findCodebaseByPathPrefixso consent is inherited (bug: concurrent-run guard has TOCTOU race with pre-created pending rows #1036).EnvLeakErrorFATAL classification checkserror.nameinstead of message text (bug: concurrent-run guard has TOCTOU race with pre-created pending rows #1036)..envfiles surface as findings (bug: concurrent-run guard has TOCTOU race with pre-created pending rows #1036).Security
allow_env_keysisfalse(fail-closed). Five remediation paths documented indocs/reference/security.md(bug: concurrent-run guard has TOCTOU race with pre-created pending rows #1036, polish(env-leak-gate): CLI escape hatch, retroactive consent, context-aware errors, docs #973, feat(env-leak-gate): polish sweep — CLI flag, config bypass, retroactive consent (#973) #983).Merging this PR releases 0.3.0 to main. Tagging
v0.3.0after merge triggers binary builds (5 platforms) and Homebrew formula update via.github/workflows/release.yml.Summary by CodeRabbit
New Features
--allow-env-keysCLI flag.PATCH /api/codebases/:idendpoint to manage environment-key consent on existing codebases.--include-closedto remove environments associated with closed/abandoned PRs.Improvements