Add markpost sources rotate-secret command - #130
Merged
Conversation
Adds `markpost sources rotate-secret [uuid]` to rotate a provider source's signing secret against markpost's POST /api/sources/[uuid]/rotate-secret endpoint. Generated providers (github/zapier/shortcuts) reveal a fresh secret once; stripe prompts (masked) for the pasted value. Closes #126.
Collaborator
Author
Independent code review trailRan the independent reviewer (Opus, did not write the code) for the full 3-round loop. It did not converge to Round 1 — 7 findings:
Round 2 — 5 findings:
Round 3 — 4 findings:
|
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.
What & why
Adds
markpost sources rotate-secret [uuid]— the CLI had no way to rotate a source's signing secret, the only recovery path when a signing secret is lost or compromised (the one-time create reveal aside). Closes #126.Targets markpost's
POST /api/sources/[uuid]/rotate-secret(server/api/sources/[uuid]/rotate-secret.post.ts). The response reveals the freshly-generatedproviderSecretexactly once, mirroring source creation.Behaviour
create).existing.provider).uuidmay be omitted to pick from an interactive list; the picker only offers rotatable (provider-backed) sources.Key decisions
provider, nottype— this mirrors markpost's rotate-secret handler exactly. markpost's create path (deriveProvider→normalizeProvider) always persists a canonical lowercaseproviderfor provider-typed sources, so the value the CLI reads back is already normalized; an exact-match check is correct and avoids offering rotation the server would reject.@inquirer/promptspassword,mask: true) — the one place the CLI accepts a secret, kept out of terminal scrollback/CI logs.failWithMessage): a failed rotation, or a generated rotation whose response omits the plaintext, is surfaced as an error before any success line and with a non-zero exit, since the rotation may already have replaced the live secret. Pre-write validation failures (not-rotatable, blank secret, uuid-not-found) exit 0 to stay consistent with the siblingupdate/deletehandlers.create/update/rotate-secretnow go through onewriteSourceRequesthelper (rule of three — the JSON:API write envelope + unwrap + error fallback was about to be duplicated a third time), kept generic over the JSON:API resource type so the serializer-drift envelope types stay live.Tests
tests/libs/sources.test.ts:rotateSourceSecretURL/method/headers/body (empty vs supplied secret), uuid encoding, success unwrap, error surfacing, timeout propagation, network-failure null.tests/commands/sources.test.ts: generated reveal-once, masked stripe prompt + payload, blank-secret abort, non-rotatable refusal, not-found, picker filtered to rotatable sources, empty-list messages, rotation-failure exit code, missing-secret alarm + exit code, no-leak of an echoed manual secret, control-char sanitisation,--jsonrejection.tests/types/sources.types.test.ts: locks the manual/generated/rotatable provider sets to markpost'sshared/utils/webhookSecrets.ts.Viewable
CLI command — run
markpost sources rotate-secret --help-style usage viamarkpost sources(usage text updated), ormarkpost sources rotate-secret <uuid>.Closes #126
Follow-up suggestions
Status-code-aware rotate/create error messages—rotateSourceSecret(and the shared write seam) collapse every failure tonull, so the command can't distinguish a clean 4xx rejection (nothing changed) from an ambiguous post-commit 5xx/parse failure; threading the status through would let the CLI drop the "previous secret may no longer work" caveat when it definitely doesn't apply. (suggested: P3, effort: M, evidence: src/libs/sources.ts writeSourceRequest, src/commands/sources.ts rotateSecretForSource)