feat(bootstrap): forgejo actions runner (T10)

foundation-runner (forgejo/runner:6, digest-pinned). Registration is idempotent
(ADR-007): it reuses /data/.runner if present, else mints a token via
`forgejo actions generate-runner-token` and consumes it with `forgejo-runner
register` (the token never leaves the VM). The daemon runs as uid 1000 with the
host docker group (gid 996) added for socket access — root-equivalent and
co-located, the documented day-zero compromise (PLAN-002 R5 / PLAN-001 §4a); a
fenced or separate runner VM is the steady state.

Live on cx33 Helsinki: runner declared (labels docker,dind) and polling; a
hello-world `runs-on: docker` workflow pushed to olsitec/foundation ran to
success (workflow run #1). Acceptance T10 met.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Andreas Niemann 2026-06-30 22:38:37 +02:00
parent d5c53ce9a2
commit 9618da1421
3 changed files with 108 additions and 3 deletions

View file

@ -19,6 +19,7 @@ import { deployRustfs } from "./components/rustfs";
import { deployVault } from "./components/vault";
import { deployProxy } from "./components/proxy";
import { deployForgejo, bootstrapForgejo } from "./components/forgejo";
import { deployRunner } from "./components/runner";
import * as fs from "fs";
const cfg = loadConfig();
@ -70,18 +71,19 @@ const forgejoBootstrap = bootstrapForgejo(ctx, {
repoName: "foundation",
sshPublicKey,
});
// const runner = deployRunner(ctx, { forgejo, credentials });
const runner = cfg.features.runner ? deployRunner(ctx, forgejo) : undefined;
// =============================================================================
// Stack outputs (extended as phases land).
// vaultCreds (T06) is a gate for Forgejo (T08) — it has no output to export yet.
void vaultCreds;
export const phase = "T09-forge-bootstrap"; // admin + org + repo + operator key
export const phase = "T10-runner"; // forge + CI runner live
export const caddyImageId = proxy.imageId;
export const forgejoEndpoint = forgejo.endpoint;
export const cloneUrl = pulumi.interpolate`git@${cfg.hosts.git}:${cfg.forgejo.orgName}/foundation.git`;
void forgejoBootstrap; // GATE B consumer; no secret output to export
void runner; // CI runner (feature-flagged)
export const networkName = network.name;
export const vmTarget = `${cfg.vm.user}@${cfg.vm.host}`;
export const postgresEndpoint = postgres.endpoint;