fix(kickoff): macOS Keychain auth fallback + protect --doc from agent rewrites#588
Merged
Merged
Conversation
… rewrites (#729, GH#580) ## Bug 1 — macOS Keychain auth gap The container entrypoint only handled `/host-auth/.credentials.json`. On macOS the claude CLI keeps OAuth in Keychain, so the file doesn't exist and the agent boots unauthenticated. - `entrypoint.sh` now resolves auth via a fallback chain: credentials.json → `/host-auth/*.env` (sourced) → `CLAUDE_CODE_OAUTH_TOKEN` / `ANTHROPIC_API_KEY` env passthrough. Emits a clear warning to stderr when no source resolves instead of failing silently. - `launch_container` forwards those two env vars to the runtime via `-e NAME` (no value), so tokens stay out of `ps` listings. ## Bug 2 — agent rewrote the design doc passed via --doc The kickoff agent edited the canonical design file mid-run, dropping OPEN-question markers and reshaping headings. Defense in depth: - Prompt: KICKOFF.md gains a "Design Document — Canonical Input" stanza when `--doc` is supplied. - chmod 0444 on the worktree copy of the doc at launch time. - Container `:ro` overlay mount of the doc on top of the writable workspace mount. - Launch-time breadcrumb (`.kickoff-doc.json`) records rel_path + SHA-256; `crosslink kickoff status` / `report` re-hashes on the way out and emits a Mismatch line + tracing::error! on drift. ## Tests 5 new unit tests cover the integrity verdict matrix (NotProtected / Match / Mismatch / Missing-deleted / Missing-malformed). Existing exclude-pattern tests updated for the new `.kickoff-doc.json` entry. Full suite: 2808 passed, 0 failed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pure formatting — rejoins a let binding that fits on one line. No behavior change. Verified `cargo fmt --check` clean and `cargo clippy --lib --bin crosslink -- -D warnings` clean afterwards. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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
Fixes both bugs in GH#580:
/host-auth/.credentials.json, so macOS hosts (OAuth lives in Keychain, no file on disk) booted the agent unauthenticated. Now resolves auth via fallback chain: credentials.json →/host-auth/*.env(sourced) →CLAUDE_CODE_OAUTH_TOKEN/ANTHROPIC_API_KEYenv passthrough.launch_containerforwards those env vars viadocker -e NAME(no value, so tokens stay out ofps). Emits a clear stderr warning when no source resolves instead of failing silently.--docfile: four-layer defense — KICKOFF.md "Canonical Input" stanza,chmod 0444on the worktree copy, container:rooverlay mount on top of the writable workspace, and a.kickoff-doc.jsonbreadcrumb (rel_path + SHA-256) thatcrosslink kickoff statusandreportre-verify on the way out. Drift surfaces as aMismatchline +tracing::error!so it cannot be silently shipped.Closes GH#580. Tracked locally as #729.
Test plan
cargo test --bin crosslink— 2808 passed, 0 failedcargo clippy --lib --bin crosslink -- -D warnings— cleanNotProtected/Match/Mismatch/Missingon deletion /Missingon malformed breadcrumb).kickoff-doc.jsonentrybash -n entrypoint.sh— syntax okcrosslink kickoff run --container docker --doc .design/<doc>.md ...on macOS — verify Keychain-only hosts now authenticate viaCLAUDE_CODE_OAUTH_TOKEN, and the agent cannot write to the mounted.design/<doc>.mdcrosslink kickoff statusandreportflag the mismatch🤖 Generated with Claude Code