diff --git a/conformance/tests/l0-static/c2-root-surface/chainsaw-test.yaml b/conformance/tests/l0-static/c2-root-surface/chainsaw-test.yaml new file mode 100644 index 0000000..07773f4 --- /dev/null +++ b/conformance/tests/l0-static/c2-root-surface/chainsaw-test.yaml @@ -0,0 +1,116 @@ +# ============================================================================= +# L0 STATIC — the C2 root surfaces every service the cluster runs, plus platform +# health and controlled actions (R-C2-01, R-C2-02) [EXECUTABLE] +# Catalog: docs/14 L0 row ("Pre-apply, in CI") — runs WITHOUT a cluster. +# +# THE REQUIREMENTS, VERBATIM (spec docs/00-vision-and-scope.md): +# R-C2-01 "The root `home.keithjackson.dev` MUST serve a UI that surfaces the services +# running in the cluster and links to them." +# R-C2-02 "The C2 UI MUST surface platform health (cluster, storage, GitOps, alerts) and +# provide controlled operational actions where safe." +# Detail: spec docs/12-command-center-ui.md — Homepage at the root is "the primary R-C2-01 +# surface"; Headlamp is "the R-C2-02 'controlled operational actions where safe' surface"; +# Grafana is the dashboards/alerts surface; "never a raw cluster-admin kubeconfig in a browser". +# +# WHY L0, AND NOT L2 +# ------------------ +# The REACHABILITY half of R-C2-01 is already exercised against a live cluster: +# l2-behavioral/gateway-ingress-reachable dials the Gateway and l2-behavioral/trusted-tls +# verifies the certificate it serves. What no live probe can decide is the half the +# requirement is actually about — whether the UI at the root surfaces THE SERVICES RUNNING +# IN THE CLUSTER. Deciding that is a comparison of two SETS, and both are repository facts: +# what git declares the cluster serves (every in-repo HTTPRoute hostname, every L4 Service +# that publishes a hostname, every catalog ServiceDefinition) against what the dashboard's +# ConfigMap links. A probe of the root gets HTTP 200 from a dashboard that hides half the +# estate and cannot tell the difference. +# +# It is also the assertion that ROTS, in the direction nothing else notices: onboard a +# service, forget the dashboard, and every cluster test stays green while the operator's +# front door hides a running service. That is not a styling preference — it is exactly the +# R-C2-01 failure mode, and this check found a live instance of it when it was written (see +# the commit message: platform/crafty served crafty.${BASE_DOMAIN} and nothing on the root +# linked to it). +# +# GIVEN the repository as git tracks it, +# WHEN the apex ingress, the dashboard's declared link set, every in-repo HTTPRoute, every +# hostname-publishing L4 Service, the versioned catalog and the platform-health +# surfaces are read and compared, +# THEN — R-C2-01 — +# the bare apex is claimed by exactly one route, that route binds the ONE Gateway +# listener whose hostname matches a bare apex, the apex is a SAN on the certificate +# that listener terminates with, the dashboard is RECONCILED (not merely authored), +# FORWARD every HTTP service the repo routes is linked from the root, FORWARD every +# catalog `kind: container` service with a route is linked, and REVERSE every +# home-zone link the root offers resolves to something this repo actually serves — +# an HTTPRoute (L7) or a hostname-publishing LoadBalancer Service (L4); +# — R-C2-02 — +# both health surfaces docs/12 names are linked AND reconciled, the health DATA exists +# as code (PrometheusRule groups for cluster/nodes, storage, GitOps and cert expiry, +# reconciled by the platform-config tier), and actions are CONTROLLED: the console +# binds NO ClusterRole to its own ServiceAccount, authenticates per-user by native +# OIDC from a named SOPS Secret, and cluster rights arrive through OIDC GROUPS at more +# than one privilege level. +# +# STATUS: EXECUTABLE. `check.sh` is a pure offline assertion script (git ls-files + PyYAML — +# the same dependency catalog/render.py already requires). conformance/run.sh --layer l0 and +# ci/l0.sh run it directly; this Chainsaw Test wraps the SAME script. +# +# WHAT IT DOES NOT PROVE — honest gaps, restated in check.sh's own header: +# - That the apex answers HTTP 200, or that any tile's status ping is green. That is L2; +# the Gateway/TLS half is covered under R-DNS-01 / R-TLS-01. +# - That the C2 is access-CONTROLLED in fact. The auth assertions read a DECLARED posture, +# because the Gateway ext-authz attachment that would enforce forward-auth is not built +# anywhere in this repo (platform/homepage/httproute.yaml says so in its own header, and +# every forward-auth app shares the gap). Declared, not enforced — and labelled as such +# in the assertion text. +# - That an operational action in the console succeeds, or that it is audited. The +# assertions prove there is no shared cluster-admin identity to act with and that rights +# arrive per-user; the audit trail is a runtime property. +# - Whether a tile is USEFUL. Homepage service-widget API keys are a deliberate follow-up +# (platform/homepage/configmap.yaml); link presence is what R-C2-01 asks for. +# ============================================================================= +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: c2-root-surface + labels: + conformance.home.k3s/R-C2-01: "true" + conformance.home.k3s/R-C2-02: "true" + annotations: + conformance.home.k3s/requirements: "R-C2-01, R-C2-02" + conformance.home.k3s/layer: "L0" + # WHOLE-REPO SCOPE, and it is the whole point of the forward assertion. + # + # The invariant is "every service the repo routes is linked from the C2 root". Its input + # surface is therefore EVERY tracked manifest that can declare an HTTPRoute — apps/wave-*, + # platform/*, runbooks/ — not just the two components that own the C2. ci/touched- + # requirements.sh keys `platform/homepage/*` and `platform/headlamp/*` to nothing at all + # today (there is no path-map arm for either), and even with one, the change that BREAKS + # this invariant is the change that adds a route somewhere else: `apps/wave-1/newthing.yaml` + # attributes R-GITOPS-02 / R-NET-* / nothing, never R-C2-01. Requirement-scoped selection + # would filter this check out of exactly the change that introduces the bug — the R-TEST-03 + # blind spot recorded in conformance/lib/common.sh. + # + # Declaring the scope is the whole fix: conformance/run.sh --include-scope whole-repo + # (ci/l0.sh Stage 3b) unions this test into EVERY gate invocation. Do NOT hand-add a stage + # to ci/l0.sh — tests/l0-static/whole-repo-invariants-wired fails the gate if anyone does. + # A SKIP of a scope-declaring check is rc 3 (UNWIRED), never green. + conformance.home.k3s/scope: "whole-repo" + conformance.home.k3s/safety-critical: "false" + conformance.home.k3s/executable: "true" + conformance.home.k3s/intent: >- + The bare apex is bound to the landing dashboard over trusted TLS and is reconciled; the + dashboard links every HTTP service this repo routes and every link it offers resolves to + something the repo serves; and the C2 surfaces platform health backed by real alert rules + while granting operational rights per-user through OIDC groups rather than through a + shared cluster-admin identity. +spec: + steps: + - name: compare-the-c2-root-against-what-the-repo-actually-serves + description: >- + Read the apex ingress chain, the dashboard's declared links, every in-repo HTTPRoute and + hostname-publishing Service, the catalog, the platform-health alert rules and the + console's RBAC posture, and assert the two sets agree in both directions. + try: + - script: + content: bash ./check.sh