# CI Runner, Actions, And GitOps Ownership Last reviewed: 2026-06-07 Status: contract v1. This document defines ownership and handoffs only; it does not authorize a live runner deployment, credential change, GitOps controller change, or Gitea-to-Forgejo cutover. ## Purpose Railiance uses forge-hosted automation to build, test, publish, and verify workloads. The automation path crosses several repos, so this contract separates runner substrate, reusable workflow templates, app-specific checks, and GitOps operation. The short version: - `railiance-forge` owns the runner substrate and forge automation runtime. - `railiance-enablement` owns reusable workflow templates and paved paths. - Source and app repos own their repo-specific workflows and build scripts. - `railiance-apps` owns S5 app-release checks and deployment evidence. - Lower layers own the cluster, platform services, and runtime secret custody that runners consume through approved handoffs. ## Ownership Matrix | Concern | Owner | Contract | | --- | --- | --- | | Gitea/Forgejo Actions runner deployment and registration | `railiance-forge` | Defines how runners are installed, registered, upgraded, drained, replaced, and removed. | | Runner labels, placement, and capacity | `railiance-forge` | Publishes stable capability labels and placement rules. Consumers reference labels, not hostnames. | | Runner registration tokens and runtime credentials | `railiance-forge` with secret custody from `railiance-platform` | References secret names and approved delivery paths only; no decrypted values or tokenized URLs in Git. | | Reusable CI/CD and GitOps workflow templates | `railiance-enablement` | Defines generic build, test, publish, scan, promote, and GitOps review patterns that consume forge labels and credentials. | | App-specific workflows and build scripts | Source repo or app repo | Owns language build details, package metadata, image build definitions, and repo-local test behavior. | | S5 app-release dry-run checks | `railiance-apps` | Owns checks for app Helm charts, app values, app runbooks, and deployment guardrails. | | Runner prerequisites for S5 checks | `railiance-forge` plus lower-layer providers | Forge owns runner label and health evidence; cluster/platform own API reachability, CRDs, kubeconfig delivery, and secret custody. | | ArgoCD and GitOps controller operation | `railiance-cluster` for current addon operation, with patterns from `railiance-enablement` | Forge hosts source and executes checks, but does not own the desired state controller. | | Artifact publish evidence | `railiance-forge` | Captures source repo, commit SHA, artifact identity, package/image version, runner identity, and publish result. | | Deployment and smoke evidence | `railiance-apps` | Captures S5 manifest change, server-side dry-run result, deployment result, and app smoke result. | | Gitea-to-Forgejo automation cutover | `railiance-forge` | Preserves semantic runner labels and evidence contracts while moving the automation runtime. | ## Runner Label Contract Runner labels are the public interface between forge-owned substrate and workflow consumers. Labels should describe capability and trust level, not the machine that happens to run the job. Recommended label categories: - OS/runtime: `linux`, `container-runtime`. - Build capability: `container-build`, `python-build`, `node-build`. - Publication capability: `registry-publish`, `package-publish`. - Cluster access: `cluster-read`, `cluster-dry-run`. - Release posture: `s5-release-check`, `trusted-secrets`. Rules: - `railiance-forge` is the only repo that defines and changes the label contract. - `railiance-enablement` templates may require labels from this contract. - Source and app workflows may use labels only when the workflow purpose matches the capability. - Labels that imply secrets or cluster access require a named credential path and a human-reviewed purpose. - Workflow files should not hard-code runner hostnames, local paths, or registration-token details. ## Placement And Secret Access Runner placement is a security boundary. Treat a runner with publish credentials or cluster access as a privileged execution environment. - Registry/package publish jobs should run only on runners intended for trusted publication. - Server-side manifest dry-run jobs should run only on runners approved for representative cluster API access. - General build jobs should not receive cluster credentials or broad package publication tokens. - Production-like credentials must be scoped by repository, workflow purpose, and runner label wherever the forge supports that granularity. - Runner tokens should rotate when a runner is replaced, when a trust boundary changes, or during a Gitea-to-Forgejo cutover. - Documentation may reference secret names, SOPS files, OpenBao paths, and Kubernetes Secret names, but must not include live secret values. ## GitOps Boundary Forge automation is not the GitOps control plane. - `railiance-forge` hosts source, runs automation, and provides run/publish evidence. - `railiance-enablement` defines reusable GitOps workflow patterns, such as review gates, promotion conventions, and rollback evidence shape. - `railiance-apps` owns app deployment declarations and S5 release guardrails. - `railiance-cluster` currently owns ArgoCD addon operation until another reviewed workplan moves that responsibility. - `railiance-platform` owns shared runtime services consumed by GitOps-managed workloads. Automation should normally produce evidence and reviewed manifest changes. Direct runner-driven syncs against a live GitOps controller require a separate approval path because they couple CI credentials to deployment authority. ## S5 Server-Side Dry-Run Split The current S5 dry-run surface belongs in `railiance-apps`: - `.gitea/workflows/manifest-server-dry-run.yaml` - `make k8s-server-dry-run` - `tools/k8s-server-dry-run.sh` - app Helm charts and app values Forge-owned prerequisites: - a runner label such as `cluster-dry-run` or `s5-release-check`; - runner health evidence for that label; - documented placement and trust posture for runners with cluster reachability; - evidence that the runner can receive approved kubeconfig material without exposing live values in Git. Lower-layer prerequisites: - `railiance-cluster` provides a representative API server and installed CRDs. - `railiance-platform` provides approved secret delivery and shared service dependencies required by the manifests. If a workflow cannot find a runner with the required label or cannot access the representative cluster, the failure should be reported as a runner/prerequisite gap, not worked around inside the app chart. ## Gitea To Forgejo Cutover Path The cutover from current Gitea Actions to future Forgejo automation must keep the consumer contract stable. Minimum path: 1. Inventory current runners, labels, credentials, repository hooks, and workflows. 2. Define the Forgejo runner equivalent in `railiance-forge`. 3. Preserve semantic labels used by S4 templates and S5 checks unless a reviewed migration note announces a replacement. 4. Prove a non-production workflow can run on the new runner substrate. 5. Dual-run critical publish and dry-run checks where feasible. 6. Rotate registration tokens and publish credentials during the switchover. 7. Update forge evidence docs with the new runner identity and endpoint. 8. Retire the old Gitea runner only after downstream workflows no longer depend on it. This cutover does not move template ownership into forge and does not move app release checks out of S5. ## Minimum Evidence Before Enforcement Before a workflow template or S5 check treats a runner label as required, forge should provide: - runner inventory with labels, placement, and trust level; - credential scope notes by repository/workflow purpose; - a successful sample job for each privileged label; - package or image publish evidence for publication labels; - representative cluster dry-run evidence for cluster-access labels; - a rollback or disable path for a bad runner registration. ## Current Implementation Surface `docs/gitea-actions-runner-substrate.md` defines the first supported Gitea Actions runner model, the initial haskelseed compatibility labels, the attended registration path, and recovery steps. `make runner-status` provides the read-only probe entry point, and `.gitea/workflows/forge-runner-smoke.yaml` provides the first non-production proof workflow. The first compatibility labels are `self-hosted` and `haskelseed`, matching the inter-hub blocker. New workflow consumers should prefer semantic labels such as `linux`, `container-build`, and `registry-publish` once smoke evidence is recorded. ## Open Follow-Ups - `docs/observability-operating-evidence.md` defines the runner health and artifact evidence signals that consumers may cite. - `docs/gitea-actions-runner-evidence.md` records the current runner inventory, smoke evidence, and inter-hub unblock evidence. - WP-0006-T09 should declare runner substrate, label contracts, and evidence edges in Railiance Fabric. - `RAILIANCE-WP-0005-T05` should document app-side dry-run behavior once forge runner prerequisites are ready to enforce.