picatz / picatz/flowstate

flowtest: a var seeded from one case's `secrets:` prints in full for every other case

Open
#2,041 1 comment 0 reactions 0 assignees View on GitHub

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 test leaks both identically — caseError (run.go) renders the same sentence under the same posture — so this is not specific to the flow validate surface 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 flowtest containment 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 own secrets: still withholds the entry's material.
  • Cases for both routes, on flow test and flow validate, since the posture is shared.

Two candidate shapes

  1. Drop the literal-seed exclusion and let a seed join withheldVars like 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.
  2. 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 and sensitive: input values to the posture, and documents this surface in the containment table. It does not touch the seed rule.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.