PR #13 added conformance-trigger-job-shape.yaml to platform/kyverno/admission/ kustomization.yaml. That file applies NOTHING. Its own sibling says so: "kept as reference; THIS file is the buildable render root" -- and that render root (platform/kyverno/kustomization.yaml) ships only the namespace and the HelmRelease, noting that ClusterPolicies are applied a tier later, by platform-config, because they need the Kyverno CRDs first. So three lists exist and only platform-config/kustomization.yaml applies anything. The policy went into the wrong one and EVERYTHING WENT GREEN: the file parsed, kyverno test exercised it by path and passed, the merge gate passed, and Flux reported `platform` Ready at the new revision. Measured on prod afterwards: kubectl get clusterpolicy conformance-trigger-job-shape Error from server (NotFound) while ns conformance, the conformance-trigger ServiceAccount, its Role and its RoleBinding were all live. That is exactly the state that identity's own RBAC header says must never exist -- the trigger identity present with nothing bounding it. Blast radius was small only because no trigger kubeconfig exists yet, which is luck, not design. Wires the policy into platform-config (verified: the render goes from 7 ClusterPolicies to 8 and contains conformance-trigger-job-shape). CLOSES THE CLASS, which matters more than the instance. Adds the L0 check admission-policies-actually-applied: every ClusterPolicy file under platform/kyverno/ is either referenced by platform-config/kustomization.yaml or named in a CI_ONLY list with a reason -- and CI_ONLY may not name a policy that IS applied, so the exemption cannot rot in either direction. Declared scope whole-repo deliberately: a policy wired nowhere touches no requirement the diff attributes, so a path-scoped run would have skipped it on the exact commit that introduced the defect. Proven both ways, not assumed: with the fix reverted -> FAIL, naming conformance-trigger-job-shape as never applied with the fix -> PASS, 9 policy files, 8 applied, 1 CI-only with a reason `kyverno test` proves a policy is CORRECT. This proves it is DEPLOYED. Nothing did before. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
121 lines
5.8 KiB
Bash
Executable File
121 lines
5.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# =============================================================================
|
|
# L0 static check (offline, no cluster) — admission-policies-actually-applied
|
|
# Serves: R-SEC-01, R-SEC-02 (admission enforcement is only real if it is APPLIED)
|
|
#
|
|
# WHY THIS EXISTS — a policy that ships green and never reaches the cluster.
|
|
#
|
|
# platform/kyverno/ holds THREE lists, and only one of them applies anything:
|
|
# 1. platform/kyverno/admission/kustomization.yaml — reference only. Its own sibling says
|
|
# "kept as reference; THIS file is the buildable render root".
|
|
# 2. platform/kyverno/kustomization.yaml — that render root: namespace +
|
|
# HelmRelease ONLY. It explicitly notes the ClusterPolicies are applied elsewhere.
|
|
# 3. platform-config/kustomization.yaml — THE ONE. Kyverno CRs go here because
|
|
# they need the CRDs from the HelmRelease in (2), so they reconcile a tier later.
|
|
#
|
|
# On 2026-09-29 a ClusterPolicy (conformance-trigger-job-shape, the R-SEC-02 boundary bounding
|
|
# what the conformance CI trigger may create) was added to (1). Everything went green: the file
|
|
# parsed, `kyverno test` exercised it BY PATH and passed, the gate passed, Flux reported
|
|
# `platform` Ready at the new revision — and the policy was never in any applied set. The
|
|
# cluster ended up running the conformance-trigger ServiceAccount with NOTHING bounding it,
|
|
# which is precisely the state that identity's own RBAC header says must never exist.
|
|
#
|
|
# Nothing could have caught it. `kyverno test` proves a policy is CORRECT, not that it is
|
|
# DEPLOYED. This check asserts the second thing.
|
|
#
|
|
# GIVEN the repository as git tracks it,
|
|
# WHEN every file under platform/kyverno/ that declares a ClusterPolicy is enumerated,
|
|
# THEN each one is either referenced by platform-config/kustomization.yaml (so Flux applies
|
|
# it), or named in CI_ONLY below with a reason — and CI_ONLY itself may not name a
|
|
# policy that IS applied, so the exemption list cannot rot into a lie either way.
|
|
# =============================================================================
|
|
set -euo pipefail
|
|
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
ROOT="$(cd "${DIR}/../../../.." && pwd)" # repo root
|
|
exec python3 - "$ROOT" <<'PY'
|
|
import sys, subprocess
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(sys.argv[1])
|
|
FAILURES, CHECKS = [], 0
|
|
|
|
def check(cond, desc):
|
|
global CHECKS
|
|
CHECKS += 1
|
|
if not cond:
|
|
FAILURES.append(desc)
|
|
|
|
# Policies authored for the CI L0 gate that are deliberately NOT applied in-cluster. Each needs
|
|
# a reason, and each is asserted BELOW to really be absent from the applied set — an exemption
|
|
# that silently starts being applied is as much a lie as one that silently stops.
|
|
CI_ONLY = {
|
|
"disallow-plaintext-secrets":
|
|
"CI-only by design: it requires a top-level `sops` block, which is IMPOSSIBLE at "
|
|
"admission because Flux decrypts before the Secret reaches the API server. Its "
|
|
"in-cluster counterpart is admission/secret-provenance.yaml.",
|
|
}
|
|
|
|
tracked = subprocess.run(["git", "ls-files", "-z", "--", "platform/kyverno/**/*.yaml",
|
|
"platform/kyverno/*.yaml"],
|
|
cwd=ROOT, capture_output=True, text=True, check=True)
|
|
files = [ROOT / p for p in tracked.stdout.split("\0") if p]
|
|
|
|
# A ClusterPolicy file, identified without a YAML parse of every doc: cheap and sufficient.
|
|
policies = {}
|
|
for f in files:
|
|
try:
|
|
txt = f.read_text()
|
|
except Exception:
|
|
continue
|
|
if "kind: ClusterPolicy" not in txt:
|
|
continue
|
|
for line in txt.splitlines():
|
|
st = line.strip()
|
|
if st.startswith("name:") and " name:" in line:
|
|
policies[f.relative_to(ROOT).as_posix()] = st.split("name:", 1)[1].strip()
|
|
break
|
|
|
|
check(len(policies) >= 6,
|
|
f"(0) the scan found {len(policies)} ClusterPolicy file(s) under platform/kyverno/ — "
|
|
f"too few means the scan broke, and every assertion below would be vacuous")
|
|
|
|
applied_txt = (ROOT / "platform-config" / "kustomization.yaml").read_text()
|
|
|
|
unapplied, wrongly_exempt = [], []
|
|
for rel, name in sorted(policies.items()):
|
|
# platform-config references these as ../platform/kyverno/...
|
|
referenced = rel in applied_txt or rel.replace("platform/", "../platform/", 1) in applied_txt
|
|
if name in CI_ONLY:
|
|
if referenced:
|
|
wrongly_exempt.append(f"{name} ({rel}) is listed CI_ONLY but IS applied by platform-config")
|
|
elif not referenced:
|
|
unapplied.append(f"{name} ({rel})")
|
|
|
|
check(not unapplied,
|
|
f"(1) every in-cluster ClusterPolicy is referenced by platform-config/kustomization.yaml "
|
|
f"— an unreferenced policy is authored, tested, green, and NEVER APPLIED {unapplied if unapplied else ''}")
|
|
|
|
check(not wrongly_exempt,
|
|
f"(2) no CI_ONLY exemption names a policy that IS applied — a stale exemption hides a "
|
|
f"real deployment {wrongly_exempt if wrongly_exempt else ''}")
|
|
|
|
for name, reason in CI_ONLY.items():
|
|
check(bool(reason.strip()),
|
|
f"(3) CI_ONLY['{name}'] carries a reason — an unexplained exemption is how this "
|
|
f"list stops being reviewable")
|
|
|
|
check(CHECKS >= 4,
|
|
f"only {CHECKS} assertions ran — the check degenerated to a near-no-op")
|
|
|
|
if FAILURES:
|
|
print(f"CHECK FAIL (admission-policies-actually-applied): {len(FAILURES)} of {CHECKS} assertions failed",
|
|
file=sys.stderr)
|
|
for f in FAILURES:
|
|
print(f" - {f}", file=sys.stderr)
|
|
raise SystemExit(1)
|
|
print(f"check OK: admission-policies-actually-applied — {CHECKS} assertions; "
|
|
f"{len(policies)} ClusterPolicy file(s), {len(policies) - len(CI_ONLY)} applied by "
|
|
f"platform-config, {len(CI_ONLY)} CI-only with reasons. Proves policies are DEPLOYED, "
|
|
f"not that they are correct — `kyverno test` is what proves correctness.")
|
|
PY
|