feat(secret-push): variadic targets + System.keychain backing (S-63)#90
Merged
Conversation
Promotes `dotfiles secret push` from a single-host login-keychain seed
into a multi-host upsert that handles both backing stores, both seed
and rotation cases, and verifies each target before claiming success.
Closes S-51 § Trade-offs row 2 + S-53 § Future work item 1. Triggered
by 2026-05-10 SA rotation event (rotation across Air + Mini that
exercised the gotchas this spec codifies).
New surface:
- Variadic targets after VAR_NAME (one or more SSH aliases).
- --backing-store=login|system flag (default login for backwards-compat).
- --local opts the local machine into the iteration.
- Per-target verdict + final summary; non-zero exit on any failure.
- Sequential iteration (parallel sudo/biometric prompts interleave illegibly).
Auto-detect upsert (delete-then-add unconditionally) subsumes both
seed and rotation cases on both backing stores at the cost of one
extra keychain op. Required because add -U against System.keychain
over non-TTY SSH silently fails: macOS gates ACL updates behind a
GUI prompt that piped SSH cannot satisfy. Symptoms: User-interaction-
not-allowed + already-exists, exit 0, no value change. Login.keychain
doesn't gate ACL updates so -U worked there; S-53's System.keychain
path needed delete-then-add.
Negative-cache .miss cleanup as a side-effect of every successful
seed closes the rotated-but-still-empty-for-24h footgun (the cache
script's 24h TTL otherwise survives the rotate).
New bash helper home/dot_local/bin/executable_secret-upsert-target
does the per-target dance (probe sudo, delete, add via stdin, verify
by read-back, neg-clear). Pulled out of fish because remote sudo +
heredocs + fish quoting is unreadable past 2 layers. Mirrors the
fish/bash split from S-61.
Cross-references and cookbook:
- S-51 trade-offs row 2 + spec chain table updated.
- S-53 future-work item 1 closed.
- secrets-architecture: spec table extended, Q1 closed, operations
cookbook reference added.
- tasks.md: S-63 row + v0.6.4 banner bump.
- sync-log.md: hostname-tagged entry for the S-63 ship event.
- New operations cookbook docs/operations/2026-05-10-sa-rotation-air-mini.md
documents today's specific rotation across Air + Mini.
Doc discipline:
- scripts/test-doc-discipline.sh extended with S-63 spec + new
helper in FRAMEWORK_DOCS (placeholder-clean) and the new
operations cookbook in OPERATIONS_DOCS (must contain personal
markers). Test passes.
Tested:
- Doc-discipline test: PASS.
- Usage line shape: PASS.
- E2E smoke against headless host (--backing-store=system): PASS;
op whoami via no-agent SSH confirms expected SA Integration ID.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a notify-only sub-check under Step 2 that runs `op whoami` and
greps stderr for the specific 403 "Service Account Deleted" string.
On a hit, the report's notify-only band surfaces the S-63 push one-
liner so the user doesn't have to remember it.
Two cases produce the same error string and the output covers both:
(a) keychain itself is stale (rotation just happened, no fix yet)
→ dotfiles secret push OP_SERVICE_ACCOUNT_TOKEN <hosts> --local --backing-store=system
(b) keychain is fresh but THIS shell's env is older
→ exec fish (reloads env from the fresh keychain)
Fail-soft on every other op error (network down, op missing, signed
out) — those have other surfacing paths and aren't rotation signals.
Updates the Step 3d notify-only example to show how it renders.
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
dotfiles secret pushinto a multi-host upsert: variadic targets,--backing-store=login|system,--local. Auto-detect delete-then-add subsumes seed + rotation on both backing stores.home/dot_local/bin/secret-upsert-targetdoes the per-target dance (probe, delete, add via stdin, verify, neg-clear). Mirrors the fish/bash split from S-61.Why now
Today's rotation went through the pre-S-63 flow: 6 commands across 3 sessions, with
add -Uagainst System.keychain silently failing on the first attempt (User interaction is not allowed+specified item already exists, exit 0, no value change). Decision 2 in the spec codifies the delete-then-add fix; Decision 6 closes the negative-cache footgun. Full design context indocs/specs/S-63-secret-rotate-multi-host.md.What changed
dotfiles secret push--backing-store=login|system,--local. Backwards-compat: existing single-target invocations behave identically.home/dot_local/bin/secret-upsert-targetdocs/specs/S-63-secret-rotate-multi-host.mddocs/operations/2026-05-10-sa-rotation-air-mini.mddocs/specs/S-51-*.md,docs/specs/S-53-*.mddocs/secrets-architecture.mddocs/tasks.mddocs/sync-log.mdscripts/test-doc-discipline.shFRAMEWORK_DOCS; cookbook toOPERATIONS_DOCS.Test plan
scripts/test-doc-discipline.shpasses (11 framework docs placeholder-clean, 2 operations cookbooks contain expected personal markers).fish -c 'dotfiles secret push'shows new usage with all four shape examples.mini-tieubaowith--backing-store=system:1 succeeded, 0 failed.op whoamivia no-agent SSH confirms the expected SA Integration ID post-seed.--localend-to-end on Air (deferred; today's local rotation already happened via the manual paste flow before this PR).host-a host-b) sequential iteration test (not covered today since N=1 in the smoke; helper logic handles it but unverified at runtime).The deferred items are the spec's test-plan rows 9, 10, 13, 14 — exercise on the next real rotation rather than synthesizing them here.
Versioning
v0.6.4 patch (additive; no breaking change to the existing
push VAR targetinvocation form). Banner already bumped intasks.md. Tag the release after this merges.🤖 Generated with Claude Code