From a3bcd33961e375fd676f7fc73aa9e8cfdcfd39c3 Mon Sep 17 00:00:00 2001 From: vince Date: Sat, 20 Jun 2026 17:34:09 +0200 Subject: [PATCH] ci: use dedicated host deploy runner --- .forgejo/workflows/dimensionlab-website.yml | 12 +++++------- README.md | 17 ++++++++++------- apps/web/src/lib/workspace-boundary.test.ts | 5 +++-- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/.forgejo/workflows/dimensionlab-website.yml b/.forgejo/workflows/dimensionlab-website.yml index 672ab25..52cc868 100644 --- a/.forgejo/workflows/dimensionlab-website.yml +++ b/.forgejo/workflows/dimensionlab-website.yml @@ -48,10 +48,7 @@ jobs: deploy: needs: ci if: github.event_name == 'push' && github.ref == 'refs/heads/main' - runs-on: docker - container: - image: ghcr.io/catthehacker/ubuntu:act-latest - options: --security-opt label=disable + runs-on: deploy timeout-minutes: 30 steps: - name: Checkout @@ -67,13 +64,14 @@ jobs: - name: Verify Podman deployment socket run: | - timeout 15s docker version - unit="$(timeout 15s docker inspect dimensionlab-website --format '{{ index .Config.Labels "PODMAN_SYSTEMD_UNIT" }}')" + command -v podman + command -v systemctl + unit="$(timeout 15s podman inspect dimensionlab-website --format '{{ index .Config.Labels "PODMAN_SYSTEMD_UNIT" }}')" test "$unit" = "dimensionlab-website.service" - name: Deploy production website env: - DEPLOY_CONTAINER_CLI: docker + DEPLOY_CONTAINER_CLI: podman DEPLOY_EVENT_NAME: ${{ github.event_name }} DEPLOY_REF: ${{ github.ref }} DEPLOY_RESTART_STRATEGY: quadlet-container diff --git a/README.md b/README.md index 6cdcd09..a1ae19e 100644 --- a/README.md +++ b/README.md @@ -168,15 +168,18 @@ Merges to `main` run `.forgejo/workflows/dimensionlab-website.yml`. Pull requests run check, test, and build only; the deploy job is guarded to run only for `push` events on `refs/heads/main`. -The Dimension Lab runner exposes the rootless Podman socket to job containers as -`/var/run/docker.sock`. Because this host uses SELinux labeling, the runner -configuration must set: +The workflow uses two runner classes. Pull request CI runs on the containerized +`docker` runner. Production deployment runs on a separate host runner with the +`deploy:host` label so the guarded deploy script can use the user's rootless +`podman` and `systemctl --user` commands directly. ```yaml -container: - options: --security-opt label=disable +runner: + labels: + - deploy:host ``` -The deploy job also performs a socket preflight against the +The deploy job also performs a host preflight against the `dimensionlab-website.service` Podman label before it builds or restarts the -production container. +production container. Do not give the general pull request runner deployment +socket access; keep deploy privileges on the dedicated `deploy` runner. diff --git a/apps/web/src/lib/workspace-boundary.test.ts b/apps/web/src/lib/workspace-boundary.test.ts index 49f4cee..bdc978c 100644 --- a/apps/web/src/lib/workspace-boundary.test.ts +++ b/apps/web/src/lib/workspace-boundary.test.ts @@ -275,10 +275,11 @@ describe("workspace boundaries", () => { expect(workflow).toContain("bun run test"); expect(workflow).toContain("bun run build"); expect(workflow).toContain("needs: ci"); - expect(workflow).toContain("options: --security-opt label=disable"); + expect(workflow).toContain("runs-on: deploy"); expect(workflow).toContain("github.event_name == 'push'"); expect(workflow).toContain("github.ref == 'refs/heads/main'"); - expect(workflow).toContain("docker inspect dimensionlab-website"); + expect(workflow).toContain("podman inspect dimensionlab-website"); + expect(workflow).toContain("DEPLOY_CONTAINER_CLI: podman"); expect(workflow).toContain("PODMAN_SYSTEMD_UNIT"); expect(workflow).toContain("scripts/deploy-dimensionlab-website.sh"); });