Skip to main content
← Back to list
01Issue
FeatureShippedSwamp CLIPublic
Assigneeszack

Relationships

#3627 typed-secrets 3.4: destination refusals, identifier stand-ins, shell safety and masking

Opened by zack · 10/19/2026· Shipped 10/20/2026

Outcome

On the internal typed-secrets path, local behavior execution applies destination policy to reference sentinels before loading values. Refusing destinations fail with secret_destination_refused; identifier destinations retain their existing stand-ins; reports, events, logs and errors expose masks or value-free diagnostics. Shell secrets reach the child environment without being pasted into swamp's command text.

This is Phase 3.4 of design/enablers/typed-secrets.md, Sections 3.3, 6.3, 7, 10.1 and 11. It builds on Phase 3.2, swamp-club#3625 and Phase 3.3, #3626 so both vault-origin and data-origin values arrive as registered sentinels.

Scope

  • Refusal metadata. Support .meta({ secrets: "refuse" }) beside the existing sensitive metadata, using the existing metadata walker. A field marked both sensitive and refuse is a schema error. At the method execution boundary, inspect merged global and method arguments and refuse a secret anywhere in a refusing field before loading the attempt's bag. Preserve the existing exclusion of global arguments with unresolved expressions and the existing refusal to save literal sensitive global arguments.
  • Delivery ordering. After destination checks pass, use the shared Phase 2 load once per reference per attempt. Resolve method/global arguments, merge and validate as today. Local pre-flight checks and the method share the loaded context.vaultSecrets; checks receive resolved global arguments and method arguments with sentinels in unresolvedMethodArgs. Keep remote checks skipped as today.
  • Identifiers and paths. For local behavior destinations, derive the existing sensitive-<vault>.<key> stand-ins for names, tags, labels and data-name suffixes directly from registered sentinels. Refuse secrets in path destinations. Do not inspect plaintext to decide these policies. Preserve ordinary text, including sentinel-shaped text from another prefix.
  • Shell placement. Keep the existing POSIX and PowerShell 5.1 quote-context scanner and environment-variable placement. Generated environment names must not collide with authored keys. Mark workingDir as refusing and reject secrets in environment keys. Replace the two data-origin plaintext-pasting cases with refusals: a quoted-delimiter here-document and PowerShell single quotes. Detect these reference-based refusals before a delivery load or process launch. A vault.get inside single quotes keeps today's literal-reference behavior and warning on both shells.
  • Environment values. Allowed secrets are loaded into the child environment, with exact values preserved. A value containing an embedded NUL is rejected after loading but before launch, without echoing the value. Distinguish this value-dependent check from the destination refusals that require no load.
  • Masks and errors. Share one implementation per destination family. Mask registered sentinels as *** in local reports, events, logs, previews, history and telemetry; ensure errors and method-output records carry no value. Keep output redaction for plaintext returned or emitted by trusted consumers. Do not load a reference just to mask it. Persistence destinations that require reference text continue using their persisted-form contract rather than display masks.
  • Rollout and coverage. Keep the new behavior behind the internal option, set only by tests. Use integration/secret_sink_inventory.json to cover the Phase 3 destinations and keep the inventory/rules aligned if a sink is discovered. Record 3.4 and its source map in the design when it ships.

Acceptance criteria

  • Refusal metadata covers scalar, nested, list/map and composed values across global and method arguments. Conflicting metadata fails as a schema error. Destination refusals occur before any delivery load or check/method invocation and use secret_destination_refused without a value.
  • Identifier stand-ins are derived from references even when no plaintext was loaded. Unknown-prefix sentinel-shaped input remains ordinary data.
  • Both shell strategies retain environment-variable placement for allowed secrets, avoid generated-name collisions and preserve literal vault.get single-quote behavior. The two prohibited data-origin placements, secret working directories and secret environment keys refuse before loading or launching.
  • Every permitted canary reaches the trusted method/check boundary or child environment exactly as specified. Swamp's shell command text contains no plaintext. An embedded NUL fails before launch with a value-free error.
  • Local report/event/log/error and output-record tests cover vault-origin and data-origin sentinels, compositions and canary classes in both log and JSON output modes. Masking makes zero provider calls and does not depend on the length or contents of a value.
  • The relevant Phase 3 sink inventory checks pass, output redaction remains in place, and option-off behavior remains unchanged.

Use in-process unit tests for metadata, destination policy, masking and the POSIX/PowerShell scanners. Add integration tests for refusal-before-load and exact delivery; mock subprocess execution in this repository. Compiled-binary shell journeys and prohibited-sink scans belong in swamp-uat on supported OS/shell targets.

Later slices

Phase 3.5 wires the local entry points and effectful calls through these policies. Phase 4 owns workflow task selectors, placement, child workflow references, guards/asserts, step identities, run events/records/indexes and the remaining inline resolutions listed in Section 3.3. Phase 5 owns remote dispatch and control-plane sinks. This issue does not remove the internal option or the legacy paths needed by later phases.

02Bog Flow
✓OPEN✓TRIAGED✓IN PROGRESS✓SHIPPED+ 1 MOREASSIGNED+ 9 MOREREVIEW+ 25 MOREPR_MERGED+ 2 MORESESSION_SUMMARIZED

Shipped

10/20/2026, 8:56:28 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
zack assigned zack10/20/2026, 4:48:28 PM

Sign in to post a ripple.