Skip to main content
← Back to list
01Issue
FeatureOpenSwamp CLIPublic
AssigneesNone

Relationships

#2345 worker secret allowlist rejects caller-chosen vault references resolved at run time (method args carrying {vaultName, secretKey})

Opened by randybias · 9/22/2026

Problem

A worker's secret allowlist is built only from vault.get(...) expressions found in the step's global and method args (dispatch_service.ts:496, extractVaultReferences). A method that is given a vault reference as plain data and resolves it at run time through the capability bridge gets refused:

[WRN] worker·bridge: Bridge "capability.resolveSecret" failed after 4ms (...):
"resolveSecret: secret 'inventory_db_root_password' is not referenced by the dispatched step"
✗ Dispatch 5af91441: @mirantis/inventory-ingest.listReservations failed in 666ms

The same workflow and inputs succeed on a local run (loopback), and on serve's loopback.

Why we pass references, not vault.get expressions

We pass {vaultName: ${{ inputs.dbPassVault }}, secretKey: ${{ inputs.dbPassKey }}} so that one definition can run against production and against a test twin with a different vault and key. Our reading was that vault.get() resolves its arguments verbatim, so a run-time input cannot select the vault or key. That gives the choice: either the extension resolves the reference, or the workflow hard-codes the vault. 131 of our 319 workflow files use this pattern. None of them can be placed on a worker.

Reproduction (20260922.011324.0)

A step with workflow-level labels: {pool: x} calls a method with arg dbPassVaultRef: {vaultName: ${{ inputs.v }}, secretKey: ${{ inputs.k }}}. The method resolves the reference through the context vault. Run it via swamp workflow run --server ... with one enrolled worker. The dispatch fails as shown above.

Ask, any one of these

  1. A declared reference type in the model's arg schema (for example a vaultRef / sensitiveRef marker) whose resolved {vaultName, secretKey} values count as static refs in extractVaultReferences.
  2. vault.get(${{ inputs.v }}, ${{ inputs.k }}) resolving input-driven arguments before dispatch. It would then land in staticRefs after resolution, with the allowlist computed after expression resolution.
  3. Documentation of the supported way for a method to take a caller-chosen secret under placement.
02Bog Flow
◉OPEN○TRIAGED○IN PROGRESS○SHIPPED

Open

9/22/2026, 4:16:59 PM

No activity in this phase yet.

03Sludge Pulse
Editable. Press Enter to edit.

randybias commented 9/30/2026, 4:23:21 AM

Any thoughts on this one yet?

Sign in to post a ripple.