# 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:` 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.