picatz / picatz/flowstate

security: make the artifact-integrity envelope algorithm-agile before a second algorithm exists

Open
#1,328 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

design engine kind/decision security
Dominant language
Go
Stars
9
Forks
0
Avg merge
3h 3m
Merged PRs (30d)
509

Description

Problem

The digest format is shaped like it names an algorithm and does not. ContentDigestPrefix = "sha256:" is a constant with ContentDigestHexLen = sha256.Size * 2 (pkg/flowstate/v1/digest.go:29-32); validateDigestPin requires exactly that prefix and 64 lower-case hex (plugin/admission.go:149-178); every comparison is a whole-string compare. A sha384: or blake3: pin is a startup error by construction, and PinsConfig is a strict-mode map[string]string (plugin/pins_config.go:20,:40), so a future pins file that grows a signers: or algorithms: key is refused by every older binary. Both refusals are the right direction — which is exactly why the extension shape should be decided once, deliberately, rather than grown under pressure when a second algorithm arrives.

The repository has already made this call twice and written down why: payloadcodec stamps a key id on every ciphertext because rotation "cannot be retrofitted onto history already written" (pkg/flowstate/v1/payloadcodec/payloadcodec.go), and ResolvedPlugin carries claims_schema_version beside claims_digest with an explicit "empty means not asserted" compatibility rule (proto/flowstate/v1/workflow.proto:684-716). Integrity values live in the same two kinds of hard-to-edit place: reviewed operator configuration and durable run pins.

On post-quantum readiness, measured rather than recalled: go.mod pins go 1.27.0, whose standard library carries crypto/mldsa (FIPS 204) with crypto.Signer, PKCS#8/x509 round-trip, and TLS verification support; measured sizes are ML-DSA-44 pk 1312 B / sig 2420 B up to ML-DSA-87 at 2592/4627 (caveat: unavailable under FIPS 140-3 Go module v1.0.0, available v1.26.0+). So a PQ signing arm is a zero-new-dependency option for this toolchain today. One consequence for the format fork: the in-tree JOSE dependency's algorithm set (RS/PS/ES/EdDSA/HS) carries no ML-DSA as read from the module cache — re-verify upstream — so a JWS-shaped envelope would foreclose PQ until that grows. For hybrid classical+PQ, the composition rule has an in-tree precedent worth copying verbatim: webhook verify: requires every declared scheme to pass, not any one (pkg/flowstate/v1/webhookverify.go:99-101), because satisfying only the weaker half would make adding a scheme a way to weaken the control. Both verify, or the launch is refused. The envelope must also inherit the "never none, never HMAC-for-signatures" rule the auth policy already enforces for JOSE (pkg/flowstate/v1/auth/policy.go:487-518).

Desired outcome

A recorded decision on the integrity-envelope container — algorithm identifier, key id, support for multiple signatures with all-must-verify, and the versioning/compatibility rule — decided independently of who signs (trust-root decision filed separately), so the format is not chosen implicitly by whichever library that decision picks.

Acceptance

  • A design record states the envelope shape, its compatibility rule for older readers (refusal, not silent ignore — matching today's strict parses), and the hybrid rule.
  • Adding a second algorithm (e.g. an ML-DSA arm beside Ed25519) is demonstrably a configuration/registry change, not a format break, argued against the current sha256:-only spellings.

Constraints and dependencies

Sequenced with the trust-root decision: decide this first or together, otherwise the container gets picked implicitly. #1019 rotates the auth signing key inside JOSE and is precedent, not a home; #1216's rehearsal mints no attestations yet, which is exactly why the envelope can still be chosen freely.

Open questions

Whether digest agility (sha256: → multi-algorithm) and signature agility ride one envelope or two; whether the FIPS-module caveat matters for any deployment this project targets.

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 by reading pkg/flowstate/v1/digest.go, plugin/admission.go, plugin/pins_config.go, and the cited payloadcodec, workflow, webhook, and auth-policy code. Compare the current sha256-only validation and strict configuration parsing with the stated algorithm, key-id, multi-signature, and compatibility questions. Done means a design record answers those questions and shows that adding an algorithm is a registry or configuration change rather than a format break.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
cryptography, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.