From 17835c09e042e96c7b03370b61e09c92f20d17e1 Mon Sep 17 00:00:00 2001 From: Joseph Ibrahim Date: Fri, 19 Jun 2026 15:45:43 -0400 Subject: [PATCH] =?UTF-8?q?feat(ops):=20first-class=20key=20rotation=20?= =?UTF-8?q?=E2=80=94=20make=20rotate-key=20+=20runbook?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit scripts/rotate_anthropic_key.sh shipped on master bundled in #16 (3e0343e). This focused PR makes it discoverable + documented: - make rotate-key — one command (paste new key, hidden, validate + persist) - docs/key-rotation.md — runbook: rotate locally, then delete the old key in the Anthropic console. The MCP coaching path uses no Claude credential, so rotation never disrupts it. Co-Authored-By: Claude Opus 4.8 --- Makefile | 10 +++++++++- docs/key-rotation.md | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 docs/key-rotation.md diff --git a/Makefile b/Makefile index 5053ee2..b96c726 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ endif .PHONY: help build-rust build-macos sign notarize staple dmg release \ clean-macos test compliance-greps verify doctor signing-readiness \ - regen-trajectories regen-predictor build-healthbridge + regen-trajectories regen-predictor build-healthbridge rotate-key help: @echo "Harlo build targets" @@ -58,10 +58,18 @@ help: @echo " regen-trajectories Regenerate data/trajectories_10k.jsonl (~229 MB, ~minutes)" @echo " regen-predictor regen-trajectories + train models/cognitive_predictor_v1.joblib" @echo " clean-macos Remove dist/ and build/" + @echo " rotate-key Rotate ANTHROPIC_API_KEY (paste new key; validates + persists)" build-rust: maturin develop --release +# Rotate the daemon's ANTHROPIC_API_KEY: prompts for the new key (hidden, never +# in shell history), validates it against the API, sets the launchctl session +# env + a persistent login agent, bounces the daemon. Never prints the key. +# See docs/key-rotation.md. +rotate-key: + bash scripts/rotate_anthropic_key.sh + build-macos: ifeq ($(UNAME_S),Darwin) rm -rf build dist diff --git a/docs/key-rotation.md b/docs/key-rotation.md new file mode 100644 index 0000000..90dc91e --- /dev/null +++ b/docs/key-rotation.md @@ -0,0 +1,32 @@ +# Key rotation — `ANTHROPIC_API_KEY` + +Harlo's only cloud credential is `ANTHROPIC_API_KEY` (the daemon reads it from +the environment — `provider/claude.py`). Rotate it whenever it may have been +exposed. + +## One command + +```bash +make rotate-key # or: bash scripts/rotate_anthropic_key.sh +``` + +Paste the new key when prompted (input is hidden). The script: + +1. **Validates** the key against the Anthropic API *before* changing anything. +2. Sets it for the current login session (`launchctl setenv`). +3. **Persists** it across reboots via a `chmod 600` login agent. +4. Bounces the Harlo daemon so it picks up the new key. + +The key is **never** printed, logged, or passed as a shell argument. + +## Then, in the Anthropic console + +`console.anthropic.com → Settings → API Keys` → **delete the old key**. That is +the step that actually neutralizes the old credential; the script only swaps in +the new one locally. + +## Note + +The Harlo MCP server (the default coaching surface) uses **no** Claude +credential at all — only the `twin ask` CLI path calls the API. So rotating the +key never disrupts the MCP coaching path.