# Centralized registry/host constants (oleks/ci-scripts#4) Woodpecker has no cross-repo variable store and no `include:` mechanism, so these constants can't be defined once and referenced by name inside raw YAML pipelines. Two real mechanisms exist instead — use whichever fits the value: 1. **Woodpecker secret or org secret** — for anything that's actually a credential, or that we want to be able to rotate without touching every repo's pipeline file. Prefer this whenever a value isn't public. 2. **Manifest field, interpolated by the oleks/ci-scripts generator** (`generator/render.py`, oleks/ci-scripts#2) — for values that are public infrastructure addresses baked into rendered YAML. Put the value in the per-repo manifest once; the generator stamps it into every rendered file. This is the practical stand-in for a "constants file" Woodpecker can't natively `include:`. There is no third option (a shared "constants.yaml" `include:`d by every pipeline) — Woodpecker pipelines are standalone YAML with no include directive, so the generator is the only place central substitution happens. ## Inventory | Constant | Value(s) | Where it's inlined today | Mechanism | |---|---|---|---| | Git server / netrc machine | `git.oleks.space` | every `clone:` block | manifest field `git_host` (rarely changes; secret would be overkill) | | Gitea clone token | — | every `clone:` block, `GITEA_CLONE_TOKEN` env | **secret** `gitea_clone_token` (org secret, already is one) | | Registry push token | — | matrix/manifest build steps | **secret** `registry_token` (org secret) | | Attic cache token | — | split (attic-closure) build steps | **secret** `attic_token` (org secret) | | Build image | `git.oleks.space/oleks/nix-ci:latest` / `:latest-arm64` | every build step's `image:` | manifest field `image` + arch suffix rule (generator appends `-arm64` for arm64 legs) | | BuildKit address | `tcp://buildkit-${ARCH}.infra.svc.cluster.local:1234`, `tcp://buildkit-rootless-${ARCH}.infra.svc.cluster.local:1234` | matrix-shape build/manifest steps | manifest field `buildkit_prefix` (`buildkit` or `buildkit-rootless`), arch interpolated by the generator | | Resolver nameserver | `169.254.20.10` | s390x cross-build pipelines (building/s390x, out of this worker's scope) | manifest field `nameserver` where the shape needs it; coordinate with fleet-worker (owns building/s390x + building/arm64) | | Kubernetes node selector overrides | e.g. `kubernetes.io/hostname: howard2404` (csi-s3, pinned to the only s390x/arm64-capable node) | matrix-shape `backend_options.kubernetes.nodeSelector` | manifest field `node_selector` (map, optional) | ## Convention going forward - If a value is secret-shaped (token, password, key) → it MUST be a Woodpecker secret, never a manifest field or literal in generated YAML. - If a value is public infrastructure (hostname, image ref, in-cluster service DNS name) that's the same across most repos → put it in the per-repo manifest consumed by `generator/render.py` (oleks/ci-scripts#2), not hand-typed into `.woodpecker/*.yaml`. - If a value is genuinely repo-specific (a one-off node pin, a nonstandard arch list) → it's still a manifest field, just not shared across repos. The manifest is the single place per-repo variance lives; the rendered YAML is never hand-edited (see the "GENERATED" header the generator stamps on every output file).