Add OCI Vault: vaults, keys, secrets - #425
Conversation
Implements OCI Vault against the portable secrets driver. providers/oci/vault holds a Mock over memstore.Store carrying vaults, master encryption keys and their versions, secrets, and secret versions with OCI's CURRENT/PENDING/PREVIOUS/DEPRECATED stages. Deletion is scheduled rather than immediate throughout: a vault, key, secret or version moves to PENDING_DELETION with a timeOfDeletion inside OCI's window and stays there until the deletion is cancelled. The portable DeleteSecret maps onto ScheduleSecretDeletion at the soonest OCI permits, one day out. The portable operations then treat the secret as gone while the OCI surface still lists it and can restore it — the same soft delete the AWS Secrets Manager mock exposes. OCI has no secret outside a vault, so the portable create mints one vault and one AES key on first use. server/oci/vault claims /20180608 for KMS and secret management and /20190301 for the secret-retrieval data plane. Vaults, keys and rotation are OCI-only, so they reach the driver through a consumer-side Extras interface rather than the portable one; a driver that does not satisfy it is served 501. Mutations OCI runs asynchronously record a work request and stamp opc-work-request-id. The KMS crypto endpoint shares the management prefix and is claimed only to report that CloudEmu stores no key material.
Collapses the three changeCompartment handlers and the per-resource mutation tails onto shared helpers, names the path segment positions rather than indexing by number, passes the create specs by pointer, and splits the secret router so the version sub-collection routes on its own. docs/coverage/oci/vault.md lists the seven portable operations and nothing more: vaults, keys and rotation reach the driver through the handler's Extras interface, so they stay out of the AWS, Azure and GCP coverage docs.
NitinKumar004
left a comment
There was a problem hiding this comment.
Review notes
Real data-plane engine (per #427): N/A — OCI Vault is a secrets/KMS service.
CI: the Build failure is a flaky runner I/O error (fork/exec .../link: input/output error), not a code defect — a re-run should clear it. Findings below are the real items.
Findings
Medium · real-engine — Secret name uniqueness enforced globally across all vaults instead of per-vault
providers/oci/vault/secret.go:117
If a user creates a secret named db-password in vault A, then calls CreateSecret (CreateOCISecret) for db-password in vault B -> the handler returns 409 AlreadyExists, but real OCI creates it, because validateSecretSpecLocked (secret.go:117) calls secretByNameLocked (secret.go:398) which scans every secret in every vault and never compares spec.VaultID (OCI scopes secret-name uniqueness to the vault). CancelOCISecretDeletion (secret.go:339) reuses the same global check and can likewise wrongly refuse a restore when an unrelated vault reused the name.
Medium · docs — docs/services.md not updated for OCI Vault (Definition-of-done miss)
docs/services.md:1389
If a user or contributor consults docs/services.md (the human service reference) for OCI secrets -> the ~30-op Vault/KMS surface is invisible: the Secrets header (line 1389) still lists only AWS/Azure/GCP and there is no OCI Vault section, unlike every sibling OCI service (VCN line 407, Monitoring 623, Identity 749). oci-conventions.md Definition-of-done explicitly requires 'Operations added to docs/services.md'; only the generated coverage pages (7 portable ops) were updated, and those cannot describe the OCI-only Extras surface.
Low · docs — Garbled doc comment on VaultManagement interface
server/oci/vault/extras.go:7
If a maintainer reads the VaultManagement doc comment (extras.go:7-11) -> they get an out-of-order, incoherent sentence (a dangling 'container above a secret at all...' fragment and a //nolint:revive directive that runs on into prose), because the comment lines were reordered incorrectly in a tidy edit. The nolint still functions; cosmetic only.
Low · coverage — server/oci/vault wire handler coverage 79.7% (below 90% pillar)
server/oci/vault/handler.go:246
If a client sends an unsupported verb (e.g. DELETE /vaults/{id}) or walks a multi-page list -> those paths ship untested (notFound 0%, listKeys 37.5%, listSecretVersions 50%, getSecretVersion 54.5%, paginate next-page 70%), so a regression in the negative-verb or pagination branch would pass the suite silently.
Low · coverage — No oci-go-sdk SDK-compat test
server/oci/vault/handler_test.go:31
If the wire envelope subtly diverges from what the real oci-go-sdk KMS/Vaults/Secrets client expects (field casing, work-request waiter behavior) -> the hand-rolled map[string]any assertions may still pass while the actual SDK client would fail, because no test round-trips through the real SDK marshaller/waiter (convention calls this the strongest evidence, framed as 'ideally').
Summary
secretsdriver.Extrasinterface. Nothing added toservices/secrets/driver, per Move OCI-only capabilities out of shared driver packages #393.Closes #413. Part of #376.
Changes
providers/oci/vault/—Mockovermemstoreimplementingdriver.Secrets, onesync.RWMutexguarding all four stores: vaults, master encryption keys and key versions, OCI-shaped secrets, secret versions and stages.server/oci/vault/—/20180608management and/20190301retrieval, claimed separately inMatches.providers/oci/oci.goandserver/oci/oci.go.How
DeleteSecretmaps onto scheduled deletionThe interesting design question in this service.
DeleteSecret(name)takes the same path asScheduleSecretDeletion, withtimeOfDeletionat OCI's soonest permitted value — one day out — rather than the 30-day default an unspecified wire call receives.The secret moves to
PENDING_DELETION, keeping its OCID and every version. All seven portable operations then treat it as gone (NotFoundfrom Get/Put/GetValue/ListVersions/Delete; absent fromListSecrets), while the OCI surface still lists it asPENDING_DELETIONandCancelSecretDeletionrestores it — the same soft delete the AWS Secrets Manager mock exposes. Nothing reaps; a scheduled resource stays pending until cancelled.One deliberate consequence: a pending secret releases its name, so a portable delete→recreate works.
CancelSecretDeletionthen fails withAlreadyExistsif the name was retaken, rather than producing two live secrets with the same name.Deletion windows are enforced — 7–30 days for vaults and keys, 1–30 for secrets; out-of-window or unparseable
timeOfDeletionis a 400.Judgement calls
CreateSecretmintscloudemu-default-vaultand an AES-256 key. Tested that a second create reuses them, and that 16 concurrent creates mint exactly one vault.encrypt/decrypt/sign/verify/generateDataEncryptionKey/exportKeyanswer 501 naming the gap, because CloudEmu stores no key material. A fake ciphertext would be worse than an honest refusal.RequireCompartmentIDon/vaults,/keys,/secrets; deliberately not onkeyVersions,secrets/{id}/versions,getByNameor any/20190301path — the real API takes none there and the parent resource already names the compartment.ScheduleVaultDeletionResponsecarries aVault), 204 headers-only for secret and version deletions (those responses carry no body), 202 forchangeCompartment.definedTags,restoreFromFile,restoreFromObjectStore,externalKeyManagerMetadata,autoKeyRotationDetails,externalKeyReference,desiredState,secretRules,rotationConfig,secretGenerationContext, a non-BASE64contentType, and reshaping a key after create.Provider Coverage
Checklist
go test ./...) — exit 0, 272 packagesgolangci-lint run --timeout=9m) — 0 issuescloudemu_test.go— driver + handler tests insteadTest Plan
Coverage leak check clean: no OCI operation in
docs/coverage/{aws,azure,gcp}/*.md;git diff development -- services/empty.docs/coverage/oci/vault.mdlists exactly the 7 portable operations, as expected with capabilities consumer-side.Lock sweep over all 63
*Mockmethods: every one of the 42 exported methods takesm.muexactly once, no locking method calls another locking method, no unexported helper touchesm.mu, and there is nostore.Updateanywhere — so no closure can re-enter its store.End-to-end on a running server (port 4614):
OCIDs came out as
ocid1.{vault,key,keyversion,vaultsecret}.oc1.iad.….A note on parallel worktrees
The session first reported
cmd/cloudemu TestServeOutOfProcessas a pre-existing failure. That was wrong and I have re-checked it: with nothing else running, the test passes on cleandevelopmentin under 6s. The failure is contention on the shared~/.cloudemudaemon lock between the six Wave 2 worktrees running suites in parallel. This branch's full suite is exit 0.Left out
KMS crypto operations (disclosed as 501), OCI secret rules and rotation targets, tag namespaces, and vault backup/restore — each rejected by name rather than silently dropped.