Skip to main content
It fails closed on every check it can run, so a conflict with your taints, quotas or admission profile surfaces now instead of during your first sync. Run it again when the environment changes — new nodes, a new quota or LimitRange, a changed admission profile, a Kubernetes upgrade. Releases need no preflight: that is what the channel is for. Give it --manifests. Without it there are no delivered workloads to check and P2/P3 see only the bot profile — the reason a 4Gi postgres limit cleared a 2560Mi ceiling on 2026-09-06 and was refused at admission after a green install. install.sh renders the chart itself; run standalone, hand it a render.
Each check prints PASS, WARN, FAIL or NOT EVALUATED with a remedy line; --json emits the same report machine-readably. Exit 4 is the third answer, and it is not a verdict on your cluster. A namespace-scoped account cannot list nodes or StorageClasses; reporting that as PASS claims something was verified and reporting it as FAIL claims a defect nobody observed. So those checks say NOT EVALUATED, name the read that was refused, and get their own exit code — sharing 0 with a clean run is how “four of these were never looked at” used to read as “your cluster is fine”. Turn them into answers with the snapshot handoff below. install.sh names them and continues.
  • P1 · Taints and tolerations — workloads that cannot schedule sit Pending forever. Covers the dynamically spawned bot pods, which appear in no manifest.
  • P2 · Resources vs LimitRange — a LimitRange silently defaults undeclared containers to 64Mi. Compares every declared request and limit, memory and cpu, against max and min — the four pairs admission itself checks — and names the object and the number it would be refused on. Prints the ceiling it compared against, so a pass says what was true when it was taken.
  • P3 · ResourceQuota headroom — quota that cannot fit the declared totals refuses pods at the margin. Memory and cpu.
  • P4 · Pod security admission — reads the effective admission: the PSA enforce level and the SCC annotations the namespace actually carries. OpenShift SCC restricted-v2 rejects explicit UIDs outside the namespace range; PodSecurity restricted needs runAsNonRoot, seccomp, capability drops. Names the workload that would be refused. A namespace enforcing neither is NOT EVALUATED, never a pass — a green obtained from the enforcement being absent is the one answer this check must not give.
  • P5 · NetworkPolicy reachability — default-deny egress with no DNS allowance, or no route to the registry. Static by default, which cannot prove a route; the live probe needs --live-probes --registry-host.
  • P6 · Shared-memory sizing — the bot’s memory-backed /dev/shm counts against its memory limit; checks your LimitRange max and node capacity hold it.
  • P7 · Image pull (opt-in) — pulls a release image by digest with this namespace’s secrets; warm node caches hide broken credentials until the first new release. It creates a pod and needs the namespace’s image-pull Secret, which the install writes, so it runs only with --live-probes --pull-test-image <ref> and belongs after the install rather than before it.
  • P8 · Storage — a default StorageClass exists if the delivered set carries volume claims.
  • P9 · Version floor — Kubernetes is at or above the tested floor.
Live-probe pods are themselves PodSecurity restricted compliant, so preflight works inside hardened namespaces. Air-gapped clusters: dump on a connected workstation with cluster access, then analyse anywhere with --snapshot cluster.json. Live probes need cluster access; everything else works from the snapshot.
Preflight answers will it run here, never did it work here. A cluster can pass every check and still fail to capture a meeting — that is the smoke test’s job, and it needs a human. vexa_validate.py runs both in order and packages the receipts together. Next: Install · Operations