Skip to main content
← Back to list
01Issue
FeatureOpenExtensionsPublic
AssigneesNone

Relationships

↔ sibling #3030

#18 @swamp/digitalocean/space-key stores secret in plaintext - should mark as sensitive

Opened by stack72 · 4/7/2026· GitHub #29

Description

The @swamp/digitalocean/space-key extension model does not mark the secret field as sensitive in its ResourceSchema. When a Spaces key is created via the DigitalOcean API, the response includes both access_key and secret. The secret field is not declared in the schema and passes through via .passthrough(), resulting in it being stored in plaintext in the .swamp/ data directory.

Steps to reproduce

  1. Create a space-key model: swamp model create @swamp/digitalocean/space-key my-key --global-arg name=test-key
  2. Run the create method: swamp model method run my-key create
  3. Inspect the persisted data in .swamp/data/ — the secret field is stored in plaintext

Expected behavior

The secret field should be:

  1. Explicitly declared in the ResourceSchema (not relying on .passthrough())
  2. Marked with z.meta({ sensitive: true }) so it is auto-vaulted
  3. Replaced with a ${{ vault.get(...) }} reference in the persisted data

Suggested fix

In space_key.ts, update the ResourceSchema to explicitly include the secret field with sensitive metadata:

const ResourceSchema = z.object({
  name: z.string().optional(),
  grants: z.array(z.object({
    bucket: z.string().optional(),
    permission: z.string().optional(),
  })).optional(),
  access_key: z.string().optional(),
  secret: z.string().meta({ sensitive: true }).optional(),
  created_at: z.string().optional(),
}).passthrough();

Environment

  • swamp version: 20260401.170720.0-sha.ac267ac9
  • Extension: @swamp/digitalocean v2026.03.31.1

Automoved by swampadmin from GitHub issue #29

02Bog Flow
◉OPEN○TRIAGED○IN PROGRESS○SHIPPED

Open

4/7/2026, 11:28:58 PM

No activity in this phase yet.

03Sludge Pulse
stack72 linked sibling of #303010/5/2026, 5:19:41 PM
Editable. Press Enter to edit.

sntxrr commented 9/30/2026, 7:38:01 PM

Still reproduces on @swamp/digitalocean 2026.09.29.1 (space-key model 2026.06.08.1). Two corrections to the suggested fix, plus the same gap in other DO models.

1. The field is secret_key, not secret. DigitalOcean's create response is {"key": {name, access_key, secret_key, grants, created_at}} (key_create_response.yml). create unwraps it and writes the whole object as state (space_key.ts#L170-L180). ResourceSchema is .passthrough() and does not declare the field (#L55-L63). So a fix that declares secret would leave secret_key in plaintext. It should be:

secret_key: z.string().meta({ sensitive: true }).optional(),

2. The fix belongs in codegen. space_key.ts is generated ("Do not edit manually"). DO codegen only marks the injected token input as sensitive (extensionModelGenerator.ts#L135, #L184). No output field is marked in any DO model. secret_key exists only on the create-response schema, so the generator never sees it when building ResourceSchema. Suggested: merge create-response-only properties into ResourceSchema, and mark known secret fields sensitive (a name list, or a per-resource override map).

The same gap in other DO models (declared in ResourceSchema, returned by the DO API, not marked sensitive):

  • database_user.ts: password (L71), access_key (L73)
  • database_cluster.ts: password and credential-bearing uri in connection, private_connection, standby_connection, standby_private_connection, ui_connection, schema_registry_connection (L223-L278)
  • database_replica.ts: connection / private_connection password and uri (L113-L128)
  • function_namespace.ts: key (the namespace auth key) (L77)
  • database_logsink.ts: config.key, config.datadog_api_key (L83, L90)

Behaviour change to call out: once these fields are marked, create/get/sync need a configured vault at write time (#566), so users without one will start failing. Values already persisted by earlier versions stay in older data versions. Keys minted before the fix should be rotated, and the fix alone doesn't do that.

Suggested tests:

  • Codegen snapshot: the space-key ResourceSchema contains secret_key: z.string().meta({ sensitive: true }).
  • Model level: a fake fetch returns DO's documented example (secret_key: "DOSECRETKEYEXAMPLE") from POST /v2/spaces/keys. Run create, then assert that the persisted state bytes do not contain DOSECRETKEYEXAMPLE and do contain a vault.get( reference. There are no DO model tests today; the GCP/AWS _test.ts models are the nearest pattern.

sntxrr commented 9/30/2026, 7:38:22 PM

Correction: the CLI redactor treated the pinned commit SHAs in the links above as secrets, so they show as [REDACTED-SECRET-n]. Replace them with:

  • [REDACTED-SECRET-1] (DO openapi): 569464c1b5844f9f28ee982e5620e49f6a7887d8
  • [REDACTED-SECRET-2] (swamp-extensions): 0a0f205485061a15d458dbc378f7aaa064f40145

For example: https://github.com/swamp-club/swamp-extensions/blob/0a0f205485061a15d458dbc378f7aaa064f40145/model/digitalocean/extensions/models/space_key.ts#L170-L180

Sign in to post a ripple.