feat(secrets): rotation lock for vault read-modify-write cycles (P8, 2/3; stacked on #98) #99
Loading…
Reference in a new issue
No description provided.
Delete branch "jfraeys/feat/rotation-lock"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Merge #98 first (stacked: both add a lint step; until #98 merges the diff also shows its commit).
Nothing serialised two vault rewrites, so two runs (a rotation and a vault-set, or two rotations) could silently lose one update. Plan P8: an OS-level-style lock, stale detection after crashes, documented manual recovery, never delete a lock owned by a live process.
scripts/lib/rotation_lock.py(+rotation-lock.shfor bash):mkdirlock (stock macOS has no flock) with an owner record: pid, host, user, start time, command (key names only, never values). Live owner on this host: refused (exit 3) with who/since/what, andbreakrefuses too. Dead owner on this host (crash, kill -9): treated as stale and cleared on the next run with a [WARN] (atomic rename first, so two racers cannot both clear it). Owner on another host or an ownerless lock: refused (3 / 4),break --forceafter you checked. Children of the owner re-enter via ROTATION_LOCK_HELD and never release the parent's lock.sopsvault.upsert/write(held across the read and the write: no lost update; busy lock = a readable error) andscripts/rotate-secret.sh(not on --dry-run; its EXIT trap also releases).scripts/tests/test-rotation-lock.sh, added to the lint workflow, with real processes: live owner refused and named,breakandbreak --forcerefuse a live owner, kill -9 then stale recovery with the warning, re-entrancy (child passes, child release is a no-op, a stranger is refused), Python API nesting, foreign-host lock (only --force clears), ownerless lock, 8 racers with exactly 1 winner and 7 refused, and the real callers (sopsvault.upsert,rotate-secret.sh) refusing a busy lock without touching secrets/vault.sops.yml (checksum compared). 31 checks pass; shellcheck -S error clean on the new and changed shell files.docs/secrets-management-sops.md(table of situations, manual recovery),scripts/CLAUDE.md(new vault writers must take the lock).Not done here: the monthly workflow and the manifest data (PR 3).
🤖 Generated with Claude Code