Relationships
#3558 typed-secrets 2.2: VaultSecretBag entries hold references, one registry per run, 128-bit sentinels
Opened by zack · 10/16/2026· Shipped 10/16/2026
Outcome
Every VaultSecretBag entry carries its reference, its encoding and its
data-origin flag beside the value it holds today. Every pass of a run issues
sentinels into one run-scoped registry, of which a step's bag is a view. The
sentinel prefix is 128 random bits. The persisted form is derived from entries,
not from a value search. Values are still read eagerly, so behavior is
unchanged.
Why now
This is the structural half of Phase 2 in design/enablers/typed-secrets.md Section 11, specified in Section 3.2. Doing it while values are still eager means every existing suite proves the refactor preserved behavior before 2.3, not yet filed, changes what a bag holds. It does not depend on 2.1 (swamp-club#3557), and 2.3 depends on both.
Scope
VaultSecretBagentries hold a reference (vault name and key), an encoding and a data-origin flag, beside the value. Data-origin entries record the source thatRunSensitiveValuesalready holds for each value.- The run-scoped bag registry: the run-start pass, workflow-level evaluation
and every step pass issue sentinels into it, and a step's bag is a view of
it, so a sentinel from an earlier pass is never delivered as literal text.
Rehoming between bags (
SanitizedTaskOverlay.forStep) covers vault-origin entries as well as data-origin ones. - The sentinel prefix grows from 32 to 128 random bits in src/domain/vaults/vault_secret_bag.ts. A sentinel-shaped string with another prefix stays ordinary text.
toPersistedFormtakes its entries from sentinels, and its callers pass the registry. The value search stays only for plaintext that data reads still bring into CEL, and the code says so.alignProvenanceandSplicePaircompare sentinels, not values.- Tests: property tests for the sentinel format and the persisted-form round trip (fast-check, beside the source); an integration test in integration/ that a sentinel issued in the run-start pass resolves from a later step's bag and through a child workflow's rehoming.
- The design doc's source map (Section 13) if a seam moves.
Follow the repository conventions: no subprocesses or env mutation in tests,
withMockedEnv for env values, and deno run license-headers for new files.
Exit
- Existing suites pass unchanged.
- A sentinel issued by any pass of a run resolves from any step's bag of that run, including after rehoming into a child workflow.
- The persisted form of a run with vault-origin and data-origin secrets is the same as today's apart from the longer prefix, and no value search is needed for a vault-origin entry.
- Each entry answers its reference, encoding and data origin without reading its value.
Out of scope
- Stopping the eager read, the load step, the inline resolutions as loads, and the existence check (2.3).
- Removing
sentinelResolverOf, which still has a value to resolve until 2.3. VaultExistenceProviderandhas(2.1).- Any
Secretvalue or refusal in CEL (Phase 3).
Shipped
Click a lifecycle step above to view its details.
Sign in to post a ripple.