Files
home-network-k3s-impl/conformance/tests/l1-rendering/egress-class-render/render-check.sh
jakman85andClaude Opus 4.8 4a017c590e Wire L1 render conformance tests to the renderer (R-NET-01, R-NET-05/06/07)
Implements the two L1 rendering tests that were failing scaffolds:
- egress-class-render (R-NET-05/06/07): renders vpn + internet fixtures, diffs each
  against a committed golden, asserts the vpn steering label is present on vpn and
  absent on internet (fail-closed), and that flipping the class changes ONLY the
  egress path (R-NET-07). This fixes the --requirements R-NET-05 merge gate.
- default-deny-baseline-render (R-NET-01): asserts every render carries the
  namespaced default-deny baseline, shaped deny-all + both directions.

Each test carries a pure-offline render-check.sh (renderer + golden diff, no
cluster). run.sh runs L1 render checks offline and emits a REAL pass/fail JUnit
(docs/14: L1 rendering assertions run in CI without a cluster) instead of skipping
L1 with the cluster-gated layers; the chainsaw-test.yaml wrappers invoke the same
render-check.sh so an in-cluster run executes the identical assertion.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-24 22:19:08 -05:00

51 lines
2.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# =============================================================================
# L1 render check (offline, no cluster) — egress-class-render
# Serves: R-NET-05 (egress is a declared property), R-NET-06/07 (vpn steering /
# flip only changes the egress path). Run by conformance/run.sh --layer l1 and by
# ci/l1.sh. Pure bash + the renderer (catalog/render.py); no cluster, no chainsaw.
#
# GIVEN two ServiceDefinitions identical except `egress: vpn` vs `egress: internet`,
# WHEN the renderer produces resources,
# THEN (1) each matches its committed golden byte-for-byte,
# (2) the vpn render carries the egress-class=vpn steering label and the
# internet render does NOT (fail-closed: no silent vpn path on internet),
# (3) the two renders differ ONLY in the egress-class value (R-NET-07):
# flipping the class changes the egress path, not the workload spec.
# =============================================================================
set -euo pipefail
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd "${DIR}/../../../.." && pwd)" # repo root
RENDER="${ROOT}/catalog/render.py"
PYTHON="${PYTHON:-python3}"
LBL="homelab.keithjackson.dev"
tmp="$(mktemp -d)"
trap 'rm -rf "${tmp}"' EXIT
fail() { echo "RENDER-CHECK FAIL (egress-class-render): $*" >&2; exit 1; }
# (1) golden match for both classes.
"${PYTHON}" "${RENDER}" "${DIR}/fixtures/svcdef-egress-vpn.yaml" > "${tmp}/vpn.yaml"
"${PYTHON}" "${RENDER}" "${DIR}/fixtures/svcdef-egress-internet.yaml" > "${tmp}/internet.yaml"
diff -u "${DIR}/golden/egress-vpn.expected.yaml" "${tmp}/vpn.yaml" || fail "vpn render drifted from golden"
diff -u "${DIR}/golden/egress-internet.expected.yaml" "${tmp}/internet.yaml" || fail "internet render drifted from golden"
# (2) vpn steering label present on vpn, absent on internet (R-NET-05, fail-closed).
grep -q "${LBL}/egress-class: vpn" "${tmp}/vpn.yaml" \
|| fail "vpn render is missing the egress-class=vpn steering label"
if grep -q "${LBL}/egress-class: vpn" "${tmp}/internet.yaml"; then
fail "internet render must NOT carry the vpn steering label (fail-open leak)"
fi
grep -q "${LBL}/egress-class: internet" "${tmp}/internet.yaml" \
|| fail "internet render is missing the egress-class=internet label"
# (3) R-NET-07: the only difference is the egress-class value. Neutralize the class
# value in each render; the rest MUST be byte-identical.
sed 's#egress-class: vpn#egress-class: CLASS#' "${tmp}/vpn.yaml" > "${tmp}/vpn.norm"
sed 's#egress-class: internet#egress-class: CLASS#' "${tmp}/internet.yaml" > "${tmp}/internet.norm"
diff -u "${tmp}/vpn.norm" "${tmp}/internet.norm" \
|| fail "flipping egress class changed more than the egress path (R-NET-07 violated)"
echo "render-check OK: egress-class-render (R-NET-05/06/07)"