Setup
Get from zero to a first dry-run against your instance.
Install
The package ships a bundled CLI, forgejo-warden. Run it with npx or install it:
# one-off
npx @intentius/forgejo-warden
# or install
npm install -g @intentius/forgejo-warden
forgejo-warden --help
Node 22+ (the CLI uses the global fetch).
Create a token
Warden authenticates with a single Forgejo API token, sent as
Authorization: token .... The token's user must be an owner (or site admin) of
every org the policy manages.
In the Forgejo web UI:
- Avatar menu > Settings > Applications.
- Under Manage access tokens, name the token (e.g.
forgejo-warden). - Select scopes. For a dry-run, read access to
organizationandrepositoryis enough. For apply, grant read-and-write onorganizationandrepository; thesecrets-variablescycle also needs whatever your Forgejo version gates Actions secrets/variables behind (on current versions this is covered by write access toorganizationandrepository). - Generate token and copy it immediately (it is shown once).
On a self-hosted instance you can also mint one from the CLI:
forgejo admin user generate-access-token --username <admin> --scopes all --raw
Export it into the environment; warden only ever reads the token from an env
var (--token-env) and never from argv:
export FORGEJO_TOKEN=<the token>
Point at your instance
--base-url is the instance root, no trailing /api:
- self-hosted:
--base-url https://forgejo.example.com - Codeberg:
--base-url https://codeberg.org - or keep it out of the command line:
--base-url-env FORGEJO_URL
Requests resolve to <base-url>/api/v1/....
First dry-run
Write a minimal policy that only reads what you already have. Start with one slice, say org settings:
# governance.yml
orgs:
my-org:
settings:
description: Managed by forgejo-warden
Run it. Dry-run is the default, so nothing gets written:
forgejo-warden reconcile \
--config governance.yml \
--base-url https://forgejo.example.com \
--token-env FORGEJO_TOKEN
You get one plan block per cycle per org. Cycles with no declared slice report an empty plan. If the plan looks right, apply it:
forgejo-warden reconcile --config governance.yml \
--base-url https://forgejo.example.com --token-env FORGEJO_TOKEN \
--mode apply
Then grow the policy slice by slice (teams, repos, branch protection), checking the dry-run plan each time. POLICY.md has a complete annotated example; CLI.md covers flags and exit codes.
A disposable sandbox: the e2e stack
The repo ships a hermetic throwaway Forgejo you can experiment against without touching a real instance: Forgejo 11 on sqlite, web installer skipped, no persistence beyond the compose volume.
git clone https://github.com/INTENTIUS/forgejo-warden && cd forgejo-warden
npm ci
# compose up + create an admin user + mint a token;
# exports FORGEJO_E2E_URL / FORGEJO_E2E_TOKEN into your shell
eval "$(npm run --silent e2e:up)"
# point warden at it
forgejo-warden reconcile --config governance.yml \
--base-url "$FORGEJO_E2E_URL" --token-env FORGEJO_E2E_TOKEN
# tear down (removes the volume and all state)
npm run e2e:down
The stack definition is e2e/docker-compose.yml; e2e/bootstrap.sh waits for
the API, creates the warden-admin user, and mints an all-scopes token. The
instance serves the web UI at http://localhost:3000 if you want to click around
and watch warden's changes land. npm run test:e2e:run runs the e2e suite
against it (set FORGEJO_E2E_APPLY=1 to include the apply phase).