Skip to content

CLI reference

One binary, two subcommands:

gitlab-warden reconcile --config governance.yaml [flags]
gitlab-warden migrate <path> [flags]

reconcile is the governance loop this page documents; migrate translates GitHub Actions workflows into GitLab CI YAML and has its own page (MIGRATE.md, flags included). gitlab-warden --help (or no arguments, or --help after a subcommand) prints usage; gitlab-warden --version prints the version (inlined from package.json at build time).

Reconcile flags

Flag Default Meaning
--config <path> required governance config file (YAML, or JSON when the path ends in .json)
--mode dry-run\|apply dry-run dry-run computes and prints the plan; apply mutates after guardrails pass
--cycles <name[,name…]> all 20 comma-separated cycle names to run (see CYCLES.md); an unknown name is an error listing the known ones
--base-url <url> https://gitlab.com GitLab instance URL for self-managed, e.g. https://gitlab.example.com
--base-url-env <VAR> read the base URL from an env var instead (--base-url wins if both are given)
--token-env <VAR> GITLAB_TOKEN env var holding the API token; the run fails (exit 2) if it is unset or empty
--allow-guardrail-override off apply even when a guardrail trips
--removal-cap-fraction <f> 0.25 max deletable fraction of each resource type's live entries per apply; must be in (0, 1] or the parse fails with exit 2

The command accepts flags only; a positional argument is an error. Every flag except --allow-guardrail-override takes a value.

Config loading

  • The file is parsed as JSON if the path ends in .json (case-insensitive), otherwise as YAML.
  • It must be an object with a nodes map (POLICY.md documents the schema). Anything else is rejected with exit 2.

Auth and token scopes

The token is sent as the PRIVATE-TOKEN header against <base-url>/api/v4 (REST) and <base-url>/api/graphql (the GraphQL cycles). Use a personal access token or a group access token with:

  • api scope (required; the reconcile both reads and writes).
  • Owner on declared group nodes and Maintainer or above on declared project nodes (member management, protected branches, tokens, and settings writes need those roles).
  • Instance admin for kind: instance nodes (/application/settings, /hooks, and /admin/ci/variables are admin-only and absent on GitLab.com, where the instance-governance cycle simply manages nothing).

Never pass the token on the command line; export it and name the variable via --token-env.

Modes, guardrails, budget

  • dry-run (default): reads live state, prints a per-cycle plan (=== <cycle> @ <scope> ===), changes nothing. When a declared slice's read was tier-gated, the plan ends with NOTE: <slice>: read was tier-gated (403); planned entries may fail on apply.
  • apply: applies each planned entry, then prints Applied: N, Failed: M per cycle with one FAILED [type] key: error line per failure (e.g. a 403 from a tier-gated endpoint).
  • Guardrail: the per-collection removal cap bounds how much of any one resource type's live entries a single apply may delete — the exact promise lives with the delete semantics in POLICY.md. A tripped guardrail prints GUARDRAIL BLOCK: …, skips that cycle's apply, and exits 1; --allow-guardrail-override applies anyway, and --removal-cap-fraction adjusts the threshold.
  • Request budget: a run has a shared budget of 1000 API requests. On exhaustion the run stops cleanly and prints DEFERRED (budget): <cycles> to stderr; run again (or narrow --cycles) to finish.

Exit codes

Code Meaning
0 Success: the plan printed (dry-run), or apply completed with no failures.
1 Guardrail block: apply mode, at least one guardrail tripped, and --allow-guardrail-override was not set. For migrate --strict: error-severity findings remain.
2 Argument or config error (unknown flag, unknown cycle, unreadable or invalid config, missing auth).
3 Runtime error (API failure, an errored cycle, or failed apply entries).

In CI, that means: a dry-run job fails only on real errors, and an apply job fails loudly on a guardrail trip (1) or partial application (3). See CI.md.

Examples

# Plan everything against gitlab.com
gitlab-warden reconcile --config governance.yaml

# Apply only the flagship push-rule reconcile against self-managed
export GITLAB_TOKEN=glpat-…
gitlab-warden reconcile --config governance.yaml \
  --mode apply --cycles push-rules \
  --base-url https://gitlab.example.com

# Base URL and token both from the environment (CI-friendly)
gitlab-warden reconcile --config governance.yaml \
  --base-url-env CI_SERVER_URL --token-env WARDEN_TOKEN