# ROADMAP.md ## Project **Name:** custom-gitea-runner **Status:** Planning / bootstrap **Objective:** Deliver a self-owned, versioned, Docker-first Gitea runner platform that is reliable on Unraid and Linux, easy to debug, and explicitly documented from image build through runtime operations. --- ## Guiding outcomes The project is considered successful when it can: - run as a pinned Docker image, - execute checkout + Node-based + Docker build/push workflows reliably, - register and restart predictably, - surface actionable logs during failure, - and be upgraded or rolled back cleanly. --- ## Project phases ## Phase 0 — Research and design **Status:** Complete ### Goals - Define architecture, scope, and first-release constraints. - Capture prior failure modes as design inputs. - Establish documentation and decision-tracking structure. ### Tasks - [x] Write `AGENT.md` - [x] Write `README.md` - [x] Write `ROADMAP.md` - [x] Create `CHANGELOG.md` - [x] Create `.env.example` - [x] Create ADR template under `docs/decisions/` - [x] Write `docs/architecture.md` - [x] Decide base image strategy - [x] Decide socket-mount vs DinD position for v1 - [x] Decide registration mode defaults ### Exit criteria - Scope is documented. - Core repo structure is defined. - Major open decisions are listed. - First implementation sequence is agreed. --- ## Phase 1 — Base image and bootstrap **Status:** Complete ### Goals - Produce the first buildable runner image. - Eliminate runtime package mutation. - Establish deterministic startup behavior. ### Tasks - [x] Create `docker/runner/Dockerfile` - [x] Pin base image tag - [x] Pin `act_runner` source/version - [x] Install required dependencies at build time: - [x] bash - [x] curl - [x] git - [x] jq - [x] nodejs - [x] npm - [x] docker CLI - [x] ca-certificates - [x] tini - [x] tzdata - [x] Create `docker/runner/docker-entrypoint.sh` - [x] Create `docker/runner/healthcheck.sh` - [x] Add image metadata labels - [x] Verify startup prints tool versions ### Notes - First successful build: `custom-gitea-runner:v0.1.0` (act_runner v0.2.11, node v20.20.2, npm 10.8.2, git 2.34.1, docker CLI 29.6.1). - Runtime smoke test passes 17/17 via `./scripts/verify-runtime.sh`. ### Exit criteria - Image builds locally. - Container starts cleanly. - `node`, `git`, `docker`, and `act_runner` are all present. - Healthcheck script returns useful status. --- ## Phase 2 — Registration and config flows **Status:** Complete ### Goals - Support both mounted-config and env-driven registration. - Make bootstrap idempotent. - Ensure config persistence survives restarts. ### Tasks - [x] Create `config/runner.example.yaml` - [x] Create `config/labels.example.env` - [x] Create `scripts/register-runner.sh` - [x] Create `scripts/deregister-runner.sh` - [x] Add config path validation - [x] Add first-boot registration flow - [x] Add re-run safe bootstrap logic - [x] Document required environment variables - [x] Validate restart behavior with existing config ### Exit criteria - Runner can register successfully. - Existing config is reused without duplicate registration. - Missing configuration fails fast with clear logs. ### Notes - Validated live against `git.alwisp.com` (Gitea 1.26.4): runner `forgerunner-01` registered as instance-level runner (id 5), came online and healthy, and a container restart reused the existing config with no duplicate registration. - Registration token obtained via `POST /api/v1/admin/actions/runners/registration-token`; deregistration via `DELETE /api/v1/admin/actions/runners/{id}` (act_runner has no unregister command). --- ## Phase 3 — Docker workflow support **Status:** Complete ### Goals - Prove the runner can handle real Docker-centric CI workloads. - Ensure JavaScript-based actions work out of the box. ### Tasks - [x] Validate `actions/checkout` - [x] Validate Node-based action runtime - [x] Validate `docker/login-action` - [x] Validate `docker build` - [x] Validate `docker push` - [x] Add support notes for self-hosted Gitea Container Registry - [x] Validate mounted Docker socket usage - [x] Document permission expectations for `/var/run/docker.sock` - [ ] Evaluate `buildx` as optional enhancement (deferred to Phase 6) ### Notes - `.gitea/workflows/ci-smoke.yml` (run 110, `success`) validated on the live runner via the `host` label: `actions/checkout@v4`, bundled node/npm/git/docker versions, and Docker-socket access (`docker info`) all pass. - Image published: `registry.alwisp.com/jason/custom-gitea-runner:v0.1.0` + `:latest` (login via the jason Gitea account succeeded; push validated the registry round-trip). - `docker/login-action` + `docker build` + `docker push` **from a workflow** validated: `.gitea/workflows/docker-push.yml` (run 114, `success`) logged in to `registry.alwisp.com`, built, and pushed a test image; the artifact was confirmed in the registry then cleaned up. - Repo Action secrets `REGISTRY_USER`/`REGISTRY_TOKEN` are set (currently the admin API token — replace with a dedicated `write:package`-scoped token when convenient). ### Exit criteria - Standard Docker build/push workflows pass. - No runtime install hacks are needed. - Node-based actions work on first boot. --- ## Phase 4 — Test harness and smoke validation **Status:** Planned ### Goals - Convert operational pain into repeatable tests. - Establish confidence before release. ### Tasks - [x] Create `docker/runner/smoke-test.sh` - [x] Create `scripts/verify-runtime.sh` - [x] Create `scripts/test-local-runner.sh` - [x] Add `test/sample-workflows/checkout.yml` - [x] Add `test/sample-workflows/node-action.yml` - [x] Add `test/sample-workflows/docker-login.yml` - [x] Add `test/sample-workflows/docker-build-push.yml` - [ ] Add regression test cases for: - [ ] missing `node` - [ ] broken Docker socket access - [ ] invalid registration config - [ ] startup tool validation failures - [ ] Document how to run smoke tests locally ### Exit criteria - Smoke tests are runnable by an operator. - Known painful regressions are covered. - Runtime validation is part of the normal release flow. --- ## Phase 5 — Unraid packaging and docs **Status:** Planned ### Goals - Make deployment smooth in the real target environment. - Provide operational documentation that matches actual host usage. ### Tasks - [ ] Create `docker/compose/docker-compose.example.yml` - [ ] Create `docker/compose/unraid-template-notes.md` - [ ] Write `docs/unraid.md` - [ ] Write `docs/operations.md` - [ ] Write `docs/troubleshooting.md` - [ ] Document update procedure - [ ] Document rollback procedure - [ ] Document appdata path recommendations - [ ] Document Docker socket trust model - [ ] Optionally create Unraid XML/template artifact ### Exit criteria - Operator can deploy from docs alone. - Unraid-specific steps are explicit. - Upgrade and rollback are documented and tested. --- ## Phase 6 — Hardening and enhancements **Status:** Backlog ### Goals - Expand safety and flexibility after the baseline runner is stable. ### Candidate enhancements - [ ] Rootless variant - [ ] DinD variant - [ ] Dedicated BuildKit support - [ ] Ephemeral single-job runner mode - [ ] Structured JSON logging - [ ] Metrics/exporter support - [ ] Label policy controls - [ ] Custom CA bootstrap helpers - [ ] Small helper CLI in TypeScript - [ ] Multi-runner orchestration concepts ### Exit criteria - Enhancements are prioritized based on real operational need. - Stability is not regressed by added flexibility. --- ## Immediate next actions ### Next 10 actions 1. Create `CHANGELOG.md` 2. Create `.env.example` 3. Scaffold repo directories 4. Write `docs/architecture.md` 5. Write first ADR: base image choice 6. Create initial `Dockerfile` 7. Create `docker-entrypoint.sh` 8. Create `healthcheck.sh` 9. Build first local image 10. Verify runtime toolchain inside container --- ## Risks and watch items ### Technical risks - Upstream `act_runner` behavior may still impose constraints even with a custom wrapper image. - Docker socket usage is convenient but increases host trust exposure. - Self-registration flows can become brittle if not made idempotent. - Docker build/push success does not guarantee all third-party actions behave as expected. ### Process risks - Letting docs lag implementation will erode the value of the project quickly. - Overengineering v1 will delay a usable baseline. - Supporting too many runtime modes too early may reduce stability. --- ## Decision log to create Create ADRs for: - [ ] Base image selection - [ ] Runner binary acquisition strategy - [ ] Runtime user model - [ ] Docker socket vs DinD - [ ] Registration strategy - [ ] Release and tagging policy --- ## Definition of done for v0.1.0 `v0.1.0` should mean: - image builds reproducibly, - runner registers successfully, - startup validation is clear, - `actions/checkout` works, - Node-based actions work, - Docker login/build/push works, - docs cover install, operation, upgrade, rollback, and troubleshooting, - and the release is tagged and documented in `CHANGELOG.md`.