Files
2026-06-18 22:21:38 -04:00

14 KiB
Raw Permalink Blame History

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, user_setup, must_haves
phase plan type wave depends_on files_modified autonomous requirements user_setup must_haves
08-gitea-ci 01 execute 1
.gitea/workflows/runner-probe.yml
false
CI-01
CI-02
service why dashboard_config
gitea-actions-runner CI cannot run without a registered act_runner; 0 runners currently registered on git.bergerhouse.net
task location
Install + register act_runner on the Unraid host against git.bergerhouse.net, prefer Docker-executor mode (service containers require it) Unraid Community Applications → act_runner template; register with a runner-registration token from Gitea → Site Admin → Actions → Runners
service why env_vars
gitea-registry-pat Publish job (CI-02) authenticates to the Gitea container registry; GITHUB_TOKEN/GITEA_TOKEN cannot push packages
name source
GITEA_REGISTRY_PAT Gitea → Settings → Applications → Generate Token with write:package (+ read:package) scope; add as repo secret GITEA_REGISTRY_PAT
truths artifacts key_links
A runner-probe workflow runs on the gsd/phase-08-gitea-ci branch and prints Node/pnpm versions, runner mode, Docker access, action resolution, and Playwright WebKit dep installability
The probe surfaces whether the runner is Docker-executor (services: works) or host-executor (docker run fallback needed) — the answer that forks W1/W2 DB bring-up
An act_runner is registered and visible in the Gitea Actions runners list (operator action)
A GITEA_REGISTRY_PAT repo secret with write:package scope exists (operator action)
path provides contains
.gitea/workflows/runner-probe.yml Probe-only workflow answering runner unknowns P-01..P-13 runner-probe
from to via pattern
.gitea/workflows/runner-probe.yml the registered act_runner runs-on: ubuntu-latest (runner has no self-hosted label), on: push to gsd/phase-08-gitea-ci runs-on:\s*ubuntu-latest
Establish the Gitea CI foundation by (a) registering the act_runner and creating the registry PAT (operator actions), and (b) landing a probe-only workflow that answers every runner unknown BEFORE any real test/build/publish step is trusted. This is Pitfall 12 (runner-probe-first) and the critical fork in 08-RESEARCH §Runner-Probe Checklist: several downstream design choices (service containers vs docker run, action resolution, reporter override, artifact upload fork, WebKit deps) depend on the probe's answers.

Purpose: De-risk every assumption (A1A10 in 08-RESEARCH Assumptions Log) on the actual Unraid runner so Waves 12 are written against confirmed behavior, not guesses. Per D-03 the real CI lives in one ci.yml; the probe is a separate throwaway workflow on the feature branch.

Output: .gitea/workflows/runner-probe.yml, a registered runner, and a stored registry PAT.

<execution_context> @$HOME/.claude/gsd-core/workflows/execute-plan.md @$HOME/.claude/gsd-core/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/08-gitea-ci/08-CONTEXT.md @.planning/phases/08-gitea-ci/08-RESEARCH.md @.planning/research/PITFALLS.md

<artifacts_this_phase_produces>

  • .gitea/workflows/runner-probe.yml (NEW — this plan)
  • .gitea/workflows/ci.yml (NEW — Plans 02/03/04) </artifacts_this_phase_produces>
Task 1: Register act_runner + create registry PAT (operator-only) Nothing automated — these are infrastructure actions outside the repo that the executor cannot perform (08-VALIDATION Manual-Only table; CI-01/CI-02 prerequisites). 1. On the Unraid host, install/register act_runner against https://git.bergerhouse.net using a runner-registration token from Gitea → Site Admin → Actions → Runners. PREFER Docker-executor mode — service containers (the MariaDB the CI needs) only work in Docker mode (08-RESEARCH §Critical fork, Assumption A1). If only host mode is available, that is acceptable; the probe (Task 2) will detect it and Waves 12 will use the docker-run fallback. 2. Confirm the runner appears with status "idle"/online in Gitea → Site Admin → Actions → Runners. 3. In Gitea → Settings → Applications, generate a token with `write:package` (and `read:package`) scope. Add it as a repository secret named `GITEA_REGISTRY_PAT` (repo → Settings → Actions → Secrets). Do NOT paste the token anywhere in the repo. Type "runner registered" once the runner is online AND the GITEA_REGISTRY_PAT secret exists, or describe what is blocking (e.g. host-mode only). Task 2: Author the runner-probe workflow .gitea/workflows/runner-probe.yml - .planning/phases/08-gitea-ci/08-RESEARCH.md (§Runner-Probe Checklist — the P-01..P-13 table is the canonical task list; §Critical fork Docker-vs-host) - .planning/research/PITFALLS.md (Pitfall 12 runner-probe-first, Pitfall 11 MariaDB-11 healthcheck) - apps/pwa/playwright.config.ts (reporter: 'github' under CI — probe must note whether annotations render) Create `.gitea/workflows/runner-probe.yml` as a probe-only, non-destructive workflow. Trigger: `on: push` filtered to `branches: [gsd/phase-08-gitea-ci]` (runs on the current feature branch; never on main). `runs-on: self-hosted`.
The job MUST answer every check in 08-RESEARCH §Runner-Probe Checklist P-01..P-13. Implement each as a clearly-labeled step whose output is visible in the Gitea Actions log:
  - P-01 Node: `node --version` (note if not 22; then test `actions/setup-node@v4` with node-version 22 — P-08).
  - P-02 pnpm: `pnpm --version || (corepack enable pnpm && pnpm --version)`.
  - P-03 Runner mode (THE critical fork): print `cat /proc/1/cgroup | head -5`, `hostname`, and `ls -la /.dockerenv 2>&1` so the log shows whether the job runs in a Docker container (Docker-executor → services: works) or on bare host (host-executor → docker run fallback). State the conclusion explicitly in an `echo` line.
  - P-04 Docker socket: `docker info 2>&1 | head -20` and `docker ps 2>&1 | head`.
  - P-05 Service container spawn: add `services: mariadb: { image: mariadb:11, env: { MARIADB_ROOT_PASSWORD: root, MARIADB_DATABASE: familysync, MARIADB_USER: familysync, MARIADB_PASSWORD: testpass }, options: --health-cmd="healthcheck.sh --connect --innodb_initialized" --health-interval=10s --health-timeout=5s --health-retries=10 --health-start-period=30s }` to the probe job; a step runs `docker ps | grep -i maria || echo "no mariadb container visible (likely host mode)"`.
  - P-06 MariaDB reachability: try BOTH `mysql -h mariadb -P 3306 -u familysync -ptestpass -e "SELECT 1" 2>&1 | head` (Docker mode hostname) AND `mysql -h 127.0.0.1 ...` (host mode). Record which hostname resolves (do NOT fail the job if one path errors — capture both, `continue-on-error: true` on the step or `|| true`).
  - P-07 checkout: `uses: actions/checkout@v4` as the first real step; reaching subsequent steps proves it resolves.
  - P-08 setup-node: `uses: actions/setup-node@v4` with `node-version: '22'`; print resulting `node --version`.
  - P-09 cache: `uses: actions/cache@v4` with a throwaway key, wrapped `continue-on-error: true` — log whether it completes or hangs/times out (08-RESEARCH Pitfall 7).
  - P-10 Playwright WebKit deps: in `apps/pwa`, `npx playwright install --with-deps webkit chromium 2>&1 | tail -30` with `continue-on-error: true` — confirms WebKit system deps install without sudo/apt failure (A10).
  - P-11 artifact upload: write a dummy file and `uses: https://github.com/ChristopherHX/gitea-upload-artifact@v4` (NOT actions/upload-artifact@v4 — broken on Gitea per 08-RESEARCH) with `continue-on-error: true`; note whether the artifact appears in the Gitea UI.
  - P-13 short SHA: `echo "short sha = ${GITHUB_SHA:0:7}"` — confirms the D-04 tag expression produces 7 chars.
Do NOT include P-12 (docker login/push) here — defer registry login to Plan 04 to avoid exercising the PAT before the publish job is designed. Add a final summary step that echoes a one-line verdict per fork (Docker vs host mode; cache usable y/n; WebKit deps ok y/n; upload-artifact fork works y/n) so the SUMMARY can record the answers.

Keep the workflow non-destructive: no migrations, no pushes, no writes to main. All probe steps that may fail on this runner use `continue-on-error: true` or `|| true` so the probe reports findings instead of red-failing on an expected unknown.
test -f .gitea/workflows/runner-probe.yml && grep -q "runs-on: self-hosted" .gitea/workflows/runner-probe.yml && grep -q "healthcheck.sh --connect --innodb_initialized" .gitea/workflows/runner-probe.yml && grep -q "ChristopherHX/gitea-upload-artifact@v4" .gitea/workflows/runner-probe.yml && ! grep -q "actions/upload-artifact@v4" .gitea/workflows/runner-probe.yml && ! grep -q "mysqladmin" .gitea/workflows/runner-probe.yml && echo PROBE_OK runner-probe.yml exists, triggers only on the feature branch, uses `healthcheck.sh --connect --innodb_initialized` (never mysqladmin), uses the gitea-upload-artifact fork (never actions/upload-artifact@v4), and contains a step for each of P-01..P-11 + P-13. Task 3: Run the probe and record the fork answers The runner-probe workflow (Task 2), pushed to the gsd/phase-08-gitea-ci branch so the now-registered runner executes it. 1. Ensure the branch is pushed: `git push origin gsd/phase-08-gitea-ci` (this commit triggers the probe). 2. Open Gitea → repo → Actions; find the "runner-probe" workflow run. 3. Read the log and record the answers to the fork questions: - P-03: Docker-executor mode or host-executor mode? (drives Waves 12 DB bring-up) - P-05/P-06: did the MariaDB service container appear, and on which hostname (`mariadb` vs `127.0.0.1`)? - P-09: did actions/cache complete or hang? (cache optional decision) - P-10: did `playwright install --with-deps webkit` succeed? (WebKit feasibility) - P-11: did the gitea-upload-artifact fork upload successfully and appear in the UI? 4. Confirm no secret/token is printed anywhere in the probe log (the probe must not touch the PAT). Paste the fork answers (Docker vs host mode; service-container hostname; cache works y/n; WebKit deps y/n; artifact upload y/n) so the executor records them in the SUMMARY for Waves 12. Type "probe results recorded" to continue.

<threat_model>

Trust Boundaries

Boundary Description
CI workflow → self-hosted runner Untrusted-ish: workflow YAML executes on operator infra with Docker socket access
Repo secret store → workflow env PAT crosses into the job; must never echo

STRIDE Threat Register

Threat ID Category Component Disposition Mitigation Plan
T-08-01 Information Disclosure runner-probe.yml mitigate Probe NEVER references secrets.GITEA_REGISTRY_PAT or any secret; no docker login in the probe (P-12 deferred to Plan 04). Verified by checkpoint log audit.
T-08-02 Elevation of Privilege Docker socket on runner accept Docker socket access is inherent to act_runner Docker-executor mode; accepted per Gitea self-hosted docs (08-RESEARCH Security Domain).
T-08-SC Tampering gitea-upload-artifact@v4 (only new external action) mitigate [VERIFIED] in 08-RESEARCH Package Legitimacy Audit (github.com/ChristopherHX/gitea-upload-artifact) as the cited Gitea fix for the upload-artifact@v4 GHES block; pinned at @v4. All other actions are official GitHub/Docker actions. No [ASSUMED]/[SUS] packages → no install checkpoint required.

</threat_model>

- runner-probe.yml present, branch-scoped, non-destructive; passes the Task 2 grep gate. - Probe run observed in Gitea Actions; fork answers recorded in SUMMARY. - Runner online; GITEA_REGISTRY_PAT secret created (operator confirmed). - No secret material printed in any probe log line.

<success_criteria>

  • Maps to CI-01/CI-02 prerequisites and Pitfall 12: the runner environment is probed BEFORE any real test/build/publish step is designed.
  • The Docker-vs-host fork (A1) is answered; the answer is recorded so Plans 0204 pick the correct DB bring-up path.
  • Operator infra (runner + PAT) is in place. </success_criteria>
Create `.planning/phases/08-gitea-ci/08-01-SUMMARY.md` when done. MUST record the probe fork answers (runner mode, service-container hostname, cache usable y/n, WebKit deps y/n, upload-artifact fork y/n) — Plans 0204 consume them.