#!/usr/bin/env bash # ci/l1.sh — Stage 4: L1 rendering checks. Runs in CI WITHOUT a cluster # (docs/14: "L1 rendering assertions run in CI without a cluster"). # # L1 asserts ServiceDefinition -> rendered resources match golden expectations # (e.g. `egress: vpn` renders the kill-switched egress path). The actual render # + assert is Chainsaw's L1 layer, owned by the conformance harness (T-0.4). # CI just invokes the runner filtered to the L1 layer and the touched subset. set -euo pipefail CI_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck disable=SC1091 source "${CI_DIR}/lib.sh" log "Stage: L1 rendering checks (no cluster)" mkartifacts if ! entrypoint_ready "$CONFORMANCE_CMD"; then skip "conformance runner not present at '${CONFORMANCE_CMD}' (T-0.4 / conformance/ not delivered yet) — UNWIRED, not green" summary "- l1-render: **SKIPPED** (conformance runner missing — T-0.4)" exit 3 fi # Touched-requirement subset (R-TEST-03). An empty OR undeterminable subset => run all # L1 as a superset sanity net, and SAY SO — see load_touched_requirements in ci/lib.sh. load_touched_requirements req_args=(${REQ_ARGS[@]+"${REQ_ARGS[@]}"}) # RECONCILED (PM 2026-08-16): conformance/run.sh's real interface is `--layer ` # [--requirements R-A,R-B]; it ALWAYS writes artifacts to a FIXED location # (conformance/_artifacts/) and does NOT accept --junit/--coverage. Invoke by layer + # touched subset, then COLLECT its artifacts into the CI artifact dirs. "$CONFORMANCE_CMD" --layer l1 ${req_args[@]+"${req_args[@]}"} CONF_ART="$(dirname "$CONFORMANCE_CMD")/_artifacts" if [ -f "${CONF_ART}/report.junit.xml" ]; then cp "${CONF_ART}/report.junit.xml" "${JUNIT_DIR}/l1.junit.xml" fi if [ -d "${CONF_ART}/coverage" ]; then cp -r "${CONF_ART}/coverage/." "${COVERAGE_DIR}/" fi ok "L1 rendering checks passed" summary "- l1-render: **passed**"