What
CI.md documents warden's invocation as a .gitlab-ci.yml a consumer copies and edits. GitLab's native unit for a distributable, versioned thing people adopt is a CI/CD Component, published to the CI Catalog and consumed as a one-line include:. This packages the invocation the way action.yml packages it for the GitHub sibling.
To be explicit about what this is not: it is not the GitLab equivalent of a GitHub App, and it does nothing for identity. Consumers still create their own group access token exactly as SETUP.md describes. See the "why not an app" note below so this does not get re-litigated later.
Do
- A
templates/ directory — one template per entry point (reconcile.yml, migrate.yml, mirroring the jobs CI.md already spells out), each with a spec: inputs: block.
- A
README.md documenting each component and its inputs. The Catalog requires it.
- A test
.gitlab-ci.yml exercising the templates. The existing hermetic e2e stack can drive a real dry-run smoke.
- Settings → General → Visibility → enable "CI/CD Catalog resource" (needs Owner and a project description).
- A
release: job on semver tags publishing versions to the Catalog, so consumers write include: - component: $CI_SERVER_FQDN/…/reconcile@1.
The input contract, which is the cross-repo part
The three wardens will never share a wrapper artifact — GitHub has action.yml, GitLab has this, Forgejo needs its own. 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. Forge-neutral inputs, to be named identically here:
command · config · mode · cycles · fail-on · allow-guardrail-override
Only auth differs, necessarily: GitHub takes app-id/installation-id/private-key; this takes token-variable (or token-env) and base-url. Diverging on the neutral six would be the easy mistake and the one worth avoiding.
Keep spec: inputs: in sync with src/cli.ts each release. That is one more file on the existing CLI.md/cli.ts sync point, not a new kind of obligation.
Why not an app
GitLab has no GitHub-App equivalent, and the missing primitive is nameable: an OAuth2 client-credentials (app-only, no-user) grant, tracked unimplemented at gitlab-org/gitlab#419240. Every GitLab OAuth token resolves to a human's authorization redirect, so an app cannot act as itself. src/auth/client.ts already records this — "Host-parameterized … and token-authed — no Apps" — and the README's sibling table is accurate as written.
Building OAuth support would mean a redirect flow, a client secret and refresh handling, to arrive at a token that still represents a human — which --token-env already provides with none of that. Independent confirmation: other GitLab integrators (CodeRabbit, GitGuardian) all document "ask the admin for a token," not "install our app."
Warden also needs api scope, which is wide and long-lived. Even if app-style narrow, short-lived tokens existed on GitLab, warden's own scope requirement would blunt most of the benefit.
Proof
A consuming project including the component by version and running a dry-run reconcile, with the component's inputs matching src/cli.ts's flags.
Refs: the GitHub sibling's action.yml, and the Forgejo sibling's equivalent packaging issue.
What
CI.mddocuments warden's invocation as a.gitlab-ci.ymla consumer copies and edits. GitLab's native unit for a distributable, versioned thing people adopt is a CI/CD Component, published to the CI Catalog and consumed as a one-lineinclude:. This packages the invocation the wayaction.ymlpackages it for the GitHub sibling.To be explicit about what this is not: it is not the GitLab equivalent of a GitHub App, and it does nothing for identity. Consumers still create their own group access token exactly as
SETUP.mddescribes. See the "why not an app" note below so this does not get re-litigated later.Do
templates/directory — one template per entry point (reconcile.yml,migrate.yml, mirroring the jobsCI.mdalready spells out), each with aspec: inputs:block.README.mddocumenting each component and its inputs. The Catalog requires it..gitlab-ci.ymlexercising the templates. The existing hermetic e2e stack can drive a real dry-run smoke.release:job on semver tags publishing versions to the Catalog, so consumers writeinclude: - component: $CI_SERVER_FQDN/…/reconcile@1.The input contract, which is the cross-repo part
The three wardens will never share a wrapper artifact — GitHub has
action.yml, GitLab has this, Forgejo needs its own. 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. Forge-neutral inputs, to be named identically here:command·config·mode·cycles·fail-on·allow-guardrail-overrideOnly auth differs, necessarily: GitHub takes
app-id/installation-id/private-key; this takestoken-variable(ortoken-env) andbase-url. Diverging on the neutral six would be the easy mistake and the one worth avoiding.Keep
spec: inputs:in sync withsrc/cli.tseach release. That is one more file on the existing CLI.md/cli.ts sync point, not a new kind of obligation.Why not an app
GitLab has no GitHub-App equivalent, and the missing primitive is nameable: an OAuth2 client-credentials (app-only, no-user) grant, tracked unimplemented at gitlab-org/gitlab#419240. Every GitLab OAuth token resolves to a human's authorization redirect, so an app cannot act as itself.
src/auth/client.tsalready records this — "Host-parameterized … and token-authed — no Apps" — and the README's sibling table is accurate as written.Building OAuth support would mean a redirect flow, a client secret and refresh handling, to arrive at a token that still represents a human — which
--token-envalready provides with none of that. Independent confirmation: other GitLab integrators (CodeRabbit, GitGuardian) all document "ask the admin for a token," not "install our app."Warden also needs
apiscope, which is wide and long-lived. Even if app-style narrow, short-lived tokens existed on GitLab, warden's own scope requirement would blunt most of the benefit.Proof
A consuming project including the component by version and running a dry-run reconcile, with the component's inputs matching
src/cli.ts's flags.Refs: the GitHub sibling's
action.yml, and the Forgejo sibling's equivalent packaging issue.