rig/docs/templates/ci-box/creds.md

14 lines
986 B
Markdown
Raw Permalink Normal View History

feat: Forgejo-native CI — a ci-box tenant and a forgejo-runner family rig's CI story was GitHub-shaped end to end. This makes it work against a self-hosted Forgejo, in three pieces. The registry fetch becomes forge-aware. templates_resolve hardcoded three github.com archive URLs; RIG_TEMPLATES_HOST now selects the grammar, because the forges genuinely differ — GitHub serves refs/tags, refs/heads and bare paths, Forgejo serves exactly one, and emitting the other two there would mean two guaranteed 404s per fetch and a failure message listing URLs that never could have worked. Measured against forgejo.heavyduty.builders, not inferred. The default stays GitHub, so every existing caller is unchanged. install.sh's snapshot reads the same variable through a byte-identical copy of the builder, diffed by the tests: a snapshot cached from a forge converge would never fetch from is worse than no snapshot, and the pin-in-the-name staleness guard cannot catch a wrong-ORIGIN snapshot, only an old one. ci-box is a tenant, not a machine role. The topology is a fleet machine hosting boxes, one of which runs CI — a '-box' guest by rig's own family rule. That also deletes the docker-in-docker layer the usual setup needs: bootstrap-tenant.sh already installs Docker and adds the tenant user to the group, and the isolation a privileged dind sidecar buys is already paid for by a box that is network-isolated, inbound-less and disposable. rig runner install refuses Docker for good reason — it converges a MACHINE, where the blast radius is the machine. Here it is a guest that gets thrown away. rig forgejo-runner is a new family beside rig runner, which is untouched. Forgejo registers against an INSTANCE and the token carries the scope, so there is no --repo to converge toward and nothing to compare; folding that into one command would make every guard bimodal to share a flag name while the contract underneath differs. assert_runner_instance asks the same trust-boundary question about the axis Forgejo actually has. There is no repoint and no --local, and both absences are explained where an operator arriving from the GitHub sibling will hit them. Forgejo's .runner holds the runner's own long-lived token, unlike GitHub's, so it is installed 0600 and the mode is re-asserted on every converge — a mode that drifted leaks the secret silently, since nothing fails and the runner keeps working. status reports it and never prints the token. Both downloads verify the published .sha256 before installing: this binary lands as root and is executed by a systemd unit. bootstrap --undo learns the guard for the same hazard on the other forge, and it matters more here — Forgejo has no deregistration endpoint, so the ghost it would strand has to be deleted by hand. Known prerequisite, documented rather than assumed: the fetch is unauthenticated by contract, and a Forgejo with REQUIRE_SIGNIN_VIEW=true answers 404 for repos it reports as public. Hosting a registry there needs FORGEJO__service__REQUIRE_SIGNIN_VIEW=false. The refusal names that case, because it is indistinguishable from a wrong ref. forgejo#109 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 20:40:54 +00:00
- **Creds-free by default.** The box starts with no Forgejo credentials and no
git credentials. The runner binary is installed but **not registered**:
fix: the ci-box token guidance says what a Forgejo token actually is Round finding from @codex-reviewer-andresmgsl, elevated to blocking by @grok-reviewer-andresmgsl and @kimi-reviewer-andresmgsl. Unanimous, and right. creds.md called the registration token "short-lived" and said it was "consumed at registration". Both are GitHub's facts, copied across the forge boundary with the rest of the sibling's shape. Forgejo's primary source, read rather than inferred: models/actions/runner_token.go — ActionRunnerToken has NO expiry field. Only IsActive, Created, Updated. NewRunnerToken flips IsActive false on prior tokens at the same scope and only there, so a token dies when somebody mints its replacement, never on a clock. routers/api/actions/runner/runner.go — Register reads the token, refuses it when !IsActive ("please use the latest one"), and returns WITHOUT setting IsActive = false. Registration does not spend it. One token registers as many runners as it is shown to. So it is long-lived and reusable — the precise opposite of the adjective, and GitHub's really does expire in about an hour, which is why runner-install.sh is correct to use it. This is not a wording nit because of where the wording lives. creds.md is spliced into the ci-box's own CONTEXT.md: it is the paragraph an agent INSIDE the box reads about its own credentials. Telling that reader the token self-expires is telling it a leaked one stops mattering on its own, while it is still registering runners. Pinned, not merely fixed, per codex's ask — the phrase arrived by copying from the GitHub sibling, so the same copy can bring it back. Four rows: absence from both files, and presence of the true claim, so the pin cannot be satisfied by deleting the sentence instead of correcting it. The first draft of the CIBOX pin was a phrase match and passed against the exact text it was written to catch — the old wording wrapped across two comment lines. It is a plain absence check now, and the file explains the ban without spelling the word. Mutation-checked: all four go red against the old wording, green after.
2026-07-28 16:18:33 +00:00
registration needs a token the operator mints in Forgejo (Site
Administration, org, or repo → Actions → Runners) and hands to
`sudo rig forgejo-runner install --instance <url>`. rig never writes that
token to disk — but it does **not expire, and registering does not spend
it**. A Forgejo registration token stays valid until somebody mints a
replacement at that same scope, and it will register as many runners as it is
shown to. Treat a leaked one as live until it has been replaced. (GitHub's
equivalent expires in about an hour; do not carry that habit across.) After
registration the runner's own credential lives in `~/forgejo-runner/.runner`,
mode 0600 — never copy it, print it, or commit it. Secrets that CI jobs need
belong in Forgejo's repo or org secrets, injected per job, not on this box.