A Forgejo Actions Runner, Registered By Shared Secret

Forgejo Runner 13.2 from the vendor's release, sha256-checked, in a hardened unit, registered the way Forgejo now asks: a secret registered with forgejo-cli on the Forgejo host and a connection in config.yml. The live test pushes a workflow; its job runs on the runner and finds /home hidden, /tmp private and the system read-only. Original role, live-tested on Rocky Linux 10.

ansibleCI/CD & Automation

Verification

Live-tested

Really deployed to a container sandbox, proven idempotent (a second run changes nothing), verified against the role’s assertions, then torn down.

Conformance

  • Static validation (yamllint · ansible-lint)

Provenance

  • SHA-256 checksum
  • Signature (pending)

Functional

  • Live-tested - applied, verified, destroyed

Last verified 2026-10-03 · podman 4.9.3 · ansible 2.21.4 · how we verify

Cite it in your README

badge · attribution

Paste this beside the module in the repository that uses it. The badge is rendered from this artifact's verification record, so it reads live-tested because the record says so, and the link lands on this page.

README.md, GitLab, Gitea
[![IaC Bazaar: live-tested](https://www.iac-bazaar.com/api/artifacts/ansible-forgejo-runner/badge)](https://www.iac-bazaar.com/catalog/ansible-forgejo-runner?utm_source=syndication&utm_medium=readme&utm_campaign=artifact)

Ansible role 1.0.0, live-tested on IaC Bazaar: [A Forgejo Actions Runner, Registered By Shared Secret](https://www.iac-bazaar.com/catalog/ansible-forgejo-runner?utm_source=syndication&utm_medium=readme&utm_campaign=artifact)

```yaml
# A Forgejo Actions Runner, Registered By Shared Secret: https://www.iac-bazaar.com/catalog/ansible-forgejo-runner (download from your IaC Bazaar account)
```

Preview:IaC Bazaar: live-tested

Documentation

forgejo-runner

Forgejo Runner from the vendor's release: a hardened unit that takes jobs from your Forgejo, registered the way Forgejo now asks for - a shared secret, and a connection in the runner's config.yml - rather than through the register command that 13.2 deprecates. Original role for EL 10, live-tested with podman on Rocky Linux 10.

No package, so the checksum is the whole story. EL 10 carries no forgejo-runner; Forgejo publishes each release with a SHA-256 file beside it. The role downloads both and has Ansible's get_url refuse the binary unless it matches, then installs it as root's in /usr/local/bin, pinned by forgejo_runner_version.

Registered without the deprecated commands. In 13.2 forgejo-runner register and create-runner-file both say "(deprecated)". The role makes a secret of 40 hexadecimal characters once, registers it on the Forgejo host with forgejo forgejo-cli actions register - delegated to forgejo_runner_forgejo_host, as Forgejo's own user, the secret on stdin and never in a command line - and writes the connection into config.yml: Forgejo's URL, the UUID Forgejo derives from the secret, and the path of the token file, so config.yml holds no secret. Two details are measured, not guessed: the token is the whole secret (the part after the identifier is refused as "unregistered runner"), and a trailing newline on stdin makes it 41 characters, which Forgejo refuses. Registering the same secret again updates the runner's name and labels in place, so the role does it on every run. No .runner file is written. A runner made in Forgejo's web interface works too: give its UUID and token instead, with forgejo_runner_register: false.

A host runner is a door into this host. A job on a host label runs on this machine as forgejo-runner, inside the unit's sandbox: the live test's job sees /home hidden, a /tmp of its own, a world-writable directory elsewhere read-only, and no new privileges - and with the sandbox removed, all four flip (measured both ways). What the sandbox cannot hide is the runner's own token: the daemon reads it as that user, so a job can read it too (measured). Anyone who can push a workflow to a repository this runner serves can therefore act as the runner. Scope it to an owner or a repository you trust (forgejo_runner_scope), or keep the instance's accounts to people you would give a shell on this host. systemd's LoadCredential= would hand the token to that same user, so a job could read it there as well; it also could not be opened in the container this role is tested in (measured).

What a failure looks like. With a wrong token or an unreachable Forgejo at start, the runner exits and systemd restarts it (both measured). The role watches for one steady process, so it fails the run instead of reporting a runner that never connects (measured with a token Forgejo does not know). Once the runner is registered, a Forgejo outage only makes it log fetch errors and keep polling; it is idle again when Forgejo is back (measured).

License

Commercial - IaC Bazaar EULA. (c) IaC Bazaar.

Usage code & full reference need an account

The complete copy-paste usage, the full input/output reference, and operational notes are free with an account - shown here and bundled in the download. Sign in and this section fills in.

  • Variables
  • Test

Related modules

Live-tested

ansible-forgejo

Forgejo from the upstream release as a hardened service on loopback with sqlite and a configuration it never needs to write. The live test creates an administrator with Forgejo's own command, sees a wrong password refused and registration disabled, creates a private repository, hides it from an anonymous request and clones it over HTTP. Original role, live-tested on Rocky Linux 10.

View module
Live-tested

ansible-atmos

atmos on EL 10 from the GitHub release, get_url refuses it unless its SHA-256 is the one in the vendor's SHA256SUMS, and the live test re-checks it, then writes an atmos.yaml, a stack and a component, validates the stacks and describes the component with no Terraform installed. Pinned. Original role, live-tested on Rocky Linux 10.

View module
Live-tested

ansible-checkov

Checkov pinned in /opt/checkov, a virtual environment apart from the system Python. The live test runs pip check, scans a one-resource module with the built-in checks and --skip-download and expects a 'Failed checks:' summary with no network, and asserts the system Python cannot import it. Original role, live-tested on Rocky Linux 10.

View module
Live-tested

ansible-conftest

conftest on EL 10 from the GitHub release, refused by Ansible's get_url unless its SHA-256 is the one in the project's checksums.txt, and re-checked with sha256sum -c by the live test, which then writes a one-rule Rego v1 policy and a one-line document, runs conftest test and expects the denial in the report. Original role, live-tested on Rocky Linux 10.

View module
Live-tested

ansible-consul-cli

consul on EL 10 from releases.hashicorp.com: the client binary, not a server. HashiCorp's key lives in a GnuPG home of its own, pinned by fingerprint; the SHA256SUMS signature is verified before get_url checks the zip against that file, and the live test verifies it again, then runs consul members against nothing and expects the refused connection. Original role, live-tested on Rocky Linux 10.

View module
Live-tested

ansible-gh-cli

gh on EL 10 from the release tarball, refused by Ansible's get_url unless its SHA-256 is the one in GitHub's checksums file, and re-checked with sha256sum -c by the live test; one more file to trust and no more repositories. Tokens are per user; gh auth status with none stops at 'not logged into any GitHub hosts', the live test's proof the client ran. Original role, live-tested on Rocky Linux 10.

View module