Enable Forgejo Actions: app.ini toggle, per-repo flag, pinned runner on the Prod Guest #3
Labels
No labels
needs-info
needs-triage
ready-for-agent
ready-for-human
wontfix
needs-info
needs-triage
ready-for-agent
ready-for-human
review/merge-ready
review/needs-fix
review/needs-human
review/needs-review
wayfinder:grilling
wayfinder:map
wayfinder:prototype
wayfinder:research
wayfinder:task
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
olympus/infra-forge#3
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem Statement
Docs publishing on the Pit homelab Forgejo is about to move to an Actions-based workflow, and later tofu/ansible CI may follow. None of that can run: Actions is disabled instance-wide (
has_actionsfalse on every repo, the Actions admin API routes absent, no runner daemon installed on the Prod Guest). Pedro needs Actions turned on — as infrastructure, provisioned and version-pinned by the forgejo Ansible role like every other part of the service — so that workflow-based work (starting with the wiki sync) can proceed, and so that a future re-provision of the Guest cannot silently turn CI off.Solution
The forgejo Ansible role provisions Forgejo Actions end to end: the instance-wide Actions toggle managed in the app.ini template, the per-repo
has_actionsflag flipped on this repo, and a pinned Forgejo runner daemon installed, registered, and running on the Prod Guest under a role-managed systemd unit. After a playbook run, pushing a.forgejo/workflows/file to any enabled repo executes it, with logs and history visible in the Forgejo UI. Nothing in the repo's application behavior changes; this is pure platform enablement, done in the same idempotent, reviewable style as the rest of the role.User Stories
uses:lines in workflows resolve without touching GitHub.has_actionsenabled on this repo, so that its.forgejo/workflows/files are picked up.User Stories (agent follow-ups, deferred)
Implementation Decisions
[actions]section: Actions enabled, default actions URL set to Forgejo's own action mirror (souses:lines resolve without GitHub). The template's existing restart notify applies the change on the next playbook run.Restart=on-failure, same pattern as the Forgejo service unit.has_actionsflag is ensured by the playbook (API call with the admin token), not left as a manual UI step.Testing Decisions
Out of Scope
Further Notes
has_actions: false; the Actions admin API routes are absent on the instance; no runner is installed. Runner latest is the v13 line (v13.1.0 published 2026-08-31).Status of the change, by PR.
#5 — enable Actions end to end (merged 2026-10-06)
What landed in the role:
[actions]section in theapp.initemplate (ENABLED = true,DEFAULT_ACTIONS_URL = https://data.forgejo.org), applied through the template's existing restart handler (stories 1–3).13.1.0next to the Forgejo pin in role defaults, downloaded checksum-first, owned by the service user under the service home (stories 6–9).forgejo-cli actions register, daemon authenticates with it. No manual UI step, no expiring token (story 10).Restart=on-failure(story 11).has_actionsensured by the playbook via the API with a per-run admin token, not a manual UI step (stories 4–5).Applied to Prod (guest 141) on 2026-10-06: app.ini
[actions]live,forgejo,forgejo-runneranddockerall active+enabled, runner registered and online (action_runnerrowguest-runner, labels[docker, ubuntu-latest],Declare200 OK).#6 — fix the per-repo flag (merged 2026-10-06)
Applying #5 on Prod revealed that the per-repo enablement step silently did nothing:
has_actionsstayedfalseand no token was ever minted. Three bugs, all fixed here and verified on a fresh PRE guest (142, destroyed and recreated):community.postgresql'slist_to_pg_arraystr()s a listnamed_arg, so['pit/infra-forge']was sent as the literal{'pit/infra-forge'}whose element is the single-quoted 17-char string — never equal to the slug. Passed as a scalar and split in SQL instead.ansible-has-actions-*rows after a run.Also added: an assertion that fails fast if a repo slug contains the list separator (so a malformed slug can't reproduce the same silent skip), and pinned the separator in role defaults.
PRE evidence: full role run green (
ok=29 changed=22 failed=0),has_actionsflipsFalse→Truevia the API, second runchanged=0(idempotent).Still open before this issue can close
has_actions: falseforpit/infra-forge(the type-10repo_unitrow is absent) — the fix is inmainbut not applied. Needs one playbook run againstinventories/prod/hosts, with a PBS snapshot of guest 141 first (convention 3).action_runcount is 0 and there is no.forgejo/workflows/file in the repo. The closing criterion — "push a trivial workflow to the enabled repo and observe a green run with logs in the UI" — must be observed once on Prod after the re-run.Closing evidence — Actions works end to end on Prod
Prod applied. One playbook run against
inventories/prod/hostsafter a snapshot of guest 141:ok=30 changed=3 failed=0. The §6 block executed for the first time on Prod — guard matched, transient token minted,PATCH has_actions: true, token deleted. Verified on the guest: type-10repo_unitrow now present forpit/infra-forge(has_actions: true), 0 leftoveransible-has-actions-*tokens,forgejoandforgejo-runnerboth active. Second run:ok=26 changed=0(idempotent, story 12).The definitive integration check (Testing Decisions). Pushed a trivial
.forgejo/workflows/actions-smoke.ymlto a throwaway branch on Prod and observed the run:action_runid 1 — eventpush, refrefs/heads/smoke/actions-throwaway, status 1 (success).35623966-3663-3639-3532-333236616365v13.1.0 received the task.data.forgejo.org/oci/node:22-bookworm), not on the host (story 13).🏁 Job succeeded.data/actions_log/pit/infra-forge/01/1.log.zst— visible in the UI, so logs and history are there.Log excerpt:
The throwaway branch and workflow file have been removed; nothing was pushed to
main.Story status
Done: 1–18, all verified on Prod (instance toggle, restart notify, mirror default, per-repo flag, playbook-managed flag, runner installed, version pinned, checksum-first download, service-user ownership, CLI registration, systemd unit with
Restart=on-failure, idempotent second run, container execution, ADR + fallback, ADR for future engineers, RCE posture noted, systemd reachable, labels match workflows).Deferred (out of scope, listed as agent follow-ups in the issue): 19 (run logs queryable from the Guest) and 20 (job timeout default — actually set to
1hinrunner.yaml; can be moved out of deferred if you want it counted).No blockers. This issue is ready close as completed.
Resolution
Done — Actions is provisioned as infrastructure by the
forgejorole and proven working end to end on Prod. Closing as completed.Delivered (PRs #5 and #6, both merged):
[actions]in the app.ini template, applied through the existing restart notify.forgejo-runner.serviceunder the service user, registered via the Forgejo CLI shared-secret flow.has_actionsmanaged by the playbook via the API — including the guard fix in #6 so the flag is actually set, and the token-cleanup fix so no admin token is left behind.Verified on Prod (guest 141, after a snapshot):
ok=30 changed=3 failed=0— flag flipped, 0 leftover tokens, both services active. Second runok=26 changed=0..forgejo/workflows/push producedaction_runid 1, status success, job executed indata.forgejo.org/oci/node:22-bookworm, logs archived and visible in the UI (🏁 Job succeeded).Left deferred (as recorded in the issue): story 19 (query run logs from the Guest rather than copying the
.zstoff it) and story 20, which turned out to be implemented already —runner.yamlsetstimeout: 1h. Story 19 is the natural next issue if guest-side log access is wanted; nothing here depends on it.Closing.