policy: the trust, egress, and task-shape policy files are read once at process start and never again; nothing documents that a changed file needs a restart, and no running process can say which policy revision it enforces — the baseline #104's reload seam, #1590's digest, and #1884's change record all assume
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 9
- Forks
- 0
- Avg merge
- 3h 3m
- Merged PRs (30d)
- 509
Description
Observed behavior
At 7530b29, all three policy surfaces load exactly once, at start, and install process-wide:
- Task-shape policy:
applyTaskPolicy(cmd/flow/taskpolicy.go:55-80) reads the file, parses, and callsv1.SetDefaultTaskPolicy(policy). - Egress policy:
applyEgressPolicy(cmd/flow/egress.go:167), same shape. - Trust policy: read through
authFlagsOf(cmd/flow/main.go:205) at command start.
There is no reload path. A search for SIGHUP, fsnotify, reload, or a file watch across cmd/flow, pkg/flowstate/v1/server, and pkg/flowstate/v1 returns nothing outside a generated comment. The assessing pass confirmed the consequence at runtime: a task-policy file changed from allow-all to deny-all during a local run did not affect the running process, which completed; a fresh process refused. The per-attempt enforcement tests (enforcementaudit_test.go:178, the row #1884 cites) replace the policy programmatically through SetDefaultTaskPolicy; they prove per-attempt consultation, not that a deployment file edit reaches a running worker. I confirmed the loading code from source and did not re-run the probe.
The documentation does not say this. docs/DEPLOYMENT.md mentions policy loading only as a startup check that gates readiness (:819, :915) and nowhere states that a changed file is not adopted until restart, or that a rolling restart is the adoption mechanism. The --task-policy doc comment says the fail-open a missing file would cause is "the fail-open this flag exists to prevent"; a file that changed after start is the same fail-open wearing a different face, and an operator who edits the file and sees no refusal has no signal that the edit did nothing.
Three open issues assume a baseline that does not exist yet:
- #104 designs a reload seam ("workers poll or are pushed the new digest, compile and type-check it before swapping") over the file surface.
- #1590 wants a policy digest printed at start and carried on audit records, as part of moving the policies to proto.
- #1884 wants a policy change to be an audit record with digests before and after.
None of the three delivers the smallest present-day contract: what a running process enforces, stated where an operator can read it, and what a file edit does, stated where an operator will look.
Desired outcome
Make the current behavior a stated contract before any of the three builds on it:
docs/DEPLOYMENT.md, in each policy section, states: the file is read once at start; a change is adopted by restarting the process; a rolling restart is how a fleet adopts a change; during the roll, workers enforce different revisions, and the audit trail (once #1590 lands) is how to tell which.- Each process logs, at start, a
sha256:digest of each policy file it loaded, beside the existing startup lines, computed over the file bytes today so it does not wait for the proto shape.flow workerandflow serverprint it;flow run local --egress-policyprints it. This is the "which revision does this worker enforce" answer an operator can join againstsha256sumof the file they intended. - A test pins the current behavior on purpose: a policy file rewritten after start does not change enforcement in that process. When #104's reload seam lands, that test changes deliberately rather than the behavior changing silently.
Not in scope: the reload mechanism itself. #104 owns that design and should cite this as its starting condition.
Acceptance criteria
docs/DEPLOYMENT.mdstates the read-once contract for all three files, and the--task-policy,--egress-policy, and--auth-policyflag help text says "read at start".- A startup log line per loaded policy file carries the file path and its digest; a test asserts the line and the digest of a known fixture.
- The pinning test exists for at least the task-shape policy, on both drivers (
flow run localand a worker), since invariant 3 applies to the policy model too (#104, "local parity, held the whole way"). - #104, #1590, and #1884 each cite this issue as the baseline they change.
Constraints and dependencies
- One digest spelling:
sha256:(the spelling #1590 already names). Do not introduce a second. - Fail closed is unchanged: a file that fails to parse at start still refuses the command.
- Adjacent: #104, #1590, #1884, #107 (adoption status is what a control plane would report per worker), #1468 (
flow policy explainshould print the digest it explained against, which is #1590's acceptance already).
Open questions
- Whether the digest should also appear in the readiness endpoint so a fleet's adoption state is scrapeable without log access. Cheap, but it exposes a hash of a "crown jewel" file (
THREAT_MODEL.mdasset 4) to anyone who can reach/healthz; the threat model should decide.
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 docs/DEPLOYMENT.md and the loading entry points in cmd/flow/taskpolicy.go, cmd/flow/egress.go, and cmd/flow/main.go. Read the existing startup logging and policy tests, including enforcementaudit_test.go, then verify the documented read-once contract, sha256 startup lines, flag help text, and task-policy pinning tests for local and worker drivers.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- devops, documentation, observability
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 48/100