T-0.2 CI merge-gate pipeline + portable local runners (R-TEST-02/03, R-GITOPS-01)

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
jakman85andClaude Opus 4.8 committed 2026-08-16 00:08:33 -05:00
1 parent de56c55dcc
commit 0d86630271
15 files changed
+1022 -2

No files matched your search

+81
View File
@@ -0,0 +1,81 @@
#!/usr/bin/env bash
# .gitea/workflows/scripts/decide.sh — merge-gate decision job for Gitea Actions.
# Reads upstream job results (Gitea/GitHub Actions values: success | failure |
# skipped | cancelled) from env and applies the R-TEST-03 rule honestly.
#
# R_LINT R_L0 R_L1 L0/L1 layers (run in CI, no cluster). Any failure -> BLOCK.
# R_CONF L2/L3 conformance job:
# success -> green
# failure/cancelled -> BLOCK
# skipped + CLUSTER_AVAILABLE=true -> BLOCK (should have run)
# skipped + no cluster -> UNVERIFIED (Phase 0), do NOT fake green
#
# Set REQUIRE_CLUSTER_TESTS=true (Phase 1+) to turn any unverified cluster-needing
# touched requirement into a hard block.
set -uo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${HERE}/../../.." && pwd)"
: "${R_LINT:=}"; : "${R_L0:=}"; : "${R_L1:=}"; : "${R_CONF:=}"
: "${CLUSTER_AVAILABLE:=false}"
: "${REQUIRE_CLUSTER_TESTS:=false}"
sm() { [ -n "${GITHUB_STEP_SUMMARY:-}" ] && printf '%s\n' "$*" >> "$GITHUB_STEP_SUMMARY" || true; }
say() { printf '%s\n' "$*" >&2; }
cluster_on() { case "$CLUSTER_AVAILABLE" in true|1|yes) return 0;; *) return 1;; esac; }
block=0
sm "## Merge gate decision (R-TEST-03)"
sm ""
sm "| Stage | Result |"
sm "|---|---|"
for pair in "lint:$R_LINT" "l0:$R_L0" "l1:$R_L1"; do
name="${pair%%:*}"; res="${pair#*:}"
case "$res" in
success) say "[ ok ] ${name}: green"; sm "| ${name} | pass |" ;;
skipped|"") say "[warn] ${name}: skipped/unwired (Phase 0 placeholder) — not green"; sm "| ${name} | skipped |" ;;
*) say "[FAIL] ${name}: ${res} -> BLOCK"; sm "| ${name} | **FAIL** |"; block=1 ;;
esac
done
# Touched-requirement subset for reporting UNVERIFIED items.
mapfile -t reqs < <("${REPO_ROOT}/ci/touched-requirements.sh" 2>/dev/null || true)
case "$R_CONF" in
success)
say "[ ok ] conformance (L2/L3): green"; sm "| conformance (L2/L3) | pass |" ;;
failure|cancelled)
say "[FAIL] conformance (L2/L3): ${R_CONF} -> BLOCK"; sm "| conformance (L2/L3) | **FAIL** |"; block=1 ;;
skipped|"")
if cluster_on; then
say "[FAIL] conformance skipped but CLUSTER_AVAILABLE=true -> BLOCK"
sm "| conformance (L2/L3) | **FAIL (skipped w/ cluster)** |"; block=1
else
sm "| conformance (L2/L3) | skipped — cluster required (Phase 0) |"
if [ "${#reqs[@]}" -gt 0 ]; then
say "[warn] L2/L3 UNVERIFIED (no cluster) for touched requirements: ${reqs[*]}"
sm ""
sm "> **UNVERIFIED (no cluster, Phase 0):** ${reqs[*]}"
if [ "$REQUIRE_CLUSTER_TESTS" = "true" ]; then
say "[FAIL] REQUIRE_CLUSTER_TESTS=true and requirements unverified -> BLOCK"; block=1
fi
else
say "[skip] L2/L3 skipped; no cluster-needing requirements touched"
fi
fi ;;
*)
say "[FAIL] conformance: unexpected result '${R_CONF}' -> BLOCK"; block=1 ;;
esac
sm ""
if [ "$block" -eq 0 ]; then
say "MERGE GATE: PASS"
sm "**Result: PASS** — touched-requirement subset green for the layers that can run this phase."
exit 0
else
say "MERGE GATE: BLOCKED"
sm "**Result: BLOCKED** — see failures above."
exit 1
fi
+53
View File
@@ -0,0 +1,53 @@
#!/usr/bin/env bash
# .gitea/workflows/scripts/install-tools.sh — install the PINNED tools a given
# gate stage needs on a Gitea Actions runner. Versions come from ci/versions.env
# (single source of truth, R-TEST-02). Usage: install-tools.sh <lint|l0|l1|conformance>
set -euo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${HERE}/../../.." && pwd)"
# shellcheck disable=SC1091
source "${REPO_ROOT}/ci/versions.env"
stage="${1:-all}"
os="$(uname -s | tr '[:upper:]' '[:lower:]')"
arch="$(uname -m)"; case "$arch" in x86_64) arch=amd64 ;; aarch64|arm64) arch=arm64 ;; esac
bindir="${HOME}/.local/bin"; mkdir -p "$bindir"
echo "${bindir}" >> "${GITHUB_PATH:-/dev/null}" 2>/dev/null || true
export PATH="${bindir}:${PATH}"
log() { printf '[install] %s\n' "$*" >&2; }
install_yamllint() { have yamllint || { log "yamllint ${YAMLLINT_VERSION}"; pip install --quiet "yamllint==${YAMLLINT_VERSION}"; }; }
install_kyverno() {
have kyverno && return 0
log "kyverno CLI ${KYVERNO_VERSION}"
local url="https://github.com/kyverno/kyverno/releases/download/v${KYVERNO_VERSION}/kyverno-cli_v${KYVERNO_VERSION}_${os}_${arch}.tar.gz"
curl -fsSL "$url" | tar -xz -C "$bindir" kyverno
}
install_chainsaw() {
have chainsaw && return 0
log "chainsaw ${CHAINSAW_VERSION}"
local url="https://github.com/kyverno/chainsaw/releases/download/v${CHAINSAW_VERSION}/chainsaw_${os}_${arch}.tar.gz"
curl -fsSL "$url" | tar -xz -C "$bindir" chainsaw
}
install_kubectl() {
have kubectl && return 0
log "kubectl ${KUBECTL_VERSION}"
curl -fsSL -o "${bindir}/kubectl" "https://dl.k8s.io/release/v${KUBECTL_VERSION}/bin/${os}/${arch}/kubectl"
chmod +x "${bindir}/kubectl"
}
have() { command -v "$1" >/dev/null 2>&1; }
case "$stage" in
lint) install_yamllint ;;
l0) install_yamllint; install_kyverno ;;
l1) install_chainsaw ;; # L1 render via conformance runner (Chainsaw)
conformance) install_chainsaw; install_kubectl ;; # trigger the in-cluster Job
all) install_yamllint; install_kyverno; install_chainsaw; install_kubectl ;;
*) echo "unknown stage: $stage" >&2; exit 2 ;;
esac
log "stage '${stage}' tools ready"