Repository navigation
Description
🤖 Generated by the Agentic Engineer
Evidence
The unifi GitRepository in k8s/providers/hetzner/apps/unifi/git-repository.yaml tracks a moving
branch and carries no spec.verify block:
url: https://github.com/devantler-tech/unifi
ref:
branch: mainFlux therefore accepts whatever the branch tip is, relying entirely on GitHub having enforced the
source repository's own rules. It does not itself check that the commit it fetched is signed.
Why this is defence-in-depth, not an open hole
Measured 2026-08-14: devantler-tech/unifi and devantler-tech/platform carry the same trust
controls — required signed commits, required pull request, linear history, blocked force pushes,
required status checks, required conversation resolution. Every one of the last 10 commits on
unifi@main reports verified=true.
So the source is not a weaker trust boundary than this repository. Adding verification closes the
residual case where the enforcement layer itself is bypassed or misconfigured, which is worth having
but is not urgent.
Expected behaviour
Flux verifies the signature on the commit it fetches, and refuses to reconcile an unverifiable one.
Smallest useful first step
Add spec.verify (mode HEAD) to the GitRepository with a secretRef holding the trusted public
keys, then confirm reconciliation still succeeds against the current tip.
Known risk to design around
Recent commits on the source are bot-authored and signed with GitHub's key, so the trusted key set
must cover that. A signing method the key set does not cover would block reconciliation rather
than warn — turning a hardening change into an outage. Validate against the real tip before merging,
and stage it so a verification failure is observed before it can affect the live Kustomization.
Acceptance criteria
- The GitRepository carries
spec.verifyand reconciles the current tip successfully. - A commit that fails verification is demonstrably refused (negative control).
- The live
unifiKustomization staysReady=Truethroughout.
Rough size: small–medium. Supersedes the suspend-based approach in #2705, which was closed because
suspending halts a healthy live reconciliation without raising the attacker's bar.
Metadata
Metadata
Assignees
Labels
Type
Fields
Projects
- StatusShow more project fields✅ Done
Activity
coderabbitai commentedon Aug 14, 2026
🔗 Related PRs
#3103 - feat(security): assert the node image verifier can enforce at all [merged]
#3109 - fix(deploy): avoid redundant GHCR node reboots [merged]
📝 Issue Planner
Check the box below or use the
@coderabbitai plancommand to generate an implementation plan and prompts that you can use with your favorite coding assistant.🧪 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:💬 Have feedback or questions? Drop into our discord!
chore: agent-claim #3124 nonce=3d462aa03eeb5a96f383b6d87ebd6446
devantler commentedon Aug 24, 2026
Delivered the verification boundary in #3357, merged as signed main commit 0c2676f after merge-group CI 32785799205 and its production deploy passed.
Read-only production evidence after merge:
The issue remains open for the second acceptance criterion. An unsigned local Git control was rejected and the repository validator has negative regressions for missing/wrong verification and widened key material, but those do not demonstrate source-controller itself refusing an unverifiable commit. No production resource was mutated to manufacture that failure.
devantler commentedon Aug 25, 2026
Revalidated on pickup — the premise changed the day after this was filed
This issue's evidence records the
unifiGitRepository tracking a moving branch:That is no longer true, and it stopped being true on 2026-08-15 — one day after this was
filed.
platform@a9a177fb("fix(unifi): prevent pruning managed network resources", #2707)replaced the branch with a full commit pin, and added a comment giving the same reasoning this
issue opens with:
Verified live this run against
admin@prod:and that pinned commit itself reports
verified=true, reason=valid.What that does to the proposed fix
The threat named here — "Flux accepts whatever the branch tip is" — is closed, and closed by a
stronger control than the one proposed. A 40-hex commit pin fixes the content cryptographically:
Flux fetches that object or fails. Signature verification answers who signed the tip; a SHA pin
removes the tip from the question entirely. Moving the pin is a reviewed Platform PR, which is the
same review gate
spec.verifywould have been protecting.So implementing
spec.verifynow would add a control whose residual value is small, while carryingthe exact outage risk this issue's own "Known risk to design around" section flags: a trusted key set
that fails to cover a signing method blocks reconciliation rather than warning. For the record,
that key set would be simple — all 20 most recent commits on
unifi@mainaredependabot[bot],PGP-signed by GitHub's web-flow key, uniformly
verified=true— but simple is not the same asworth the risk against a threat that is already closed.
Implementing it mechanically because the issue says so is precisely what revalidating on pickup is
meant to prevent.
The residual, which is real
The mitigation is a convention held in one YAML file with nothing asserting it. Nothing in CI
fails if a future change reverts
ref.committoref.branch— for auto-updates, or ascollateral in an unrelated refactor — and the moment that happens this issue's original threat is
back, silently, with no signature verification behind it either.
scripts/validate-flux-verify/does not cover this: it targets the operator-generated rootOCIRepository, a different resource and a different control.Decision
Reframing rather than closing: the security intent (source integrity for
unifi) still stands, butthe delivery changes from add signature verification to guard the commit pin that replaced it.
Superseded acceptance criteria are struck through below rather than deleted, so a reader meeting an
older reference can see why.
The GitRepository carriesspec.verifyand reconciles the current tip successfully.Dropped — superseded by the
ref.commitpin (fix(unifi): prevent pruning managed network resources #2707), a stronger control.A commit that fails verification is demonstrably refused (negative control).Droppedwith the above.
GitRepositoryunderk8s/uses a mutable ref instead of a40-hex
ref.commit, and its message names the reason and the fix.so it cannot pass vacuously.
unifiKustomization staysReady=Truethroughout (static guard only; no manifestbehaviour change).
chore: agent-claim #3124 nonce=696671e3027ef7dd4973a35d0099aae5
chore: agent-claim #3124 nonce=3beb47d5f8289522430ec5b2a13ad86a
chore: agent-claim #3124 nonce=db57e539ae23d918b2d33a9fae3c3ae5
fix(security): identify a GitRepository by apiVersion AND kind, and r…