feat(preflight): host/toolchain validation + VERSIONS pin-file — T01

- VERSIONS: 7 container images (CONTRACT_003 §3.2) + 13 host tools, KEY=value,
  source-able+greppable; images carry :PIN_DIGEST placeholders with a documented
  pin-digests procedure (D5 determinism — no real deploy until pinned).
- preflight.sh: fails closed (non-zero on any required check), bash-3.2 safe,
  composable checks/ (versions,tools,env,docker) + gated (ssh,dns) that WARN-skip
  until the stack is configured.
- env check honors D2 (passphrase presence only, never printed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Andreas Niemann 2026-06-30 18:00:26 +02:00
parent 188e30e23e
commit edc708b826
12 changed files with 763 additions and 0 deletions

View file

@ -0,0 +1,45 @@
# Task T01 — Pre-flight tooling + `VERSIONS` pin-file — Subtask Outline
**Mode:** BUILD (scaffolding only; no live VM touched — not HIGH-RISK/INFRA).
**Realizes:** PLAN-002 §10 T01, §9.1 (binary installation / host validation), baseline D5 (determinism).
**Contracts read:** CONTRACT_001 (config schema §1.1/§1.3), CONTRACT_003 (container/DNS §3.2).
## Restated task
Build the pre-flight validation tooling and the `VERSIONS` determinism pin-file for `olsitec-foundation`:
1. `foundation/VERSIONS` — pin every CONTRACT_003 §3.2 container image + every required host tool; `KEY=value`,
source-able + greppable; digest-pin form `image:tag@sha256:<digest>` with a documented `pin-digests`
procedure and a `PIN_DIGEST` placeholder where digests can't be resolved offline.
2. `foundation/preflight/preflight.sh` — orchestrates checks, PASS/FAIL summary, **exits non-zero on any
failure**; `set -euo pipefail`; macOS bash 3.2 + Linux compatible.
3. `foundation/preflight/checks/*.sh` — one composable script per concern.
## Checks implemented (one file per concern)
| Check | Concern | Gates exit code? |
|-------|---------|------------------|
| `versions.sh` | VERSIONS present, source-able, all required keys present; WARN on PIN_DIGEST | yes |
| `tools.sh` | every required tool present + version ≥ VERSIONS pin | yes |
| `env.sh` | `PULUMI_CONFIG_PASSPHRASE` set/non-empty (presence only, never printed — D2); `SSH_PRIVATE_KEY_PATH` (default `~/.ssh/id_rsa`) exists | yes |
| `docker.sh` | `docker info` succeeds (daemon reachable) | yes |
| `ssh.sh` | OPTIONAL/GATED: SSH reachability to `foundation:vm.host` — WARN-skip if no stack config | no |
| `dns.sh` | OPTIONAL/GATED: resolves `foundation:hosts.*` — WARN-skip if no stack config | no |
Shared helpers live in `preflight/lib/common.sh` (PASS/FAIL/WARN reporters, bash-3.2-safe numeric
version compare `pf_vercmp`/`pf_ge`, `pf_versions_get`).
## Assumptions
- **Tool list** is taken from the task scope: pulumi, bun, node, docker, git, age, zstd, jq, vault CLI,
postgresql client (psql + pg_dump), openssh client, S3/RustFS client (`mc`). CONTRACT_001/003 name the
*artifacts* but not an explicit tool floor list, so this scope list is authoritative (no contract conflict).
- **Tool minimums** in `VERSIONS` are conservative real-world floors (not exact host versions), so the
file is portable across operator workstation + CI without pinning to whatever happens to be installed here.
- **Image digests** cannot be resolved offline in this environment → every image carries the stable tag and
the `@sha256:PIN_DIGEST` placeholder. This is a WARNING, not a failure, at scaffold stage (honesty / PD-5).
- **Gated checks** depend on Pulumi stack config (`bootstrap/`) that does not meaningfully exist yet → they
detect absence and WARN-skip rather than fail (per task spec).
- Image tags chosen: caddy `2.10`, forgejo `codeberg.org/forgejo/forgejo:11`, postgres `17`,
hashicorp/vault `1.18`, rustfs `rustfs/rustfs:latest` (no stable semver — must digest-pin),
act_runner `code.forgejo.org/forgejo/runner:6`, `registry:2`. These are the pinnable identities; the
binding determinism guarantee is the digest, added by the pin-digests procedure when online.
## Out of scope (not touched)
`bootstrap/`, `packages/`, other components, any `pulumi up`, any secret material, git add/commit.