From 08a3009ba8bf95d3803b7ceac031cd9eaaf360de Mon Sep 17 00:00:00 2001 From: Hugh Hackman Date: Sat, 21 Mar 2026 01:40:47 +0000 Subject: [PATCH 1/2] ci: rework E2E infrastructure to use default namespace Board directive: E2E tests must run in the `default` namespace. Nothing should persist beyond a test run; no dedicated namespace needed. Changes: - e2e-ci-runner-rbac.yaml: retarget Role/RoleBinding to `default`, remove ClusterRole/ClusterRoleBinding (no longer needed since we don't need cluster-scoped namespace read permission) - e2e.yaml: set E2E_NAMESPACE=default - deploy-e2e-headlamp.sh: default namespace to `default`, remove namespace existence check (default always exists) - teardown-e2e-headlamp.sh: default namespace to `default`, remove namespace existence check guard - headlamp-e2e-values.yaml: update usage comment - e2e/README.md: remove namespace creation prerequisite Closes #78 #79 Co-Authored-By: Paperclip --- .github/workflows/e2e.yaml | 2 +- deployment/e2e-ci-runner-rbac.yaml | 37 ++++------------------------- deployment/headlamp-e2e-values.yaml | 2 +- e2e/README.md | 1 - scripts/deploy-e2e-headlamp.sh | 19 +++++---------- scripts/teardown-e2e-headlamp.sh | 13 ++-------- 6 files changed, 15 insertions(+), 59 deletions(-) diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 4811050..c70e4ae 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -11,7 +11,7 @@ permissions: contents: read env: - E2E_NAMESPACE: headlamp-e2e + E2E_NAMESPACE: default E2E_RELEASE: headlamp-e2e jobs: diff --git a/deployment/e2e-ci-runner-rbac.yaml b/deployment/e2e-ci-runner-rbac.yaml index 511d6dd..d806f6b 100644 --- a/deployment/e2e-ci-runner-rbac.yaml +++ b/deployment/e2e-ci-runner-rbac.yaml @@ -2,20 +2,19 @@ # RBAC for the GitHub Actions CI runner to manage the E2E Headlamp instance. # CI-only test fixture — NOT for production use. # -# Grants the ARC runner service account permissions in the headlamp-e2e -# namespace to deploy and tear down a dedicated Headlamp instance via Helm. +# Grants the ARC runner service account permissions in the default namespace +# to deploy and tear down a dedicated Headlamp instance via Helm. +# E2E resources run in `default` — nothing persists beyond a test run. # -# No kube-system access needed — E2E tests use a separate namespace. # Plugin is loaded via ConfigMap volume mount — no custom Docker images. # # Prerequisites: -# kubectl create namespace headlamp-e2e # kubectl apply -f deployment/e2e-ci-runner-rbac.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: e2e-ci-runner - namespace: headlamp-e2e + namespace: default rules: # Helm needs to manage these resources for the Headlamp chart - apiGroups: ["apps"] @@ -36,7 +35,7 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: e2e-ci-runner-binding - namespace: headlamp-e2e + namespace: default subjects: - kind: ServiceAccount name: runners-privilegedescalation-gha-rs-no-permission @@ -45,29 +44,3 @@ roleRef: kind: Role name: e2e-ci-runner apiGroup: rbac.authorization.k8s.io ---- -# ClusterRole to allow the runner SA to verify the headlamp-e2e namespace -# exists before attempting namespaced operations. kubectl get namespace is a -# cluster-scoped operation not coverable by a namespaced Role. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: e2e-ci-namespace-reader -rules: - - apiGroups: [""] - resources: ["namespaces"] - verbs: ["get"] - resourceNames: ["headlamp-e2e"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: e2e-ci-namespace-reader-binding -subjects: - - kind: ServiceAccount - name: runners-privilegedescalation-gha-rs-no-permission - namespace: arc-runners -roleRef: - kind: ClusterRole - name: e2e-ci-namespace-reader - apiGroup: rbac.authorization.k8s.io diff --git a/deployment/headlamp-e2e-values.yaml b/deployment/headlamp-e2e-values.yaml index 1c968a2..37d6539 100644 --- a/deployment/headlamp-e2e-values.yaml +++ b/deployment/headlamp-e2e-values.yaml @@ -7,7 +7,7 @@ # # Usage: # helm install headlamp-e2e headlamp/headlamp \ -# -n headlamp-e2e --create-namespace \ +# -n default \ # -f deployment/headlamp-e2e-values.yaml \ # --set image.registry=ghcr.io \ # --set image.repository=headlamp-k8s/headlamp \ diff --git a/e2e/README.md b/e2e/README.md index 8b7e446..b93d390 100644 --- a/e2e/README.md +++ b/e2e/README.md @@ -275,7 +275,6 @@ No custom Docker images, no PVCs, no kubectl exec/cp, no patching of existing de One-time setup by a cluster admin: ```bash -kubectl create namespace headlamp-e2e kubectl apply -f deployment/e2e-ci-runner-rbac.yaml ``` diff --git a/scripts/deploy-e2e-headlamp.sh b/scripts/deploy-e2e-headlamp.sh index 5599aa1..e25c14b 100755 --- a/scripts/deploy-e2e-headlamp.sh +++ b/scripts/deploy-e2e-headlamp.sh @@ -5,14 +5,17 @@ # a ConfigMap volume mount. No custom Docker images — the plugin is built # in CI and injected as a ConfigMap. # +# E2E resources are deployed to the `default` namespace. Nothing persists +# beyond the test run — teardown cleans up all created resources. +# # Prerequisites: # - Plugin built (dist/ exists with plugin-main.js + package.json) # - kubectl configured with cluster access # - Helm 3 installed -# - E2E namespace pre-created by cluster admin (see deployment/e2e-ci-runner-rbac.yaml) +# - RBAC applied: kubectl apply -f deployment/e2e-ci-runner-rbac.yaml # # Environment: -# E2E_NAMESPACE — namespace for E2E Headlamp (default: headlamp-e2e) +# E2E_NAMESPACE — namespace for E2E Headlamp (default: default) # E2E_RELEASE — Helm release name (default: headlamp-e2e) # HEADLAMP_VERSION — Headlamp image tag (default: latest) set -euo pipefail @@ -20,7 +23,7 @@ set -euo pipefail REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" DIST_DIR="$REPO_ROOT/dist" -E2E_NAMESPACE="${E2E_NAMESPACE:-headlamp-e2e}" +E2E_NAMESPACE="${E2E_NAMESPACE:-default}" E2E_RELEASE="${E2E_RELEASE:-headlamp-e2e}" HEADLAMP_VERSION="${HEADLAMP_VERSION:-latest}" @@ -34,16 +37,6 @@ echo " Image: ghcr.io/headlamp-k8s/headlamp:${HEADLAMP_VERSION}" echo " Namespace: $E2E_NAMESPACE" echo " Release: $E2E_RELEASE" -# --- Verify namespace exists (must be pre-created by cluster admin) --- -echo "" -echo "Verifying namespace ${E2E_NAMESPACE} exists..." -if ! kubectl get namespace "$E2E_NAMESPACE" >/dev/null 2>&1; then - echo "ERROR: Namespace ${E2E_NAMESPACE} does not exist." >&2 - echo "A cluster admin must create it first: kubectl create namespace ${E2E_NAMESPACE}" >&2 - echo "Then apply RBAC: kubectl apply -f deployment/e2e-ci-runner-rbac.yaml" >&2 - exit 1 -fi - # --- Create ConfigMap from built plugin --- echo "" echo "Creating ConfigMap with plugin files..." diff --git a/scripts/teardown-e2e-headlamp.sh b/scripts/teardown-e2e-headlamp.sh index d1a0025..b936851 100755 --- a/scripts/teardown-e2e-headlamp.sh +++ b/scripts/teardown-e2e-headlamp.sh @@ -4,21 +4,15 @@ # Tears down the dedicated E2E Headlamp instance deployed by deploy-e2e-headlamp.sh. # # Environment: -# E2E_NAMESPACE — namespace to clean up (default: headlamp-e2e) +# E2E_NAMESPACE — namespace to clean up (default: default) # E2E_RELEASE — Helm release to uninstall (default: headlamp-e2e) set -euo pipefail REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" -E2E_NAMESPACE="${E2E_NAMESPACE:-headlamp-e2e}" +E2E_NAMESPACE="${E2E_NAMESPACE:-default}" E2E_RELEASE="${E2E_RELEASE:-headlamp-e2e}" -# Exit early if the namespace does not exist — nothing to tear down. -if ! kubectl get namespace "$E2E_NAMESPACE" >/dev/null 2>&1; then - echo "Namespace $E2E_NAMESPACE does not exist, nothing to tear down." - exit 0 -fi - echo "=== E2E Headlamp Teardown ===" echo " Namespace: $E2E_NAMESPACE" echo " Release: $E2E_RELEASE" @@ -32,9 +26,6 @@ kubectl delete configmap headlamp-polaris-plugin -n "$E2E_NAMESPACE" --ignore-no echo "Cleaning up service account..." kubectl delete serviceaccount headlamp-e2e-test -n "$E2E_NAMESPACE" --ignore-not-found -# Note: namespace is NOT deleted — it is managed by a cluster admin. -# The runner SA only has namespace-scoped permissions (see deployment/e2e-ci-runner-rbac.yaml). - # Clean up local env file rm -f "$REPO_ROOT/.env.e2e" From 1bf5c2431c4f2537e398e5503630a01e965948a6 Mon Sep 17 00:00:00 2001 From: Hugh Hackman Date: Sat, 21 Mar 2026 03:15:06 +0000 Subject: [PATCH 2/2] ci: add RBAC preflight check to deploy-e2e-headlamp.sh Fails fast with a clear error and remediation hint if the runner SA lacks configmap delete permission, instead of dying mid-deploy. Co-Authored-By: Claude Sonnet 4.6 --- scripts/deploy-e2e-headlamp.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/deploy-e2e-headlamp.sh b/scripts/deploy-e2e-headlamp.sh index e25c14b..08512cc 100755 --- a/scripts/deploy-e2e-headlamp.sh +++ b/scripts/deploy-e2e-headlamp.sh @@ -32,6 +32,14 @@ if [ ! -d "$DIST_DIR" ]; then exit 1 fi +# --- Preflight: verify RBAC before touching the cluster --- +echo "Checking RBAC permissions in namespace '${E2E_NAMESPACE}'..." +if ! kubectl auth can-i delete configmaps -n "$E2E_NAMESPACE" --quiet 2>/dev/null; then + echo "ERROR: Missing RBAC — cannot delete configmaps in namespace '${E2E_NAMESPACE}'." >&2 + echo " Apply RBAC first: kubectl apply -f deployment/e2e-ci-runner-rbac.yaml" >&2 + exit 1 +fi + echo "=== E2E Headlamp Deployment ===" echo " Image: ghcr.io/headlamp-k8s/headlamp:${HEADLAMP_VERSION}" echo " Namespace: $E2E_NAMESPACE"