Skip to content

fix(security): nothing catches a Flux verify block placed at a path KSail ignores #2920

Description

@devantler

🤖 Generated by the Agentic Engineer

Evidence

ksail workload validate accepts a misplaced Flux verify block silently. Measured 2026-08-03 on ksail.prod.yaml, changing only the block's location:

config result
spec.workload.flux.verify (correct) 556 files validated, exit 0
spec.cluster.verify (wrong — unknown key) 556 files validated, exit 0, no warning

ClusterSpec has no verify field, so the key is discarded. The consequence reached production: the flux-system OCIRepository ran with spec.verify=<none> for ~3 weeks (#2627), pulling a mutable latest tag unverified, while CI stayed green throughout.

Problem

The pre-merge gate cannot see this class of defect. A correctly-written, green-validating security policy can be completely inert, and nothing reports it.

Expected

A check that fails when the platform's intended signature verification is not actually in effect.

Direction

Assert the effective/rendered state, not the config text. A grep for verify: in ksail.prod.yaml would have passed throughout the entire outage — it was present the whole time, just in the wrong place. It would also be defeated by ordinary restructuring, which is the failure mode that closed #2848 after five unconverged bypasses.

Two shapes worth weighing:

  1. Assert the block resolves at the KSail-read path (parse the config and require spec.workload.flux.verify.provider to be non-empty). Cheap, offline, catches this exact defect — but only this one.
  2. Assert against the rendered OCIRepository, so any future path or semantic change is caught regardless of where the key moves. Stronger, and closer to the registry-verification direction of Verify the published evidence before reconciling, instead of inferring it from the workflow text #2859.

Platform's idiom is a Go validator under scripts/<name>/ (cf. validate-dr-signing), so it likely belongs there.

Acceptance criteria

  • A config whose verify block sits at any path KSail does not read fails the check
  • The check passes on the corrected config (fix(security): move Flux cosign verify to the path KSail reads #2919)
  • Ablation recorded: the check is shown to fail on the broken input, not merely to pass on the good one
  • Wired into the same CI job that runs the existing static checks

Part of #2627. Size: S–M.

Activity

  1. moved this to 📥 Backlog in 🌊 Project Boardon Aug 3, 2026
  2. coderabbitai commented on Aug 3, 2026

    @coderabbitai
    Contributor
    ⚠️ Possible Duplicate Issue(s)
    🔗 Related PRs

    #2319 - feat(security): cosign-verify the infrastructure Flux OCI artifact [merged]
    #2502 - feat(ci): validate embedded JSON blobs in ConfigMaps [merged]
    #2633 - fix(deploy): verify incoming image on Talos nodes [merged]
    #2635 - fix(deploy): reboot stale nodes so containerd adopts refreshed GHCR auth [merged]
    #2753 - fix(aws): allow EKS version discovery [merged]


    📝 Issue Planner

    Check the box below or use the @coderabbitai plan command to generate an implementation plan and prompts that you can use with your favorite coding assistant.

    • Create Plan

    🧪 Issue enrichment is currently in open beta.

    You can configure auto-planning by selecting labels in the issue_enrichment configuration.

    To disable automatic issue enrichment, add the following to your .coderabbit.yaml:

    issue_enrichment:
      auto_enrich:
        enabled: false

    💬 Have feedback or questions? Drop into our discord!

  3. devantler commented on Aug 3, 2026

    @devantler
    ContributorAuthor

    🤖 Generated by the Agentic Engineer

    Not the same defect as #2922 — worth stating, since the two read alike

    Both end with "verification configured but not in effect", and they are independent:

    Either one alone reproduces the outage, so fixing one does not close the other. Neither fix catches the other's case.

    A second direction worth weighing before building the rendered-state check

    The proposed check asserts the effective state in this repo's CI, which is right and I am not arguing against it. But the reason the defect is invisible is upstream: an unknown key is discarded silently, so every consumer of KSail config inherits the same blind spot, and the check here only covers the one file we remember to point it at.

    Rejecting unknown fields at decode time in KSail would catch this and every future misplacement, in every repo, at the moment the config is written rather than at review time — the same "generate, don't document" leverage the shared libraries exist for.

    The trade-off is real and is why this is a note rather than a proposal: strict decoding is a breaking change for any config carrying extra keys, and it would need its own rollout (warn-then-reject, exactly like the gate in #2930).

    Suggested shape: build the rendered-state check here as specified — it is the fast, local, non-breaking fix — and file the strict-decode question as a separate KSail spike rather than folding it in. I have not filed that spike, since the call belongs with whoever picks this up.

    ⚠️ Not verified: I have not confirmed how KSail decodes today beyond the silent-discard behaviour this issue already measured. Treat the upstream half as a lead, not a finding.

  4. self-assigned this
    on Aug 4, 2026
  5. added a commit that references this issue on Aug 4, 2026
    c85f121
  6. moved this from 📥 Backlog to 👀 In Review in 🌊 Project Boardon Aug 4, 2026
  7. moved this from 👀 In Review to 📥 Backlog in 🌊 Project Boardon Aug 4, 2026
  8. moved this from 📥 Backlog to 🏃🏻‍♂️ In Progress in 🌊 Project Boardon Aug 4, 2026
  9. moved this from 🏃🏻‍♂️ In Progress to 👀 In Review in 🌊 Project Boardon Aug 4, 2026
  10. moved this from 👀 In Review to ✅ Done in 🌊 Project Boardon Aug 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Fields

No fields configured for Security.

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions