Skip to content

forgejo-warden

ci e2e npm

Keep your Forgejo org and repos in a declared state, with guardrails and drift correction.

Full documentation lives at intentius.io/forgejo-warden, with deep dives on these pages.

Set up with an agent

From a checkout, Claude Code picks up the skill in .claude/skills/forgejo-warden automatically. Other agents can install it with npx skills add INTENTIUS/forgejo-warden, or by copying the skill directory into ~/.claude/skills/. Then paste this prompt, filling in the placeholders:

Use the forgejo-warden skill in this repo to help me set up governance for my
Forgejo org <ORG> on <BASE_URL>. My API token is in the <TOKEN_ENV> env var.
Author a governance.yml policy for the org settings, teams, and repos I care
about (interview me for the details), then run a dry-run reconcile and walk me
through the plan. Do not apply anything.

The skill holds the agent to dry-run until you've reviewed the plan; deletes stay off entirely until you mark an org owned in the policy.

What you need

  • A clone of this repo (git clone https://github.com/INTENTIUS/forgejo-warden). The agent skill, the annotated policy example, and the CI templates live in it, and setup ends with a pipeline (CI.md), so you'll have the repo anyway.
  • A Forgejo API token (SETUP.md has the click-path and scopes; a dry-run needs only read). Any self-hosted Forgejo works, and so does Codeberg; point --base-url at the instance.
  • Node 22+.

About ten minutes gets you to a first dry-run plan. The quickest probe needs no clone at all:

# Dry-run: reads only, prints a plan, changes nothing.
npx @intentius/forgejo-warden reconcile --config governance.yml --base-url https://forgejo.example.com --token-env FORGEJO_TOKEN --mode dry-run

The npm package is there for pipelines; day-to-day authoring happens in the checkout.

What it reconciles

You declare desired state in YAML (selective-by-omission: an absent field is never read, diffed, or touched); warden diffs it against the live org and, in apply mode, converges it. Deletes are opt-in per org via owned: and guarded by a removal cap so a typo can't mass-delete (POLICY.md, "Delete semantics").

Cycle Reconciles
org-settings org name/description/website/visibility, repo-admin team access
membership org members (team-driven; ownership-gated removal)
teams teams + their members and repo access
repo-settings repo settings + topics
branch-protection Forgejo branch_protections (not rulesets)
repo-baseline provision repos (empty or from a template)
secrets-variables Actions secrets (presence) + variables (value), org & repo
webhooks org & repo webhooks

Tests

npm test runs the unit suite (mock-client, fully offline). The e2e suite is fully hermetic: it stands up a throwaway Forgejo via Docker Compose and mints an admin token, then provisions its own org and runs every cycle's read path against it (fetchLive, buildDesired, diff, asserted read-only), so live API-contract drift gets caught. The opt-in apply phase is a full smoke: every cycle applies from a policy, converges to an empty plan, and corrects an out-of-band mutation, plus real owned: deletes, the previously: team rename, template-based repo provisioning, and secret/membership semantics — see e2e/README.md for the coverage table. No external account or secrets are needed:

eval "$(npm run --silent e2e:up)"   # compose up + mint token
npm run test:e2e:run                # FORGEJO_E2E_APPLY=1 to include the apply phase
npm run e2e:down                    # compose down -v

CI runs it on every push to main and nightly.

How it differs from github-warden

This is a sibling of github-warden, built on the shared reconcile primitive in @intentius/chant/reconcile. What this repo supplies is the Forgejo layer: a REST client for a self-hosted instance, the config and live-state types, and a Forgejo diff() with its reconcile cycles.

The client takes a configurable instance base URL instead of a fixed API host, and auth is a plain Forgejo API token with no GitHub Apps or installation-token machinery. Membership is team-driven here, branch protection stands in for rulesets, and webhooks are in scope. Some GitHub surfaces have no Forgejo equivalent and stay out of scope; that covers GHAS and the other security features, deployment environments, and Dependabot, as well as fine-grained PAT governance.