fix(campaign): reject a when clause with no depends_on (inert-gate fail-open)#177
Merged
Conversation
…il-open) A campaign step's `when` clause is evaluated against its predecessor's output, and that evaluation lives entirely inside the Runner's `if step.DependsOn != ""` block (campaign.go:284). A step authored with a `when:` but no `depends_on:` therefore never reaches the when check — the Runner runs its tool UNCONDITIONALLY. `when` is exactly the mechanism an operator uses to make a destructive tool conditional (e.g. `when: contains "AUTHORIZED"`), so a missing depends_on turns an intended gate into a silently-inert one: a fail-open. ParseYAML now rejects `When != "" && DependsOn == ""` at load, matching the package's existing validate-at-parse philosophy (duplicate ids, unresolved / self / forward depends_on, cycles, and malformed/negative timeouts already fail at load, not mid-run). A `when` with no predecessor has no output to evaluate against, so it is meaningless as well as unsafe — failing loudly at load forces the operator to make the dependency explicit instead of getting an inert guard. ParseYAML is the sole production construction path (the web campaign API, ParseFile, and eval all route through it; there is no struct-literal bypass), so the parse-time rejection fully closes the fail-open. Found via the internal audit sweep of the automation engines (rules / campaign / workflows); the rest of those engines verified sound (tool dispatch routes through RunTool's gates, template-into-params is operator-scoped and non- recursive, cooldown is race-free, inFlight is leak-safe). Test: TestParseYAML_RejectsWhenWithoutDependsOn — a step with `when` and no `depends_on` is rejected; proven to fail pre-fix (the campaign parsed clean and the step would have run unconditionally). Verified: task ci green (lint 0 / vet / build / test:full -race 0 fail / govulncheck clean); task eval 17/17.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A campaign step's
whenis evaluated against its predecessor's output, and that check lives entirely inside the Runner'sif step.DependsOn != ""block. A step withwhen:but nodepends_on:never reaches the check — its tool runs UNCONDITIONALLY.whenis how an operator gates a destructive tool conditional (e.g.when: contains "AUTHORIZED"), so a missing depends_on turns an intended gate into a silently-inert one: a fail-open. ParseYAML now rejectsWhen != "" && DependsOn == ""at load (matching the package's validate-at-parse philosophy). ParseYAML is the sole production construction path, so this fully closes it. Found via the internal automation-engine sweep (rest verified sound). Test proven to fail pre-fix. task ci green; eval 17/17.