flowtest: a var seeded from one case's `secrets:` prints in full for every other case
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 9
- Forks
- 0
- Avg merge
- 3h 3m
- Merged PRs (30d)
- 509
Description
Problem
withheldMaterial (pkg/flowstate/v1/flowtest/vars.go:1799) deliberately skips a literal seed — a var whose value is a plain string that a secrets: entry names:
A literal seed: the
secrets:entry naming it already carries its plaintext into the case that declared it, and this is the one place widening would reach a file that states no expression.
That justification assumes the seed's material only reaches the case that declared the secret. Substitution makes it false: any case may put ${vars.token} in any fixture position, and a case's posture is built from its own secrets: plus the withheld set — which the seed is excluded from.
Two reachable routes, both confirmed by execution (flowstate-reviewer, reviewing picatz/flowstate#2040):
Cross-case. tests[0] declares secrets: {env:VENDOR_TOKEN: ${vars.token}}; tests[1] declares no secrets and scripts signals[0].name: ${vars.token}:
test "signals": signals[0].name "sk-live-crosstest-1234" matches no gate…
Table row with its own secrets. mergeRow (pkg/flowstate/v1/flowtest/table.go:184) does if len(merged.Secrets) == 0 { merged.Secrets = entry.Secrets } — replace, not merge — so a row declaring any secrets of its own loses the entry's from its posture:
test "entry/row": signals[0].name "sk-live-rowown-1234" matches no gate…
Scope
- Pre-existing, and symmetric.
flow testleaks both identically —caseError(run.go) renders the same sentence under the same posture — so this is not specific to theflow validatesurface picatz/flowstate#2040 closes, and that PR is not the regressor. Confirmed on both surfaces. - Material is a fixture value rather than a production secret, which is the same standing every other
flowtestcontainment finding has.
Acceptance criteria
- A var named by any case's
secrets:is withheld from every case's renderings in that file, or the literal-seed exclusion is replaced by something that does not assume one reader. - A
cases:row that declares its ownsecrets:still withholds the entry's material. - Cases for both routes, on
flow testandflow validate, since the posture is shared.
Two candidate shapes
- Drop the literal-seed exclusion and let a seed join
withheldVarslike any other tainted var. Simplest, and widens what is withheld for files that state no expression — which is what the current comment says it was avoiding. - Make the posture file-wide for seeds: keep the exclusion, but add every case's
secrets:plaintext to every case's posture. Narrower, and closer to what the material actually is — a value the file holds, not the case.
mergeRow's Secrets replace-not-merge wants deciding either way: a row overriding one entry is arguably not asking to drop the rest.
Related
- picatz/flowstate#2040 — routes
flow validate's signal-name refusal through the redaction seam, adds the%q-escaped spelling andsensitive:input values to the posture, and documents this surface in the containment table. It does not touch the seed rule.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with withheldMaterial in pkg/flowstate/v1/flowtest/vars.go:1799, then inspect mergeRow in pkg/flowstate/v1/flowtest/table.go:184 and caseError in run.go to trace the shared posture and rendering paths. Reproduce both cross-case and row-specific-secret routes on flow test and flow validate. Done means every case withholds material named by any case's secrets, including entry material when a row declares its own secrets.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- security, testing
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100