Each driver is real-service code only (no test awareness; tests inject just an
HTTPClient/Bin), following the established patterns:
- mongo: in-place changeUserPassword over the old connection; no secret on argv
(host/db on the URI, both passwords on stdin, output scrubbed).
- npm: create token -> /-/whoami -> delete-by-key; blob records the key.
- gcp: service-account KEY rotation; mints an RS256 JWT signed with the SA's
own private key (crypto/rsa, stdlib) to self-auth the IAM create/verify/delete.
- twilio: API Key create -> get -> delete, Basic auth (KeySid/secret).
- flyio: GraphQL — a managing token mints/deletes the rotated deploy token.
- k8s: create a service-account-token Secret, await the populated token,
verify against the SA, delete the old Secret (invalidates the old token).
All 6 register their honest proof level (MOCK-ONLY) in proofs.go +
ROTATION-PROOFS.md; mongo/npm/k8s are LIVE-VM candidates pending real-target VM
POCs. Emulators enforce credential validity (gcp verifies the JWT signature),
tests assert Verify(old) fails after revoke + a secret-leak canary.
Full suite: 103 green, -race clean on rotate/sink/vault.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add gitlab, cloudflare, ghactions (MOCK-ONLY) and appsecret (LIVE-VM) one-file
Rotators, each with a table-driven cutover-proof + leak-check test. gitlab/
cloudflare/ghactions are in-place SaaS-token rolls (self/rotate, value-roll,
sealed-secret overwrite) so RevokeOld is a no-op; ghactions seals via
nacl/box.SealAnonymous (no new go.mod dep). appsecret regenerates a local app
signing secret and rewrites it in place across every target file (atomic, mode-
preserving, redacted errors), discoverable via exact-match app-signing key names
in env.go.
Keep real-rotation code distinct from mock code: how each driver's cutover was
validated lives as DATA in internal/rotate/proofs.go (single source of truth) +
docs/ROTATION-PROOFS.md, surfaced as a PROOF column in `incredigo rotate` so a
MOCK-ONLY driver can never be mistaken for a LIVE-VM one. appsecret proven LIVE-VM
against real local files in the sandbox VM.
82 tests green, -race clean on rotate/sink/vault.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
internal/blast builds a read-only consumer map (which other files appear to
use each credential) from NON-secret metadata only — env-var names, hostnames,
identifiers — never the vault secret; rotation needs it to know what to
redeploy after a change. cmd/incredigo wires Mode A `rotate --execute`
(reconstructs Source from the gopass path segment, runs the execute spine) and
surfaces the blast-radius map. Adjusts a worklist test accordingly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
An env credential's Identity (".env / API_TOKEN") produced StorePath
imported/env/.env/api_token; gopass hides dot-prefixed segments from
`ls --flat`, so those entries were invisible to bundle.ListPaths and the
mandatory backup gate silently under-covered them (Hard Rule #1 violation).
slug() now strips leading dots per /-separated segment so incredigo can no
longer write a path that `ls --flat` hides. Locked in by
TestStorePathNoDotSegment.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Per the standing directive (dynamic discovery per credential type as each
driver lands):
- env.go: tag DB connection URLs by scheme (postgres/postgresql, mysql/mariadb,
redis/rediss) with a user:password authority, routing DATABASE_URL/REDIS_URL/
MYSQL_URL straight to the in-place DB drivers, kept regardless of the
secret-name heuristic.
- aws.go: emit the driver-ready single-line blob (was the bare secret) and
resolve region from env / ~/.aws/config.
- ssh.go: content-based key detection (not just id_*) + ~/.ssh/config
IdentityFile parsing.
- tea.go: new scanner mapping Gitea `tea` CLI config to a driver-ready PAT blob.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements the Rotator interface across all four rotation patterns, each a
self-contained one-file driver self-registering via init():
in-place DB password postgres, mysql (3-stmt unprivileged fallback), redis
local keypair + propagate sshkey (ed25519), wireguard (clamped curve25519)
provider-API token gitea PAT, mullvad device key
cloud-key self-identifying aws IAM access key (hand-rolled SigV4, no SDK dep)
Spine (execute.go) enforces Hard Rule #2: backup -> rotate -> verify(new) ->
store -> re-read+verify -> revoke-old; dryrun.go keeps --execute gated. Each
driver ships a table-driven test proving real cutover (old secret stops
authenticating) and asserting no secret substring leaks to argv/Meta/errors.
Promotes golang.org/x/crypto to a direct dependency.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Design-phase foundation for v2 rotation. Changes NO credential at any service.
- internal/rotate: Rotator interface + registry + PlanAll (zero drivers
registered, so every credential plans as "(none)")
- internal/rotate.Snapshot: the MANDATORY backup gate — seals the gopass
prefix into an authenticated bundle, re-opens it, and confirms the entry
count matches before returning; any failure blocks rotation
- internal/sink.CountBundleRecords: read-only bundle completeness check
- cmd: `incredigo rotate` runs the backup gate + prints the plan; it is
dry-run only and refuses --execute (design phase)
- tests: backup gate happy path, no-overwrite, tamper detection; race-clean
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>