feat(cmd): S04-B one-shot operator composition seam
What
S04-B Plan Step 2 — the one-shot operator composition seam the subcommands wire: runOperator + the operatorDeps injectable seam + the rotationStore interface + operatorRuntime. Reuses S04-C's wire_encryption.go helpers (resolveSecretsProvider/newRootKeyProvider/logEncryptionTierWired) rather than reimplementing the chain.
Composition order: load config → refuse a missing encryption block before any database access (the operator tool requires it, unlike the server's skip) → appLogConfig logger + component stamp + FIPS-version startup log (before the fallible stages, so a failed run still leaves an operator record) → own signal-to-context cancellation → root-key provider (validated + zeroized, key-set identity logged) → database client + command-side rotation store → run the command action. No listeners/metrics/jobs; the manager is Step 8's (conditional).
The plan's Step 2 text listed both a command-side rotationStore factory and the defaultNamespaceKeyStore/defaultNamespaceKeyManager factories; this MR takes the rotationStore reading and amends the plan in-diff — the manager is Step 8's, and the production store factory lands with the subcommands in Step 3.
Tests
Composition unit tests with injected fakes (no DB): missing-block refusal, and the secret-resolve / secret-load / decode / db-client / rotation-store / cleanup-join error branches (each pinned by its sentinel or stage wrap); signal cancellation (SIGTERM and SIGINT, with the action's own observation asserted); the forwarded client and cache TTL read back through a factory spy; the runtime logger's stream, component stamp, and configured level; the client factory's received config and the action context's parent derivation; FIPS-version log before the fallible stages (a failed composition still leaves an operator record); key-set identity log; no key material in logs. All mutation-killed.
Covers the composition-level Error Cases rows (missing block, secret-load, db-unreachable, interruption) and underpins AC 12 and AC 14.
E2E: none — composition seam, no format-client scenario.
Notes
Stacked on Step 1 (!1343 (merged)): this MR targets that branch so its diff is Step 2 only; GitLab retargets it to main when Step 1 merges.
Related to https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/496