refactor: redesign E2E to use custom Docker image instead of PVC/kubectl

Replace the PVC + kubectl-patch approach for E2E plugin deployment with
a custom Docker image that has the plugin pre-installed. This eliminates
all policy-violating operations:

- No PVCs in kube-system
- No kubectl exec/cp to Headlamp pods
- No deployment patching via kubectl
- No temporary pods or ConfigMap-based file transfers

The new approach builds a Headlamp image with the plugin baked in
(Dockerfile.e2e), deploys it as a dedicated instance in the headlamp-e2e
namespace via Helm, and tears it down after tests complete.

RBAC is scoped to the headlamp-e2e namespace instead of kube-system.

Note: .github/workflows/e2e.yaml still needs updating to use the new
scripts — that change is delegated to Hugh (CI/CD owner).

Closes: privilegedescalation/headlamp-polaris-plugin#72

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Gandalf the Greybeard
2026-03-20 00:33:09 +00:00
parent 4296eb97fb
commit 6189f2b983
9 changed files with 219 additions and 221 deletions
+33 -24
View File
@@ -4,7 +4,17 @@ Playwright-based smoke tests that validate the Polaris plugin against a live Hea
## CI
E2E tests run automatically in GitHub Actions on pushes to `main` and pull requests. The workflow (`.github/workflows/e2e.yaml`) uses either Authentik OIDC or token-based authentication via repository secrets.
E2E tests run automatically in GitHub Actions on pushes to `main` and pull requests. The workflow (`.github/workflows/e2e.yaml`):
1. Builds the plugin
2. Builds a custom Headlamp Docker image with the plugin pre-installed (`Dockerfile.e2e`)
3. Pushes the image to `ghcr.io/privilegedescalation/headlamp-polaris-e2e:<sha>`
4. Deploys a dedicated Headlamp instance in the `headlamp-e2e` namespace via Helm
5. Generates a ServiceAccount token for test auth
6. Runs Playwright tests against the E2E instance
7. Tears down the E2E instance
This approach avoids PVCs, kubectl exec/cp, and deployment patching. The plugin is part of the container image.
### Required GitHub Secrets
@@ -12,12 +22,10 @@ Configure these in GitHub repository settings (Settings → Secrets and variable
| Secret | Required | Description |
| -------------------- | -------- | -------------------------------------------------------------- |
| `HEADLAMP_URL` | Optional | Headlamp instance URL (defaults to `https://headlamp.animaniacs.farh.net`) |
| `AUTHENTIK_USERNAME` | OIDC | Authentik email or username for a CI user with Headlamp access |
| `AUTHENTIK_PASSWORD` | OIDC | Password for that user |
| `HEADLAMP_TOKEN` | Token | Kubernetes service account token (alternative to OIDC) |
Set either `AUTHENTIK_USERNAME` + `AUTHENTIK_PASSWORD` **or** `HEADLAMP_TOKEN`. OIDC takes priority if both are set.
Token-based auth is auto-generated by the deploy script. OIDC secrets are only needed if testing against the shared Headlamp instance.
## Running Locally
@@ -47,12 +55,12 @@ HEADLAMP_URL=http://localhost:4466 npm run e2e:headed
| Variable | Required | Default | Description |
| -------------------- | -------- | -------------------------------------- | --------------------------------------- |
| `HEADLAMP_URL` | No | `https://headlamp.animaniacs.farh.net` | Base URL of the Headlamp instance |
| `AUTHENTIK_USERNAME` | OIDC | — | Authentik email/username |
| `AUTHENTIK_PASSWORD` | OIDC | — | Authentik password |
| `HEADLAMP_TOKEN` | Token | — | Kubernetes bearer token (fallback auth) |
| `HEADLAMP_URL` | No | `https://headlamp.animaniacs.farh.net` | Base URL of the Headlamp instance |
| `AUTHENTIK_USERNAME` | OIDC | — | Authentik email/username |
| `AUTHENTIK_PASSWORD` | OIDC | — | Authentik password |
| `HEADLAMP_TOKEN` | Token | — | Kubernetes bearer token (auto-generated in CI) |
Set either `AUTHENTIK_USERNAME` + `AUTHENTIK_PASSWORD` or `HEADLAMP_TOKEN`. OIDC takes priority if both are set.
In CI, `HEADLAMP_URL` and `HEADLAMP_TOKEN` are set automatically by the deploy script. For local runs, set either OIDC credentials or a token manually.
## What the Tests Validate
@@ -249,25 +257,26 @@ test('plugin UI adapts to dark mode', async ({ page }) => {
Tests run automatically in GitHub Actions on pushes to `main` and pull requests. See `.github/workflows/e2e.yaml` for workflow configuration.
### Required Secrets
### Architecture
Configure these in GitHub repository settings (Settings → Secrets and variables → Actions):
The E2E workflow deploys a **dedicated Headlamp instance** for each test run:
- `HEADLAMP_URL` (optional): Headlamp instance URL
- `AUTHENTIK_USERNAME` + `AUTHENTIK_PASSWORD` (for OIDC auth)
- OR `HEADLAMP_TOKEN` (for token-based auth)
1. Build plugin and Docker image (`Dockerfile.e2e`)
2. Push image to `ghcr.io/privilegedescalation/headlamp-polaris-e2e:<sha>`
3. Deploy via Helm in the `headlamp-e2e` namespace (`scripts/deploy-e2e-headlamp.sh`)
4. Run Playwright tests against the E2E instance
5. Tear down (`scripts/teardown-e2e-headlamp.sh`)
### Workflow Overview
No PVCs, no kubectl exec/cp, no patching of existing deployments. The plugin is baked into the Docker image.
1. Checkout code
2. Setup Node.js 20 with npm cache
3. Install dependencies (`npm ci`)
4. Install Playwright browsers (`chromium` only)
5. Run auth setup (creates session in `e2e/.auth/state.json`)
6. Run all E2E tests
7. Upload artifacts on failure:
- `playwright-report/` - HTML test report
- `test-results/` - Screenshots, traces, videos
### Cluster Prerequisites
One-time setup by a cluster admin:
```bash
kubectl create namespace headlamp-e2e
kubectl apply -f deployment/e2e-ci-runner-rbac.yaml
```
### Manual Trigger