592 lines
16 KiB
Markdown
592 lines
16 KiB
Markdown
# AGENT.md
|
|
|
|
## Project
|
|
|
|
**Name:** custom-gitea-runner
|
|
|
|
**Purpose:**
|
|
Build a self-owned, versioned, Docker-first Gitea Actions runner platform that avoids opaque upstream behavior, is easy to debug, and is safe to operate on Unraid and general Linux hosts. This project should produce a maintainable runner image, startup logic, configuration templates, and documentation that make runner behavior explicit and reproducible.
|
|
|
|
This project exists because the stock/self-hosted runner path introduced hard-to-diagnose issues around nested containers, action runtime dependencies, container image behavior, and host/runtime compatibility. The replacement should favor observability, deterministic builds, explicit tooling, and low-surprise operations.
|
|
|
|
---
|
|
|
|
## Mission
|
|
|
|
Create a production-ready custom Gitea runner solution that:
|
|
|
|
- Runs reliably in Docker on Unraid and standard Linux hosts.
|
|
- Supports JavaScript-based actions by shipping the required runtime dependencies explicitly.
|
|
- Supports Docker build/push workflows without hidden image assumptions.
|
|
- Uses pinned versions wherever practical.
|
|
- Separates image build concerns from runtime registration/config concerns.
|
|
- Makes debugging first-class through logs, health checks, self-tests, and clear failure modes.
|
|
- Keeps all project knowledge versioned in-repo through AGENT.md, README.md, ROADMAP.md, CHANGELOG.md, and example configs.
|
|
|
|
---
|
|
|
|
## Product goals
|
|
|
|
1. Build a custom Docker image for a Gitea-compatible runner.
|
|
2. Provide an entrypoint/bootstrap script that prepares the runtime deterministically.
|
|
3. Support runner registration through environment variables and/or mounted config.
|
|
4. Support common CI workloads for the target environment: checkout, Node-based actions, Docker login, Docker build, Docker push, shell scripts, and future extensibility for additional tooling.
|
|
5. Provide a clean path for image tagging, publishing, rollback, and host deployment.
|
|
6. Minimize dependence on mutable upstream defaults like `latest`, floating action images, or runtime package installs during startup.
|
|
7. Make the image and scripts inspectable, testable, and easy to extend.
|
|
|
|
---
|
|
|
|
## Non-goals
|
|
|
|
- Do not build a full replacement for the Gitea server.
|
|
- Do not invent a proprietary CI protocol if standard Gitea runner registration is sufficient.
|
|
- Do not optimize first for Kubernetes.
|
|
- Do not assume multi-tenant hostile workloads at v1; this is a controlled self-hosted environment.
|
|
- Do not rely on runtime `apk add` or ad hoc container mutation as a permanent solution.
|
|
|
|
---
|
|
|
|
## Development philosophy
|
|
|
|
Treat this like an internal platform product, not a one-off container hack.
|
|
|
|
Principles:
|
|
|
|
- **Version everything.** Image versions, dependency versions, docs, sample configs, and release notes should all be explicit.
|
|
- **Document while building.** If behavior changes, update README.md and ROADMAP.md in the same workstream.
|
|
- **Prefer deterministic builds.** Install dependencies at image build time, not container startup.
|
|
- **Prefer explicit over magical.** If Node, Git, Docker CLI, certificates, or helper binaries are required, declare and verify them.
|
|
- **Design for diagnosis.** Every major startup step should emit useful logs.
|
|
- **Keep the bootstrap thin.** Complex logic should live in versioned scripts/modules, not giant one-line container commands.
|
|
- **Bias for maintainability.** Small, composable scripts beat clever entrypoints.
|
|
|
|
---
|
|
|
|
## User and environment assumptions
|
|
|
|
Primary operator profile:
|
|
|
|
- Advanced technical operator.
|
|
- Comfortable with Docker, Unraid, Node.js/TypeScript, Bash, and self-hosted infrastructure.
|
|
- Prefers documented roadmaps, structured project files, and reusable internal tooling.
|
|
|
|
Primary target environment:
|
|
|
|
- Unraid Docker host first.
|
|
- Standard Linux Docker host second.
|
|
- Gitea instance is self-hosted.
|
|
- Registry may be self-hosted Gitea Container Registry.
|
|
- Project repositories are hosted in Gitea.
|
|
|
|
---
|
|
|
|
## Required deliverables
|
|
|
|
The agent should scaffold and maintain at minimum:
|
|
|
|
```text
|
|
custom-gitea-runner/
|
|
├── AGENT.md
|
|
├── README.md
|
|
├── ROADMAP.md
|
|
├── CHANGELOG.md
|
|
├── LICENSE
|
|
├── .gitignore
|
|
├── .env.example
|
|
├── docker/
|
|
│ ├── runner/
|
|
│ │ ├── Dockerfile
|
|
│ │ ├── docker-entrypoint.sh
|
|
│ │ ├── healthcheck.sh
|
|
│ │ └── smoke-test.sh
|
|
│ └── compose/
|
|
│ ├── docker-compose.example.yml
|
|
│ └── unraid-template-notes.md
|
|
├── config/
|
|
│ ├── runner.example.yaml
|
|
│ ├── labels.example.env
|
|
│ └── trusted-ca/
|
|
├── scripts/
|
|
│ ├── register-runner.sh
|
|
│ ├── deregister-runner.sh
|
|
│ ├── verify-runtime.sh
|
|
│ ├── build-image.sh
|
|
│ ├── publish-image.sh
|
|
│ └── test-local-runner.sh
|
|
├── docs/
|
|
│ ├── architecture.md
|
|
│ ├── operations.md
|
|
│ ├── troubleshooting.md
|
|
│ ├── unraid.md
|
|
│ └── decisions/
|
|
│ └── 0001-base-image.md
|
|
├── test/
|
|
│ ├── fixtures/
|
|
│ ├── sample-workflows/
|
|
│ └── smoke/
|
|
└── src/
|
|
└── optional/
|
|
```
|
|
|
|
Notes:
|
|
|
|
- `src/` is optional unless the project grows into a TypeScript control plane or helper CLI.
|
|
- If a CLI/helper app is introduced, prefer TypeScript for maintainability and consistency with the project stack.
|
|
|
|
---
|
|
|
|
## Recommended architecture
|
|
|
|
### Baseline architecture
|
|
|
|
Start with a Docker image that wraps or embeds the official `act_runner` binary but controls:
|
|
|
|
- base image selection,
|
|
- runtime package set,
|
|
- startup/registration flow,
|
|
- mounted config handling,
|
|
- Docker socket strategy,
|
|
- health checks,
|
|
- and diagnostics.
|
|
|
|
### Preferred v1 design
|
|
|
|
- Debian or Ubuntu slim base image, not an ultra-minimal image that requires runtime mutation.
|
|
- Install at build time:
|
|
- ca-certificates
|
|
- bash
|
|
- curl
|
|
- git
|
|
- jq
|
|
- nodejs
|
|
- npm
|
|
- docker CLI
|
|
- tini
|
|
- timezone data
|
|
- Copy in a pinned `act_runner` binary or install from a pinned release artifact.
|
|
- Use `tini` as PID 1.
|
|
- Use a real multi-line `docker-entrypoint.sh`.
|
|
- Validate runtime prerequisites before daemon start.
|
|
- Prefer mounted `/var/run/docker.sock` for v1 if the host is trusted and this matches the deployment model.
|
|
- Expose health check status through a lightweight script.
|
|
|
|
### Why this design
|
|
|
|
This directly addresses the observed failure class:
|
|
|
|
- runtime packages missing in the runner image,
|
|
- overreliance on upstream defaults,
|
|
- brittle nested-container behavior,
|
|
- and low observability when setup fails.
|
|
|
|
---
|
|
|
|
## Runner behavior requirements
|
|
|
|
The custom runner must:
|
|
|
|
1. Start deterministically with a documented set of environment variables.
|
|
2. Fail fast when required inputs are missing.
|
|
3. Verify and log the presence of key tools:
|
|
- `git`
|
|
- `node`
|
|
- `npm`
|
|
- `docker`
|
|
- `act_runner`
|
|
4. Emit version information at startup.
|
|
5. Support both pre-registered config files and first-boot registration flows.
|
|
6. Avoid mutating the filesystem in surprising ways at runtime beyond known writable paths.
|
|
7. Support Docker-based build/push jobs cleanly.
|
|
8. Provide optional label mapping guidance for common targets like `ubuntu-latest`.
|
|
9. Make workspace and temp directories explicit and configurable.
|
|
10. Provide a smoke-test path that validates the runner image before production use.
|
|
|
|
---
|
|
|
|
## Configuration model
|
|
|
|
Support two modes.
|
|
|
|
### Mode A: Pre-generated config
|
|
|
|
Operator mounts:
|
|
|
|
- runner config yaml
|
|
- optional registration metadata
|
|
- optional CA bundle
|
|
|
|
This is the preferred stable production mode.
|
|
|
|
### Mode B: Bootstrap registration
|
|
|
|
Operator provides env vars such as:
|
|
|
|
- `GITEA_INSTANCE_URL`
|
|
- `GITEA_RUNNER_TOKEN`
|
|
- `GITEA_RUNNER_NAME`
|
|
- `GITEA_RUNNER_LABELS`
|
|
- `GITEA_RUNNER_WORKDIR`
|
|
- `GITEA_RUNNER_CONFIG_PATH`
|
|
|
|
Entrypoint performs:
|
|
|
|
1. validation,
|
|
2. one-time registration if config absent,
|
|
3. daemon startup.
|
|
|
|
The agent should design this so reboots are idempotent.
|
|
|
|
---
|
|
|
|
## Docker and security model
|
|
|
|
### v1 security posture
|
|
|
|
This runner is intended for a trusted, self-hosted environment. Simplicity and reliability are more important than extreme sandbox isolation in v1.
|
|
|
|
### v1 approach
|
|
|
|
- Support Docker socket mount for build/push workloads.
|
|
- Document the trust implications clearly.
|
|
- Keep the runner container itself as minimal and explicit as possible.
|
|
- Avoid privileged mode unless a specific feature requires it.
|
|
- Prefer read-only mounts where practical except for config/work directories.
|
|
- Run as non-root where feasible, but do not force complexity if Docker socket access or upstream tooling makes that unrealistic in v1.
|
|
|
|
### Future hardening track
|
|
|
|
Document as roadmap items:
|
|
|
|
- rootless variants,
|
|
- DinD variant,
|
|
- dedicated buildkit integration,
|
|
- ephemeral one-job runners,
|
|
- restricted labels by repo or org,
|
|
- network isolation strategies.
|
|
|
|
---
|
|
|
|
## Documentation requirements
|
|
|
|
The agent must keep these files current as the project evolves.
|
|
|
|
### README.md
|
|
|
|
Should include:
|
|
|
|
- project purpose,
|
|
- why this exists,
|
|
- supported features,
|
|
- architecture overview,
|
|
- quick start,
|
|
- environment variables,
|
|
- Docker compose example,
|
|
- Unraid deployment notes,
|
|
- sample workflow guidance,
|
|
- troubleshooting links,
|
|
- versioning and release model.
|
|
|
|
### ROADMAP.md
|
|
|
|
Must track phases, status, and next actions.
|
|
|
|
Recommended sections:
|
|
|
|
- Phase 0: Research and design
|
|
- Phase 1: Base image and bootstrap
|
|
- Phase 2: Registration/config flows
|
|
- Phase 3: Docker workflow support
|
|
- Phase 4: Test harness and smoke validation
|
|
- Phase 5: Unraid packaging and docs
|
|
- Phase 6: Hardening and enhancements
|
|
|
|
### CHANGELOG.md
|
|
|
|
Use Keep a Changelog style:
|
|
|
|
- Added
|
|
- Changed
|
|
- Fixed
|
|
- Removed
|
|
|
|
### docs/troubleshooting.md
|
|
|
|
Must be practical and symptom-driven.
|
|
|
|
Include sections for issues like:
|
|
|
|
- runner not registering,
|
|
- `node` not found,
|
|
- Docker socket permission errors,
|
|
- workflow checkout failures,
|
|
- registry login failures,
|
|
- container job image issues,
|
|
- CA/certificate trust issues,
|
|
- Unraid-specific gotchas.
|
|
|
|
---
|
|
|
|
## Functional scope for v1
|
|
|
|
### Must support
|
|
|
|
- `actions/checkout`
|
|
- `docker/login-action`
|
|
- `docker build`
|
|
- `docker push`
|
|
- shell-based build scripts
|
|
- Gitea registry auth patterns
|
|
- branch/tag based image builds
|
|
|
|
### Nice to support in v1 if straightforward
|
|
|
|
- `buildx`
|
|
- cache mounts
|
|
- custom CA installation
|
|
- repo/org label strategies
|
|
- self-test action workflow
|
|
|
|
### Defer unless easy
|
|
|
|
- autoscaling
|
|
- UI dashboard
|
|
- metrics exporter
|
|
- multi-runner orchestrator
|
|
- web control plane
|
|
|
|
---
|
|
|
|
## Testing strategy
|
|
|
|
The project should include real validation, not just build success.
|
|
|
|
### Required tests
|
|
|
|
1. **Image build test**
|
|
- Docker image builds successfully from scratch.
|
|
|
|
2. **Runtime verification test**
|
|
- Container starts and confirms key binaries exist.
|
|
|
|
3. **Registration smoke test**
|
|
- Runner can register against a test Gitea instance or mocked flow.
|
|
|
|
4. **Workflow smoke tests**
|
|
- checkout-only workflow,
|
|
- Node-based action workflow,
|
|
- Docker login workflow,
|
|
- Docker build/push workflow against a test registry.
|
|
|
|
5. **Regression tests**
|
|
- specifically capture previously observed failure classes around missing Node and fragile container behavior.
|
|
|
|
### Testing philosophy
|
|
|
|
Every bug that costs real debugging time should become:
|
|
|
|
- a documented issue,
|
|
- a troubleshooting entry,
|
|
- and ideally a regression test.
|
|
|
|
---
|
|
|
|
## Logging and observability
|
|
|
|
Startup logs should clearly print:
|
|
|
|
- image version,
|
|
- git commit if embedded,
|
|
- act_runner version,
|
|
- node version,
|
|
- docker version,
|
|
- registration mode,
|
|
- config path,
|
|
- work directory,
|
|
- labels,
|
|
- target Gitea URL.
|
|
|
|
Do not log secrets.
|
|
|
|
Health check should verify at minimum:
|
|
|
|
- runner process exists,
|
|
- config is present,
|
|
- Docker socket availability if required,
|
|
- core binaries exist.
|
|
|
|
Optional future enhancements:
|
|
|
|
- structured JSON logs,
|
|
- `/healthz` sidecar or helper,
|
|
- metrics export.
|
|
|
|
---
|
|
|
|
## Versioning and release policy
|
|
|
|
Use semantic-ish tags for the custom image.
|
|
|
|
Recommended tagging:
|
|
|
|
- `v0.1.0`
|
|
- `v0.1.1`
|
|
- `v0.2.0`
|
|
- `latest` only as a convenience alias to the newest stable release
|
|
|
|
Rules:
|
|
|
|
- Never deploy unpinned `latest` in production docs as the primary recommendation.
|
|
- Every release should map to a Git tag and CHANGELOG entry.
|
|
- Embed image metadata labels such as version, vcs ref, build date, and source URL.
|
|
|
|
---
|
|
|
|
## Agent operating instructions
|
|
|
|
When working on this project, the agent must:
|
|
|
|
1. Update `ROADMAP.md` when a phase changes or a major task is added/closed.
|
|
2. Update `README.md` when usage, env vars, image behavior, or deployment steps change.
|
|
3. Update `CHANGELOG.md` for user-visible changes.
|
|
4. Prefer small, reviewable commits/changesets.
|
|
5. Ask for clarification before making irreversible architecture choices when multiple valid paths exist.
|
|
6. Keep scripts POSIX/Bash-friendly and easy to audit.
|
|
7. Avoid hidden runtime package installation unless explicitly implementing a temporary debug path.
|
|
8. Prefer pinned versions in Dockerfile and examples.
|
|
9. Add troubleshooting notes whenever a new failure mode is discovered.
|
|
10. Preserve portability between Unraid and standard Linux where reasonable.
|
|
|
|
---
|
|
|
|
## Implementation preferences
|
|
|
|
Preferred languages and tooling:
|
|
|
|
- Bash for bootstrap and operational scripts.
|
|
- Dockerfile for image definition.
|
|
- TypeScript only if a helper CLI/control plane becomes necessary.
|
|
- Markdown for all project documentation.
|
|
- Git-based versioning hosted in Gitea.
|
|
|
|
Preferred project style:
|
|
|
|
- Modular files.
|
|
- Clean naming.
|
|
- Self-explanatory scripts.
|
|
- No giant inline command strings in container templates.
|
|
- Examples should be copy-paste friendly.
|
|
|
|
---
|
|
|
|
## Suggested first milestones
|
|
|
|
### Milestone 1: Foundation
|
|
|
|
- Initialize repository structure.
|
|
- Write README.md skeleton.
|
|
- Write ROADMAP.md.
|
|
- Write Dockerfile using pinned base image.
|
|
- Write entrypoint with startup validation.
|
|
- Add healthcheck script.
|
|
|
|
### Milestone 2: Registration and config
|
|
|
|
- Add env-driven bootstrap registration flow.
|
|
- Add mounted-config mode.
|
|
- Add `.env.example`.
|
|
- Add example runner config.
|
|
|
|
### Milestone 3: CI workload support
|
|
|
|
- Ensure Node, Git, Docker CLI, CA certs all present.
|
|
- Validate `actions/checkout` and `docker/login-action` support.
|
|
- Build sample workflow fixtures.
|
|
|
|
### Milestone 4: Unraid packaging
|
|
|
|
- Create compose example.
|
|
- Document Unraid template fields and recommended mounts.
|
|
- Add upgrade and rollback instructions.
|
|
|
|
### Milestone 5: Quality and regression safety
|
|
|
|
- Add smoke-test script.
|
|
- Add local test harness.
|
|
- Add troubleshooting guide.
|
|
- Capture prior bug classes as regression cases.
|
|
|
|
---
|
|
|
|
## Decision log expectations
|
|
|
|
Create ADR-style notes under `docs/decisions/` for major decisions such as:
|
|
|
|
- base image choice,
|
|
- root vs non-root default,
|
|
- socket mount vs DinD,
|
|
- bootstrap registration design,
|
|
- bundled tools list,
|
|
- release strategy.
|
|
|
|
Each decision note should include:
|
|
|
|
- context,
|
|
- decision,
|
|
- consequences,
|
|
- alternatives considered.
|
|
|
|
---
|
|
|
|
## Success criteria
|
|
|
|
This project is successful when:
|
|
|
|
- a fresh operator can build and run the image with documented steps,
|
|
- the runner reliably executes checkout + Docker login + build + push workflows,
|
|
- Node-based actions work without runtime hacks,
|
|
- failures are diagnosable from logs and docs,
|
|
- upgrades are explicit and reversible,
|
|
- and the entire runner behavior is version-controlled and understandable.
|
|
|
|
---
|
|
|
|
## Open questions for early clarification
|
|
|
|
Before heavy implementation, clarify:
|
|
|
|
1. Should v1 wrap the official `act_runner` binary or fork/build from source?
|
|
2. Is the preferred base image Debian slim or Ubuntu minimal?
|
|
3. Should v1 default to socket mount only, or support both socket mount and DinD variants from day one?
|
|
4. Should the repository include an Unraid XML/template artifact, or just docs plus compose examples?
|
|
5. Should the first release include a small helper CLI for registration/testing, or keep everything shell-only?
|
|
6. Should runner labels be opinionated by default, or minimal and operator-supplied?
|
|
7. Should custom CA trust be a first-class feature in v1?
|
|
|
|
If these are unanswered, the agent should pause and ask before overcommitting to a direction.
|
|
|
|
---
|
|
|
|
## Build order
|
|
|
|
When starting implementation, follow this order:
|
|
|
|
1. AGENT.md
|
|
2. README.md
|
|
3. ROADMAP.md
|
|
4. Dockerfile
|
|
5. entrypoint/bootstrap scripts
|
|
6. healthcheck/smoke tests
|
|
7. config examples
|
|
8. compose/unraid examples
|
|
9. troubleshooting docs
|
|
10. regression fixtures/tests
|
|
|
|
---
|
|
|
|
## Final instruction
|
|
|
|
Optimize for reliability, debuggability, and maintainability over cleverness.
|
|
|
|
This project should feel like a stable internal platform component that the operator can trust, inspect, extend, and version for years.
|