What
CI.md invokes warden as run: npx @intentius/forgejo-warden … inside a .forgejo/workflows/ job. A small Forgejo action would collapse that to one uses: line, matching how the GitHub sibling ships action.yml.
Two things to settle before building, because both are easy to get wrong.
github-warden's action.yml cannot be reused
Not a copy, and not a URL reference. Two independent reasons:
- Its inputs are GitHub-App-shaped —
app-id, installation-id, private-key — and that auth machinery does not exist on Forgejo at all.
- It is not in
data.forgejo.org's curated mirror, so it would only resolve via an explicit https://github.com/... URL or an instance-wide DEFAULT_ACTIONS_URL repoint. Both make the workflow depend on live github.com reachability from the runner, which self-hosted and air-gapped instances often do not have — and which sits badly with a tool whose premise is governing a forge chosen to be independent of GitHub.
Where it has to live
Forgejo has no marketplace. A bare uses: owner/repo@ref is prefixed with the instance's DEFAULT_ACTIONS_URL, defaulting to https://data.forgejo.org — a Forgejo-team-maintained mirror of common actions, not an open publish target. So this action must be referenced by a fully-qualified URL to somewhere Forgejo runners can reach: this repo self-hosted, or Codeberg. Decide which, because it determines whether adopters on closed networks can use it at all.
Do
- A Node20
action.yml shimming the existing CLI entry point.
- Inputs mirroring
CLI.md's flags.
- A
.forgejo/workflows/ test exercising it against the existing e2e stack.
- Documented
uses: line with the fully-qualified URL, in CI.md beside the existing npx form rather than replacing it — the npx form keeps working for anyone who cannot resolve the action.
The input contract, which is the cross-repo part
The three wardens will never share a wrapper artifact. What they can share is the input surface, so an adopter moving between forges meets one interface. github-warden's action.yml is the reference shape; name these identically:
command · config · mode · cycles · fail-on · allow-guardrail-override
Only auth differs: this takes token-env and base-url.
Note command is aspirational here — see the scope gap below.
What this does and does not buy
Ergonomics only. The workflow still needs a real org-owner PAT in secrets.FORGEJO_WARDEN_TOKEN, exactly as CI.md already sets up. Forgejo Actions' automatic token (FORGEJO_TOKEN) is repo-scoped and job-ephemeral, so it cannot reach org settings, other repos, or org-level secrets — the exact surfaces the org-settings, membership, teams and org half of secrets-variables cycles touch. An action wraps the token-provisioning step; it does not remove it.
Why there is no app to build instead
Forgejo has no installable-app concept, and this was checked rather than assumed. Its OAuth2 provider supports only the authorization-code grant — a human clicks consent — and, decisively, OAuth2 scopes are not implemented at all: a token minted that way holds full administrative rights or does not exist. Nothing in forgejo/design proposes an installation model.
Worth recording because it is a live trap: Gitea 1.23 added granular OAuth2 scopes and Forgejo has not adopted them. Reading Gitea's current docs would make OAuth2 look viable here. It is not, on Forgejo, today. This is the same class of assumption as gh's GH_TOKEN not authenticating against self-hosted Forgejo — GitHub- and Gitea-shaped concepts do not transfer by default.
Scoped PATs remain the mechanism. A dedicated bot account is the right advice but currently documentation rather than a feature: Forgejo's bot-account flag is still WIP (forgejo#8136).
Separate finding, not part of this
This repo has only reconcile. The GitHub sibling exposes command: reconcile|audit and a fail-on input. If audit parity is wanted, that is a feature gap to file on its own — it would need the same organization+repository read scopes reconcile's dry-run already documents.
Proof
A .forgejo/workflows/ job consuming the action by URL and completing a dry-run reconcile against the e2e stack.
What
CI.mdinvokes warden asrun: npx @intentius/forgejo-warden …inside a.forgejo/workflows/job. A small Forgejo action would collapse that to oneuses:line, matching how the GitHub sibling shipsaction.yml.Two things to settle before building, because both are easy to get wrong.
github-warden's action.yml cannot be reused
Not a copy, and not a URL reference. Two independent reasons:
app-id,installation-id,private-key— and that auth machinery does not exist on Forgejo at all.data.forgejo.org's curated mirror, so it would only resolve via an explicithttps://github.com/...URL or an instance-wideDEFAULT_ACTIONS_URLrepoint. Both make the workflow depend on live github.com reachability from the runner, which self-hosted and air-gapped instances often do not have — and which sits badly with a tool whose premise is governing a forge chosen to be independent of GitHub.Where it has to live
Forgejo has no marketplace. A bare
uses: owner/repo@refis prefixed with the instance'sDEFAULT_ACTIONS_URL, defaulting tohttps://data.forgejo.org— a Forgejo-team-maintained mirror of common actions, not an open publish target. So this action must be referenced by a fully-qualified URL to somewhere Forgejo runners can reach: this repo self-hosted, or Codeberg. Decide which, because it determines whether adopters on closed networks can use it at all.Do
action.ymlshimming the existing CLI entry point.CLI.md's flags..forgejo/workflows/test exercising it against the existing e2e stack.uses:line with the fully-qualified URL, inCI.mdbeside the existingnpxform rather than replacing it — thenpxform keeps working for anyone who cannot resolve the action.The input contract, which is the cross-repo part
The three wardens will never share a wrapper artifact. What they can share is the input surface, so an adopter moving between forges meets one interface. github-warden's
action.ymlis the reference shape; name these identically:command·config·mode·cycles·fail-on·allow-guardrail-overrideOnly auth differs: this takes
token-envandbase-url.Note
commandis aspirational here — see the scope gap below.What this does and does not buy
Ergonomics only. The workflow still needs a real org-owner PAT in
secrets.FORGEJO_WARDEN_TOKEN, exactly asCI.mdalready sets up. Forgejo Actions' automatic token (FORGEJO_TOKEN) is repo-scoped and job-ephemeral, so it cannot reach org settings, other repos, or org-level secrets — the exact surfaces theorg-settings,membership,teamsand org half ofsecrets-variablescycles touch. An action wraps the token-provisioning step; it does not remove it.Why there is no app to build instead
Forgejo has no installable-app concept, and this was checked rather than assumed. Its OAuth2 provider supports only the authorization-code grant — a human clicks consent — and, decisively, OAuth2 scopes are not implemented at all: a token minted that way holds full administrative rights or does not exist. Nothing in
forgejo/designproposes an installation model.Worth recording because it is a live trap: Gitea 1.23 added granular OAuth2 scopes and Forgejo has not adopted them. Reading Gitea's current docs would make OAuth2 look viable here. It is not, on Forgejo, today. This is the same class of assumption as
gh'sGH_TOKENnot authenticating against self-hosted Forgejo — GitHub- and Gitea-shaped concepts do not transfer by default.Scoped PATs remain the mechanism. A dedicated bot account is the right advice but currently documentation rather than a feature: Forgejo's bot-account flag is still WIP (forgejo#8136).
Separate finding, not part of this
This repo has only
reconcile. The GitHub sibling exposescommand: reconcile|auditand afail-oninput. If audit parity is wanted, that is a feature gap to file on its own — it would need the sameorganization+repositoryread scopes reconcile's dry-run already documents.Proof
A
.forgejo/workflows/job consuming the action by URL and completing a dry-run reconcile against the e2e stack.