Enable Forgejo Actions: app.ini toggle, per-repo flag, pinned runner on the Prod Guest #3

Closed
opened 2026-10-05 14:16:38 +00:00 by pit · 3 comments
Owner

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_actions false 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_actions flag 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

  1. As Pedro, I want Actions enabled instance-wide through the app.ini template the role already manages, so that re-provisioning the Guest cannot silently turn Actions off.
  2. As Pedro, I want the template change to restart the service through its existing notify, so that enablement takes effect with no extra manual step.
  3. As Pedro, I want the actions URL default pointed at Forgejo's own actions mirror, so that uses: lines in workflows resolve without touching GitHub.
  4. As Pedro, I want has_actions enabled on this repo, so that its .forgejo/workflows/ files are picked up.
  5. As Pedro, I want the per-repo flag managed by the playbook, so that a recreated repo or a re-run doesn't leave CI half-enabled.
  6. As Pedro, I want a Forgejo runner installed on the Prod Guest, so that queued workflow jobs actually execute rather than sit forever.
  7. As Pedro, I want the runner binary version pinned in the role defaults next to the Forgejo binary pin, so that playbook re-runs never drift the runner version (convention 4).
  8. As Pedro, I want the runner downloaded checksum-first like the Forgejo binary, so that a corrupted or tampered binary cannot reach the guest.
  9. As Pedro, I want the runner owned by the Forgejo service user under the service home, so that the blast radius of the runner process matches the service it serves.
  10. As Pedro, I want the runner registered with a token generated through the Forgejo CLI using the existing runuser pattern, so that provisioning needs no manual UI step.
  11. As Pedro, I want the runner managed by a systemd unit that restarts on failure, so that a transient crash doesn't leave CI dead until the next provision.
  12. As Pedro, I want a second playbook run to change nothing, so that the role stays idempotent like the rest of the role.
  13. As Pedro, I want the runner to execute jobs in containers rather than directly on the host, so that workflow code execution is isolated from the Forgejo service.
  14. As Pedro, I want the container execution decision revisited and the fallback recorded if Docker in the Guest proves impractical, so that the trade-off stays legible instead of becoming an undocumented constraint.
  15. As a future engineer, I want these decisions recorded in an ADR, so that "why is there a runner and what does it execute" has a canonical answer.
  16. As a future engineer, I want the runner's remote-code-execution implications noted alongside its mitigations, so that adding an outside collaborator triggers a security re-think.
  17. As an agent, I want the runner reachable as a systemd service on the Guest, so that CI health can be diagnosed without hunting processes by hand.
  18. As a workflow author, I want the runner registered with labels that match what my workflows request, so that my jobs get picked up instead of queueing forever.

User Stories (agent follow-ups, deferred)

  1. As an agent, I want run logs queryable from the Guest, so that a failed workflow can be diagnosed after the fact without UI access.
  2. As Pedro, I want a job timeout default set on the runner, so that a hung job cannot wedge the queue forever.

Implementation Decisions

  • The app.ini template gains an [actions] section: Actions enabled, default actions URL set to Forgejo's own action mirror (so uses: lines resolve without GitHub). The template's existing restart notify applies the change on the next playbook run.
  • The runner is a pinned release of the Forgejo runner (v13 line as of writing), downloaded checksum-first exactly like the Forgejo binary itself, installed under the service home, owned by the Forgejo service user.
  • Runner process: a role-managed systemd unit, Restart=on-failure, same pattern as the Forgejo service unit.
  • Registration token generated on the Guest through the Forgejo CLI with the existing runuser pattern (the role already uses it for account creation); registration itself is non-interactive.
  • Runner execution labels: container execution preferred (Docker inside the Guest; nesting is already enabled on the LXC). If Docker in the Guest proves impractical, host execution is the recorded fallback — acceptable given the single-user, registration-disabled posture, but the choice must be written down either way.
  • The per-repo has_actions flag is ensured by the playbook (API call with the admin token), not left as a manual UI step.
  • Secrets posture: registration token and any runner credentials are transient values used during provisioning; long-lived workflow credentials are NOT this issue's concern (they belong to the workflows that need them, e.g. the wiki-sync issue).
  • An ADR records the enablement and the execution-label choice, since the runner is a deliberate remote-code-execution surface added to the homelab.

Testing Decisions

  • A good test asserts external behavior only: after a playbook run, what does the Guest expose? Actions enabled in app.ini, a healthy systemd unit, a runner registered against the instance. Not the internal task ordering that got there.
  • The role is exercised against the PRE Guest (disposable rehearsal container) before Prod, same as the rest of the role's history — the PRE run is the test rig, and playbook idempotence is asserted by the conventional second run showing zero changed.
  • Prior art: the forgejo role's own account-creation tasks (guarded CLI invocations with register/changed_when) are the pattern for the registration task.
  • The definitive integration check: push a trivial workflow to the enabled repo and observe a green run with logs in the UI. This must be observed once on Prod before the issue is closed.

Out of Scope

  • Any actual workflows (the wiki sync lives in its own issue (#2)).
  • Any CI for the tofu/ansible code (lint, plan-diff) — separate future work.
  • Enabling Actions or runners for any other repo on the instance.
  • Runners on any host other than the Prod Guest; no clustering or autoscaling.
  • PRE Guest work beyond using it as the rehearsal target it already is.
  • GitLab-style PR checks or any branch-protection rules.

Further Notes

  • Verified at spec time: the repo reports 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).
  • This issue unblocks the Actions-based wiki-sync workflow issue (#2): that issue's stories about enabling Actions are satisfied by this one. It does not depend on it in reverse — the runner can run any future workflow.
  • The runner is remote code execution by design; container labels plus the single-user, registration-disabled posture are the mitigations. Revisit if the instance ever gains outside collaborators.
  • Sequencing: playbook role changes land via branch + PR per the repo's convention 1 (Pedro reviews); the trivial-workflow smoke test follows the merge, on Prod.
## 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_actions` false 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_actions` flag 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 1. As Pedro, I want Actions enabled instance-wide through the app.ini template the role already manages, so that re-provisioning the Guest cannot silently turn Actions off. 2. As Pedro, I want the template change to restart the service through its existing notify, so that enablement takes effect with no extra manual step. 3. As Pedro, I want the actions URL default pointed at Forgejo's own actions mirror, so that `uses:` lines in workflows resolve without touching GitHub. 4. As Pedro, I want `has_actions` enabled on this repo, so that its `.forgejo/workflows/` files are picked up. 5. As Pedro, I want the per-repo flag managed by the playbook, so that a recreated repo or a re-run doesn't leave CI half-enabled. 6. As Pedro, I want a Forgejo runner installed on the Prod Guest, so that queued workflow jobs actually execute rather than sit forever. 7. As Pedro, I want the runner binary version pinned in the role defaults next to the Forgejo binary pin, so that playbook re-runs never drift the runner version (convention 4). 8. As Pedro, I want the runner downloaded checksum-first like the Forgejo binary, so that a corrupted or tampered binary cannot reach the guest. 9. As Pedro, I want the runner owned by the Forgejo service user under the service home, so that the blast radius of the runner process matches the service it serves. 10. As Pedro, I want the runner registered with a token generated through the Forgejo CLI using the existing runuser pattern, so that provisioning needs no manual UI step. 11. As Pedro, I want the runner managed by a systemd unit that restarts on failure, so that a transient crash doesn't leave CI dead until the next provision. 12. As Pedro, I want a second playbook run to change nothing, so that the role stays idempotent like the rest of the role. 13. As Pedro, I want the runner to execute jobs in containers rather than directly on the host, so that workflow code execution is isolated from the Forgejo service. 14. As Pedro, I want the container execution decision revisited and the fallback recorded if Docker in the Guest proves impractical, so that the trade-off stays legible instead of becoming an undocumented constraint. 15. As a future engineer, I want these decisions recorded in an ADR, so that "why is there a runner and what does it execute" has a canonical answer. 16. As a future engineer, I want the runner's remote-code-execution implications noted alongside its mitigations, so that adding an outside collaborator triggers a security re-think. 17. As an agent, I want the runner reachable as a systemd service on the Guest, so that CI health can be diagnosed without hunting processes by hand. 18. As a workflow author, I want the runner registered with labels that match what my workflows request, so that my jobs get picked up instead of queueing forever. ## User Stories (agent follow-ups, deferred) 19. As an agent, I want run logs queryable from the Guest, so that a failed workflow can be diagnosed after the fact without UI access. 20. As Pedro, I want a job timeout default set on the runner, so that a hung job cannot wedge the queue forever. ## Implementation Decisions - The app.ini template gains an `[actions]` section: Actions enabled, default actions URL set to Forgejo's own action mirror (so `uses:` lines resolve without GitHub). The template's existing restart notify applies the change on the next playbook run. - The runner is a pinned release of the Forgejo runner (v13 line as of writing), downloaded checksum-first exactly like the Forgejo binary itself, installed under the service home, owned by the Forgejo service user. - Runner process: a role-managed systemd unit, `Restart=on-failure`, same pattern as the Forgejo service unit. - Registration token generated on the Guest through the Forgejo CLI with the existing runuser pattern (the role already uses it for account creation); registration itself is non-interactive. - Runner execution labels: container execution preferred (Docker inside the Guest; nesting is already enabled on the LXC). If Docker in the Guest proves impractical, host execution is the recorded fallback — acceptable given the single-user, registration-disabled posture, but the choice must be written down either way. - The per-repo `has_actions` flag is ensured by the playbook (API call with the admin token), not left as a manual UI step. - Secrets posture: registration token and any runner credentials are transient values used during provisioning; long-lived workflow credentials are NOT this issue's concern (they belong to the workflows that need them, e.g. the wiki-sync issue). - An ADR records the enablement and the execution-label choice, since the runner is a deliberate remote-code-execution surface added to the homelab. ## Testing Decisions - A good test asserts external behavior only: after a playbook run, what does the Guest expose? Actions enabled in app.ini, a healthy systemd unit, a runner registered against the instance. Not the internal task ordering that got there. - The role is exercised against the PRE Guest (disposable rehearsal container) before Prod, same as the rest of the role's history — the PRE run is the test rig, and playbook idempotence is asserted by the conventional second run showing zero changed. - Prior art: the forgejo role's own account-creation tasks (guarded CLI invocations with register/changed_when) are the pattern for the registration task. - The definitive integration check: push a trivial workflow to the enabled repo and observe a green run with logs in the UI. This must be observed once on Prod before the issue is closed. ## Out of Scope - Any actual workflows (the wiki sync lives in its own issue (#2)). - Any CI for the tofu/ansible code (lint, plan-diff) — separate future work. - Enabling Actions or runners for any other repo on the instance. - Runners on any host other than the Prod Guest; no clustering or autoscaling. - PRE Guest work beyond using it as the rehearsal target it already is. - GitLab-style PR checks or any branch-protection rules. ## Further Notes - Verified at spec time: the repo reports `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). - This issue unblocks the Actions-based wiki-sync workflow issue (#2): that issue's stories about enabling Actions are satisfied by this one. It does not depend on it in reverse — the runner can run any future workflow. - The runner is remote code execution by design; container labels plus the single-user, registration-disabled posture are the mitigations. Revisit if the instance ever gains outside collaborators. - Sequencing: playbook role changes land via branch + PR per the repo's convention 1 (Pedro reviews); the trivial-workflow smoke test follows the merge, on Prod.
Author
Owner

Status of the change, by PR.

#5 — enable Actions end to end (merged 2026-10-06)

What landed in the role:

  • Instance toggle: [actions] section in the app.ini template (ENABLED = true, DEFAULT_ACTIONS_URL = https://data.forgejo.org), applied through the template's existing restart handler (stories 1–3).
  • Runner binary: pinned 13.1.0 next to the Forgejo pin in role defaults, downloaded checksum-first, owned by the service user under the service home (stories 6–9).
  • Registration: Forgejo 15's shared-secret flow — the vaulted 40-hex secret registered server-side via forgejo-cli actions register, daemon authenticates with it. No manual UI step, no expiring token (story 10).
  • systemd unit for the runner daemon, Restart=on-failure (story 11).
  • Container labels: jobs run in containers (Docker inside the guest; nesting already on the LXC), registered as bare label names (stories 13, 18).
  • Per-repo flag: has_actions ensured by the playbook via the API with a per-run admin token, not a manual UI step (stories 4–5).
  • ADR-0001 recording the enablement and the execution-label choice (stories 14–16).

Applied to Prod (guest 141) on 2026-10-06: app.ini [actions] live, forgejo, forgejo-runner and docker all active+enabled, runner registered and online (action_runner row guest-runner, labels [docker, ubuntu-latest], Declare 200 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_actions stayed false and no token was ever minted. Three bugs, all fixed here and verified on a fresh PRE guest (142, destroyed and recreated):

  1. Guard query never matched. community.postgresql's list_to_pg_array str()s a list named_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.
  2. Transient-token cleanup 401'd, leaving a live 40-hex admin token behind. The route it called is the admin route and rejects token auth; the row is now deleted directly over the postgres connection the probes already use. Verified: 0 leftover ansible-has-actions-* rows after a run.
  3. Fresh-guest apt install failed on a stale index. Added one cache refresh at the top of §1.

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_actions flips False→True via the API, second run changed=0 (idempotent).

Still open before this issue can close

  • Prod has not been re-run since #6 merged. Right now Prod still reports has_actions: false for pit/infra-forge (the type-10 repo_unit row is absent) — the fix is in main but not applied. Needs one playbook run against inventories/prod/hosts, with a PBS snapshot of guest 141 first (convention 3).
  • The issue's closing integration check has not been performed: action_run count 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.
Status of the change, by PR. ## #5 — enable Actions end to end (merged 2026-10-06) What landed in the role: - **Instance toggle**: `[actions]` section in the `app.ini` template (`ENABLED = true`, `DEFAULT_ACTIONS_URL = https://data.forgejo.org`), applied through the template's existing restart handler (stories 1–3). - **Runner binary**: pinned `13.1.0` next to the Forgejo pin in role defaults, downloaded checksum-first, owned by the service user under the service home (stories 6–9). - **Registration**: Forgejo 15's shared-secret flow — the vaulted 40-hex secret registered server-side via `forgejo-cli actions register`, daemon authenticates with it. No manual UI step, no expiring token (story 10). - **systemd unit** for the runner daemon, `Restart=on-failure` (story 11). - **Container labels**: jobs run in containers (Docker inside the guest; nesting already on the LXC), registered as bare label names (stories 13, 18). - **Per-repo flag**: `has_actions` ensured by the playbook via the API with a per-run admin token, not a manual UI step (stories 4–5). - **ADR-0001** recording the enablement and the execution-label choice (stories 14–16). Applied to **Prod** (guest 141) on 2026-10-06: app.ini `[actions]` live, `forgejo`, `forgejo-runner` and `docker` all active+enabled, runner registered and online (`action_runner` row `guest-runner`, labels `[docker, ubuntu-latest]`, `Declare` 200 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_actions` stayed `false` and no token was ever minted. Three bugs, all fixed here and verified on a fresh PRE guest (142, destroyed and recreated): 1. **Guard query never matched.** `community.postgresql`'s `list_to_pg_array` `str()`s a list `named_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. 2. **Transient-token cleanup 401'd**, leaving a live 40-hex admin token behind. The route it called is the *admin* route and rejects token auth; the row is now deleted directly over the postgres connection the probes already use. Verified: 0 leftover `ansible-has-actions-*` rows after a run. 3. **Fresh-guest apt install failed** on a stale index. Added one cache refresh at the top of §1. 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_actions` flips `False`→`True` via the API, second run `changed=0` (idempotent). ## Still open before this issue can close - **Prod has not been re-run since #6 merged.** Right now Prod still reports `has_actions: false` for `pit/infra-forge` (the type-10 `repo_unit` row is absent) — the fix is in `main` but not applied. Needs one playbook run against `inventories/prod/hosts`, with a PBS snapshot of guest 141 first (convention 3). - **The issue's closing integration check has not been performed**: `action_run` count 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.
Author
Owner

Closing evidence — Actions works end to end on Prod

Prod applied. One playbook run against inventories/prod/hosts after 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-10 repo_unit row now present for pit/infra-forge (has_actions: true), 0 leftover ansible-has-actions-* tokens, forgejo and forgejo-runner both active. Second run: ok=26 changed=0 (idempotent, story 12).

The definitive integration check (Testing Decisions). Pushed a trivial .forgejo/workflows/actions-smoke.yml to a throwaway branch on Prod and observed the run:

  • action_run id 1 — event push, ref refs/heads/smoke/actions-throwaway, status 1 (success).
  • Runner 35623966-3663-3639-3532-333236616365 v13.1.0 received the task.
  • Job executed in a container (data.forgejo.org/oci/node:22-bookworm), not on the host (story 13).
  • All three steps ran; env carried between steps; final line 🏁 Job succeeded.
  • Log archived at data/actions_log/pit/infra-forge/01/1.log.zst — visible in the UI, so logs and history are there.

Log excerpt:

Runner ... (version:v13.1.0) received task 1 of job smoke, triggered by event: push
workflow prepared
🚀  Start image=data.forgejo.org/oci/node:22-bookworm
⭐ Run Main prove the runner is alive
Actions is running on the Prod Guest.
Linux 07c53439e789 ... x86_64 GNU/Linux
job: smoke  run: 1
carried: from-step-one
🏁  Job succeeded

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 1h in runner.yaml; can be moved out of deferred if you want it counted).

No blockers. This issue is ready close as completed.

## Closing evidence — Actions works end to end on Prod **Prod applied.** One playbook run against `inventories/prod/hosts` after 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-10 `repo_unit` row now present for `pit/infra-forge` (`has_actions: true`), 0 leftover `ansible-has-actions-*` tokens, `forgejo` and `forgejo-runner` both active. Second run: `ok=26 changed=0` (idempotent, story 12). **The definitive integration check (Testing Decisions).** Pushed a trivial `.forgejo/workflows/actions-smoke.yml` to a throwaway branch on Prod and observed the run: - `action_run` id 1 — event `push`, ref `refs/heads/smoke/actions-throwaway`, **status 1 (success)**. - Runner `35623966-3663-3639-3532-333236616365` v13.1.0 received the task. - Job executed **in a container** (`data.forgejo.org/oci/node:22-bookworm`), not on the host (story 13). - All three steps ran; env carried between steps; final line `🏁 Job succeeded`. - Log archived at `data/actions_log/pit/infra-forge/01/1.log.zst` — visible in the UI, so logs and history are there. Log excerpt: ``` Runner ... (version:v13.1.0) received task 1 of job smoke, triggered by event: push workflow prepared 🚀 Start image=data.forgejo.org/oci/node:22-bookworm ⭐ Run Main prove the runner is alive Actions is running on the Prod Guest. Linux 07c53439e789 ... x86_64 GNU/Linux job: smoke run: 1 carried: from-step-one 🏁 Job succeeded ``` 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 `1h` in `runner.yaml`; can be moved out of deferred if you want it counted). No blockers. This issue is ready close as completed.
Author
Owner

Resolution

Done — Actions is provisioned as infrastructure by the forgejo role and proven working end to end on Prod. Closing as completed.

Delivered (PRs #5 and #6, both merged):

  • Instance-wide [actions] in the app.ini template, applied through the existing restart notify.
  • Runner v13.1.0 pinned in role defaults, downloaded checksum-first, run as forgejo-runner.service under the service user, registered via the Forgejo CLI shared-secret flow.
  • Per-repo has_actions managed 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.
  • ADR-0001 recording enablement and the container-execution choice.

Verified on Prod (guest 141, after a snapshot):

  • Playbook run ok=30 changed=3 failed=0 — flag flipped, 0 leftover tokens, both services active. Second run ok=26 changed=0.
  • Smoke test: a trivial .forgejo/workflows/ push produced action_run id 1, status success, job executed in data.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 .zst off it) and story 20, which turned out to be implemented already — runner.yaml sets timeout: 1h. Story 19 is the natural next issue if guest-side log access is wanted; nothing here depends on it.

Closing.

## Resolution Done — Actions is provisioned as infrastructure by the `forgejo` role and proven working end to end on Prod. Closing as completed. **Delivered** (PRs #5 and #6, both merged): - Instance-wide `[actions]` in the app.ini template, applied through the existing restart notify. - Runner v13.1.0 pinned in role defaults, downloaded checksum-first, run as `forgejo-runner.service` under the service user, registered via the Forgejo CLI shared-secret flow. - Per-repo `has_actions` managed 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. - ADR-0001 recording enablement and the container-execution choice. **Verified on Prod** (guest 141, after a snapshot): - Playbook run `ok=30 changed=3 failed=0` — flag flipped, 0 leftover tokens, both services active. Second run `ok=26 changed=0`. - Smoke test: a trivial `.forgejo/workflows/` push produced `action_run` id 1, **status success**, job executed in `data.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 `.zst` off it) and story 20, which turned out to be implemented already — `runner.yaml` sets `timeout: 1h`. Story 19 is the natural next issue if guest-side log access is wanted; nothing here depends on it. Closing.
pit closed this issue 2026-10-06 08:28:37 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
olympus/infra-forge#3
No description provided.