From 1d2462ddaf21330bbe242b9ca511155ca66ef67d Mon Sep 17 00:00:00 2001 From: Andreas Niemann Date: Tue, 30 Jun 2026 20:48:35 +0200 Subject: [PATCH] =?UTF-8?q?docs(session):=20SESSION=5F2026-06-30=5F001=20?= =?UTF-8?q?=E2=80=94=20state=20+=20Wave=202=20handoff?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- .../sessions/SESSION_2026-06-30_001.md | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 documentation/sessions/SESSION_2026-06-30_001.md diff --git a/documentation/sessions/SESSION_2026-06-30_001.md b/documentation/sessions/SESSION_2026-06-30_001.md new file mode 100644 index 0000000..03e4672 --- /dev/null +++ b/documentation/sessions/SESSION_2026-06-30_001.md @@ -0,0 +1,49 @@ +# Session 2026-06-30 #001 — Foundation bootstrap: contracts → live VM + DNS + offsite backup + +## What was done +- **T00** contracts CONTRACT_001–004 (+ amendment for `hosts.git`, `vm.sshPort`, `cloudflare.zoneId`). +- **T01** `preflight/` + `VERSIONS` (images carry `:PIN_DIGEST` placeholders — see gotchas). +- **T02** Bun-workspace + typed `config.ts` + vendored `@olsitec/pulumi-{docker,vault}`. +- **ADR-006 precursor**: shared Docker-over-SSH provider + `foundation-net` (`lib/context.ts`, + `components/network.ts`, phase-slotted `index.ts`). Composition = per-component factories, gates via `dependsOn`. +- **Phase-0 VM**: vendored `@olsitec/pulumi-hetzner`; `provision/` stack. Live: **cx33 Helsinki, + `204.168.234.72`**, Docker 29.6.1, **SSH port 222**, key `~/.ssh/foundation-test_ed25519`, firewall 222/80/443/2222. +- **Offsite backup**: `offsite-backup/` stack — bucket **`olsitec-foundation`** + scoped service account + on `minio.wob.olsitec.de:19000` (home Synology). Verified scoped (cross-bucket denied). +- **Steps 1+2**: real `olsitec.net` config + **DNS** `forge/vault/s3/git.olsitec.net → 204.168.234.72` + (verified authoritative; explicit A shadows the `*.olsitec.net` wildcard). `foundation-net` live on VM. + +## Current state +- Repo: `~/work/olsitec-foundation/foundation`. Latest commit `185be52`. Working tree clean. +- **Master passphrase** (the one external secret): `pass olsitec-foundation/PULUMI_CONFIG_PASSPHRASE`. +- Deploy the foundation: `cd bootstrap && ./run.sh up` (sets passphrase + `SSH_PRIVATE_KEY_PATH`). +- Stacks (all local file backends): `bootstrap` stack **foundation** (real passphrase); `provision` + stack **foundation-test** + `offsite-backup` stack **prod** (throwaway passphrase `dev-validation-throwaway`). +- Other creds: `pass olsicloud4/{HCLOUD_TOKEN,CLOUDFLARE_MASTER_TOKEN}`; MinIO admin via the + `wob-admin-external` mc alias (accessKey `admin`, NOT `pass MINIO_BACKUP_*` which is a different instance). + +## Next steps (Wave 2 → the goal: `git clone git@git.olsitec.net`) +Validate each live on the VM via `bootstrap/run.sh up` (images still unpinned → `FOUNDATION_ALLOW_UNPINNED=1` +or pin digests per `VERSIONS` header). Each component is a factory `components/.ts`, wired into the +`index.ts` phase slots (ADR-006). +1. **T03 postgres** · **T04 rustfs** (+ buckets) — data plane. +2. **T05 vault** — sealed container + init-capture (reuse `olsitec-core/run.sh` pattern → unseal keys to + `vaultCredentials:*` encrypted config) + passphrase-gated unseal helper (ADR-004). The hard one. +3. **T06 credentials** — `@pulumi/random` → Vault (CONTRACT_002 paths). +4. **T07 Caddy** — DNS-01 TLS; needs a **Cloudflare-enabled Caddy image** (build via xcaddy; standard + `caddy:2` lacks the DNS plugin). Token already in `foundation:cloudflareApiToken`. +5. **T08 Forgejo** — app.ini ← Postgres/RustFS/Vault; first admin headless; **org + repo** so + `git clone git@git.olsitec.net:olsitec/...` works (forgeSshPort 2222, published). +6. **T10 runner** · **T12 backup** (RustFS → replicate to the offsite `olsitec-foundation` bucket; + scoped creds already in `foundation:backup.offsite*`). + +## Risks / watchouts +- `Pulumi.foundation.yaml` self-quotes scalars + `encryptionsalt` is now **load-bearing** (decrypts 3 + committed secrets) — keep it committed; don't strip the salt anymore. +- VM SSH is **port 222**; the eventual real VM would be 22 (`vm.sshPort` handles it). +- `VERSIONS` images are `:PIN_DIGEST` + RustFS is `latest` — pin before treating as production. +- Don't run `pulumi up` against the production `olsicloud4-*` stacks. The home MinIO `.local` name is + LAN-only; the VM must use the public `minio.wob.olsitec.de:19000`. +- Everything is destroyable: `provision` (VM), `offsite-backup` (bucket+creds) via `pulumi destroy`. + +## Operating mode for next session: HIGH-RISK / INFRA (remote VM, Docker, secrets).