Define S1 reef rollout handoff
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 3s

This commit is contained in:
codex 2026-07-25 15:13:41 +02:00
parent 992e42a232
commit e176738fad
13 changed files with 256 additions and 39 deletions

View file

@ -169,10 +169,10 @@ get wrong.
Work items originate as files in this repo — not in the hub. The hub is a
read/cache/index layer that rebuilds from files.
**File location:** `workplans/RAILIANCE-WP-NNNN-<slug>.md`
**File location:** `workplans/RAIL-HO-WP-NNNN-<slug>.md`
**Archived location:** finished workplans may move to
`workplans/archived/YYMMDD-RAILIANCE-WP-NNNN-<slug>.md`. The `YYMMDD` prefix is
`workplans/archived/YYMMDD-RAIL-HO-WP-NNNN-<slug>.md`. The `YYMMDD` prefix is
the completion/archive date; the frontmatter `id` does not change.
**Ad Hoc Tasks:** small opportunistic fixes discovered during a session use
@ -184,7 +184,7 @@ anything needing analysis, design, approval, dependencies, or multiple phases.
```yaml
---
id: RAILIANCE-WP-NNNN
id: RAIL-HO-WP-NNNN
type: workplan
title: "..."
domain: financials
@ -208,7 +208,7 @@ derived health labels, not frontmatter statuses.
## Task Title
` ` `task
id: RAILIANCE-WP-NNNN-T01
id: RAIL-HO-WP-NNNN-T01
status: wait | todo | progress | done | cancel
priority: high | medium | low
state_hub_task_id: "<uuid>" # written by fix-consistency — do not edit

View file

@ -1,8 +1,18 @@
# RailianceHosts
# railiance-infra
**Tagline:** Git-driven automation for secure, self-reliant servers.
RailianceHosts is an open-source control repo that provisions and manages servers on Hosteurope and Hetzner Cloud entirely from Git. It combines **Terraform** for lifecycle management, **cloud-init** for first-boot configuration, and **Ansible** for convergence. All secrets live in-repo encrypted with **SOPS** and are unlocked with your single **age** master key (which you keep in your password manager). The minimal server registry in `inventory/servers.yaml` is the source of truth.
`railiance-infra` is the canonical S1 ownership repo for the Railiance
infrastructure substrate. It provisions and manages servers on HostEurope and
Hetzner Cloud entirely from Git. It combines **Terraform** for lifecycle
management, **cloud-init** for first-boot configuration, and **Ansible** for
convergence. All secrets live in-repo encrypted with **SOPS** and are unlocked
with your single **age** master key (which you keep in your password manager).
The minimal server registry in `inventory/servers.yaml` is the source of truth.
Future `reef-*` repos will model purpose-bound substrate boundaries such as
`reef-railiance01` or `reef-ops-workstations`, but the source-backed S1
inventory, hardening baseline, and OS convergence facts stay here.
## Quickstart
@ -19,13 +29,14 @@ RailianceHosts is an open-source control repo that provisions and manages server
First, clone this repository to your workstation:
```bash
git clone https://<your-gitea-host>/coulomb/railliance-hosts.git
git clone https://<your-gitea-host>/coulomb/railiance-infra.git
cd railiance-infra
```
## 📦 1. Prerequisites
To use RailianceHosts, make sure you have the following tools installed on your workstation:
To use `railiance-infra`, make sure you have the following tools installed on
your workstation:
- **Git** → for version control
- **age** → for key management and encryption ([Install guide](docs/age-keys.md))
@ -95,11 +106,9 @@ TL;DR
## 💻 5. Convergence
After provisioning a server with Terraform, RailianceHosts uses [Ansible](https://docs.ansible.com/) to **converge** hosts into a secure, baseline state.
After provisioning a server with Terraform, `railiance-infra` uses
[Ansible](https://docs.ansible.com/) to **converge** hosts into a secure,
baseline state.
This includes admin user setup, SSH hardening, firewall rules, essential tooling, and secret handling.
📖 See the full guide here: [Convergence Documentation](docs/convergence.md)
xxx

View file

@ -14,7 +14,14 @@ S1 Infrastructure Substrate of the Railiance OAS Stack — Git-driven OS provisi
## Core Idea
Railiance is structured as five independent repos per OAS Stack layer. This repo is S1 — the foundation. It provisions bare-metal/cloud servers (Hetzner, HostEurope), hardens the OS, manages secrets (SOPS/age), and validates the resulting baseline with Goss tests. S1 must be converged and verified before any higher layer (Kubernetes, platform, etc.) can run.
Railiance is structured as five independent repos per OAS Stack layer. This repo
is S1 — the foundation and the canonical ownership home for infrastructure
substrate facts. It provisions bare-metal or cloud servers (Hetzner,
HostEurope), hardens the OS, manages secrets (SOPS/age), and validates the
resulting baseline with Goss tests. Future `reef-*` repos will model
purpose-bound substrates, but the source-backed OS baseline, inventory, and
server identity facts start here. S1 must be converged and verified before any
higher layer (Kubernetes, platform, etc.) can run.
---
@ -28,6 +35,9 @@ Railiance is structured as five independent repos per OAS Stack layer. This repo
- Goss specification and test suite for OS baseline validation
- Server inventory management (`inventory/servers.yaml` — source of truth)
- SSH access management
- Canonical S1 identity and substrate-fact base for future `reef-*` repos
- Source-backed server and workstation substrate facts needed by higher-layer
architecture work
---
@ -37,6 +47,9 @@ Railiance is structured as five independent repos per OAS Stack layer. This repo
- Platform services → railiance-platform (S3)
- Developer tooling → railiance-enablement (S4)
- Application deployments → railiance-apps (S5)
- Workload execution semantics or rail contracts → `rail-*` repos
- Purpose-specific reef repo ownership and workload-placement policy beyond the
S1 source-backed substrate facts
- No cross-layer re-configuration from higher layers
---
@ -47,6 +60,7 @@ Railiance is structured as five independent repos per OAS Stack layer. This repo
- OS hardening, Ansible convergence, or Goss verification
- Managing server inventory or SSH access
- Rotating SOPS/age keys or updating secrets
- Preparing or validating first-wave `reef-*` rollout identity facts
---
@ -59,10 +73,14 @@ Railiance is structured as five independent repos per OAS Stack layer. This repo
## Current State
- Status: active / productive
- Implementation: single-server HostEurope baseline complete (RAIL-HO-WP-0001); server spec + test suite active (WP-0002); 5-repo stack restructure active (WP-0003)
- Stability: high for single-server bootstrap; proven in production (92.205.62.239)
- Usage: foundation for all Railiance deployments; used daily for convergence and verification
- Status: maintained / productive
- Implementation: HostEurope substrate baseline active for `Railiance01` and
`CoulombCore`; server spec + test suite active; 5-repo stack architecture in
place; first reef rollout source map now defined
- Stability: high for the current single-server and transitional two-server
substrate reality; proven in production on `92.205.62.239`
- Usage: foundation for all Railiance deployments; canonical S1 source for
higher-layer and future reef planning
---
@ -70,6 +88,8 @@ Railiance is structured as five independent repos per OAS Stack layer. This repo
- Upstream dependencies: Terraform, Ansible, SOPS/age (external tools); cloud provider APIs
- Downstream consumers: railiance-cluster (S2) depends on a converged, verified OS from this layer; all higher layers transitively depend on S1
- Future substrate-boundary consumers: first-wave `reef-*` repos should project
from the source-backed facts here rather than creating a second S1 inventory
- Often used with: railiance-cluster (next layer), ops-bridge (SSH tunnel for remote State Hub access)
---
@ -84,6 +104,8 @@ Railiance is structured as five independent repos per OAS Stack layer. This repo
## Related / Overlapping
- `railiance-cluster` (S2) — consumes the OS baseline provided by S1
- `railiance-hosts` — predecessor or migration-duplicate S1 line; not the
canonical repo for new architecture work
- `ops-bridge` — used to reach local State Hub from remote HostEurope server
---
@ -91,7 +113,10 @@ Railiance is structured as five independent repos per OAS Stack layer. This repo
## Getting Oriented
- Start with: `CLAUDE.md` (session protocol, remote execution), `README.md` (provisioning workflow)
- Key files / directories: `inventory/servers.yaml` (authoritative server list), `ansible/` (playbooks/roles), `terraform/` (provider configs), `goss/` (spec + tests), `docs/adr/ADR-003-railiance-5repo-stack-architecture.md`
- Key files / directories: `inventory/servers.yaml` (authoritative server
list), `ansible/` (playbooks/roles), `terraform/` (provider configs), `goss/`
(spec + tests), `docs/reef-first-wave-source-map.md`,
`docs/adr/ADR-003-railiance-5repo-stack-architecture.md`
- Entry points: `make tf-plan`, `make tf-apply`, `make converge`, `make verify`
---
@ -123,4 +148,8 @@ keywords: [sops, age, secrets, encryption, gitops, key-rotation, credential]
## Notes
Targets two servers: COULOMBCORE (92.205.130.254) and Railiance01 (92.205.62.239). State Hub access via ops-bridge — `bridge up state-hub-coulombcore` or `bridge up state-hub-railiance01` from the workstation (see ADR-004).
Targets two current server substrates: `CoulombCore` (`92.205.130.254`) and
`Railiance01` (`92.205.62.239`). The first-wave reef rollout also recognizes a
grouped operator workstation substrate. State Hub access uses ops-bridge —
`bridge up state-hub-coulombcore` or `bridge up state-hub-railiance01` from the
workstation (see ADR-004).

View file

@ -9,7 +9,7 @@
| Kind | ID | Status | Lane | Source |
| --- | --- | --- | --- | --- |
| workplan | RAIL-HO-WP-0006 | finished | — | workplans/RAIL-HO-WP-0006-forgejo-registry-ref-cleanup.md |
| workplan | RAIL-HO-WP-0007 | ready | — | workplans/RAIL-HO-WP-0007-first-reef-rollout-and-s1-canonicalization.md |
| workplan | RAIL-HO-WP-0007 | finished | — | workplans/RAIL-HO-WP-0007-first-reef-rollout-and-s1-canonicalization.md |
| task | RAIL-HO-WP-0006-T01 | done | — | workplans/RAIL-HO-WP-0006-forgejo-registry-ref-cleanup.md |
| task | RAIL-HO-WP-0006-T02 | done | — | workplans/RAIL-HO-WP-0006-forgejo-registry-ref-cleanup.md |
| task | RAIL-HO-WP-0006-T03 | done | — | workplans/RAIL-HO-WP-0006-forgejo-registry-ref-cleanup.md |
@ -19,7 +19,7 @@
| task | RAIL-HO-WP-0006-T07 | done | — | workplans/RAIL-HO-WP-0006-forgejo-registry-ref-cleanup.md |
| task | RAIL-HO-WP-0006-T08 | done | — | workplans/RAIL-HO-WP-0006-forgejo-registry-ref-cleanup.md |
| task | RAIL-HO-WP-0006-T09 | done | — | workplans/RAIL-HO-WP-0006-forgejo-registry-ref-cleanup.md |
| task | RAIL-HO-WP-0007-T01 | todo | — | workplans/RAIL-HO-WP-0007-first-reef-rollout-and-s1-canonicalization.md |
| task | RAIL-HO-WP-0007-T02 | todo | — | workplans/RAIL-HO-WP-0007-first-reef-rollout-and-s1-canonicalization.md |
| task | RAIL-HO-WP-0007-T03 | todo | — | workplans/RAIL-HO-WP-0007-first-reef-rollout-and-s1-canonicalization.md |
| task | RAIL-HO-WP-0007-T04 | wait | — | workplans/RAIL-HO-WP-0007-first-reef-rollout-and-s1-canonicalization.md |
| task | RAIL-HO-WP-0007-T01 | done | — | workplans/RAIL-HO-WP-0007-first-reef-rollout-and-s1-canonicalization.md |
| task | RAIL-HO-WP-0007-T02 | done | — | workplans/RAIL-HO-WP-0007-first-reef-rollout-and-s1-canonicalization.md |
| task | RAIL-HO-WP-0007-T03 | done | — | workplans/RAIL-HO-WP-0007-first-reef-rollout-and-s1-canonicalization.md |
| task | RAIL-HO-WP-0007-T04 | done | — | workplans/RAIL-HO-WP-0007-first-reef-rollout-and-s1-canonicalization.md |

View file

@ -107,6 +107,15 @@ If everything works, you are ready to store secrets securely in Git.
## 🔑 Secrets Handling Digest
In RailianceHosts, **age private keys never leave your workstation**. Secrets in the repo are encrypted to one or more **public keys** listed in `.sops.yaml`. To decrypt, you either load your private key into the environment (`SOPS_AGE_KEY`) or keep it in your local `~/.config/sops/age/keys.txt` (never in Git). Ansible and Terraform decrypt files only on the control machine, so plaintext is injected at runtime but never stored on servers. For teams, simply add multiple public keys as recipients; each operator decrypts with their own private key. In CI/CD, the private key is injected securely as a secret variable. This ensures encryption is repo-wide and portable, while private keys remain personal, local, and outside version control.
In `railiance-infra`, **age private keys never leave your workstation**.
Secrets in the repo are encrypted to one or more **public keys** listed in
`.sops.yaml`. To decrypt, you either load your private key into the environment
(`SOPS_AGE_KEY`) or keep it in your local `~/.config/sops/age/keys.txt` (never
in Git). Ansible and Terraform decrypt files only on the control machine, so
plaintext is injected at runtime but never stored on servers. For teams, simply
add multiple public keys as recipients; each operator decrypts with their own
private key. In CI/CD, the private key is injected securely as a secret
variable. This ensures encryption is repo-wide and portable, while private keys
remain personal, local, and outside version control.
✅ Thats it — your secrets are now protected with your own master key.

View file

@ -1,6 +1,7 @@
# 🔧 Server Convergence
After provisioning servers with Terraform, RailianceHosts uses **Ansible** to bring them into a secure and usable baseline state.
After provisioning servers with Terraform, `railiance-infra` uses **Ansible**
to bring them into a secure and usable baseline state.
This process is called **convergence**.
## What Convergence Does

View file

@ -1,4 +1,4 @@
# 🚀 Provisioning Servers with RailianceHosts
# 🚀 Provisioning Servers with railiance-infra
This guide explains **where you declare servers**, **how Terraform uses that declaration**, and **how to provision** (and later destroy) machines on Hetzner.

View file

@ -0,0 +1,150 @@
# First-Wave Reef Source Map
Date: 2026-07-25
## Purpose
Prepare the S1 source-backed handoff for the first reef rollout without turning
`railiance-infra` into a second reef repo family.
This document records:
- why `railiance-infra` is the canonical S1 source for reef creation
- which substrate facts are already stable enough to seed the first reefs
- which labels or future interpretations must remain provisional
This follows
`/home/worsch/railiance-master/docs/reef-first-wave-rollout.md`.
## Canonical S1 Stance
For future architecture work:
- `railiance-infra` is the canonical S1 ownership repo
- `railiance-hosts` is a predecessor or compatibility duplicate, not a second
authority for new reef planning
- future `reef-*` repos should project from the source-backed facts here rather
than recreate their own incompatible substrate inventories
Practical rule:
- use `inventory/servers.yaml` as the starting identity source for server reefs
- use S1 docs and operator-runbook facts for grouped workstation reefs
- treat legacy `railiance-hosts` references in historical ADRs, inbox evidence,
and archived workplans as historical context, not as current authority
## Stable Source Files
The current first-wave reef rollout should anchor on these files:
- `inventory/servers.yaml`
- `ansible/inventory/host_vars/CoulombCore.yml`
- `docs/deploy-stack.md`
- `docs/age-keys.md`
- `docs/adr/ADR-003-railiance-5repo-stack-architecture.md`
- `docs/adr/ADR-004-forgejo-in-cluster-actions-runner.md`
These files are not a complete future reef schema, but they already provide the
minimum operational facts needed to seed the first reef repos.
## First-Wave Reef Source Map
### `reef-railiance01`
Stable facts available now:
- server identity: `Railiance01`
- IP: `92.205.62.239`
- SSH user: `tegwick`
- authoritative source today: `inventory/servers.yaml`
- current role in the ecosystem: the clearest home for new Kubernetes-first
production-oriented workloads
- operational evidence in this repo: ADR-004 records Forgejo production and
Actions runner placement on `railiance01`
- primary rail stance for first rollout: `rail-kubernetes`
Known gaps that must stay explicit:
- no dedicated `host_vars/Railiance01.yml` exists yet
- the long-term grouped-home-reef shape is not decided yet
- whether later `rail-knative` shares this reef or warrants separation remains
a workload- and security-driven decision
### `reef-coulombcore`
Stable facts available now:
- server identity: `CoulombCore`
- IP: `92.205.130.254`
- SSH user: `tegwick`
- authoritative source today: `inventory/servers.yaml`
- host-specific S1 operational facts already recorded in
`ansible/inventory/host_vars/CoulombCore.yml`
- `docs/deploy-stack.md` still treats CoulombCore as an active operator access
and execution point for convergence and stack bring-up
- ops-bridge naming already distinguishes `state-hub-coulombcore`
Operational interpretation for rollout:
- create it as a transitional reef
- keep mixed-purpose and fallback realities visible instead of pretending it is
already the preferred long-term home
### `reef-ops-workstations`
Stable facts available now:
- this is a grouped substrate class, not a permanent singleton machine
- age private keys stay on operator workstations; see `docs/age-keys.md`
- ops-bridge and attended control-plane access originate from the workstation;
see `docs/deploy-stack.md`
- kubeconfig use, SSH key custody, and attended control actions are currently
workstation responsibilities rather than server responsibilities
Operational interpretation for rollout:
- model this as operator or edge compute
- keep machine membership inside reef-local topology rather than creating one
repo per laptop
## Stable Facts Versus Provisional Labels
Stable now:
- the first-wave reef set:
- `reef-railiance01`
- `reef-coulombcore`
- `reef-ops-workstations`
- `railiance-infra` as canonical S1 ownership source
- inventory-backed server identity for `Railiance01` and `CoulombCore`
- operator workstation responsibilities for age key custody, bridge usage, and
attended control-plane actions
- `rail-kubernetes` as the first primary rail stance for `reef-railiance01`
Provisional for now:
- whether `reef-railiance01` later widens into a grouped `reef-railiance-home`
- whether `rail-knative` should share `reef-railiance01` or later move to a
separate reef
- narrative labels such as "associate", "sidecar", or "comet"
- any claim that CoulombCore has a settled long-term role beyond being an
active transitional substrate
## Handoff For First Reef Creation
Each first-wave reef repo should start with:
- substrate identity from the source-backed facts above
- declared substrate kind:
- `server` for `reef-railiance01`
- `server` for `reef-coulombcore`
- `workstation-group` for `reef-ops-workstations`
- lifecycle stance:
- primary home-reef seed for `reef-railiance01`
- transitional legacy or fallback reef for `reef-coulombcore`
- grouped operator-edge reef for `reef-ops-workstations`
- initial primary rail statement where applicable
- explicit unresolved questions instead of invented certainty
That is enough to create the first reef repos without reopening the
`railiance-hosts` versus `railiance-infra` ambiguity.

View file

@ -1,6 +1,8 @@
# 🔑 SSH Access & Connectivity Test
RailianceHosts provisions Hetzner servers with your SSH key so you can log in securely (no passwords). Follow these steps to add your key and verify access.
`railiance-infra` provisions Hetzner servers with your SSH key so you can log
in securely (no passwords). Follow these steps to add your key and verify
access.
---

View file

@ -1,6 +1,6 @@
# Server Verification
RailianceHosts ships a declarative baseline spec and a Goss test suite that
`railiance-infra` ships a declarative baseline spec and a Goss test suite that
asserts every managed node matches it. This replaces manual spot-checks with
a reproducible, CI-friendly pass/fail verdict.

View file

@ -1,6 +1,6 @@
# Railiance Managed Node — Baseline Server Specification
# This file is the authoritative source of truth for the target state of every
# server managed by railiance-hosts. All convergence roles and test assertions
# server managed by railiance-infra. All convergence roles and test assertions
# MUST be derivable from this document.
#
# When you change something here, update the Ansible roles AND the Goss tests.

View file

@ -18,7 +18,7 @@ summary: "..."
detail: {}
status: pending # → ingested after processing
recorded_at: "YYYY-MM-DD"
source_repo: railiance-hosts
source_repo: railiance-infra
```
## Drain procedure (manual until automated)

View file

@ -4,7 +4,7 @@ type: workplan
title: "First reef rollout and S1 canonicalization"
domain: financials
repo: railiance-infra
status: ready
status: finished
owner: codex
topic_slug: railiance
created: "2026-07-25"
@ -42,7 +42,7 @@ It must not:
```task
id: RAIL-HO-WP-0007-T01
status: todo
status: done
priority: high
state_hub_task_id: "e162235f-b4c1-42fb-ae17-23f698a8ad3f"
```
@ -54,11 +54,16 @@ canonical.
Done when the repo has an explicit cleanup or freeze direction for the duplicate
S1 line.
2026-07-25: Recorded `railiance-infra` as the canonical S1 ownership repo in
`SCOPE.md`, `README.md`, and `docs/reef-first-wave-source-map.md`, while
leaving historical `railiance-hosts` references in superseded ADRs and archived
records as non-authoritative context.
## T02 - Prepare substrate identity data for the first reefs
```task
id: RAIL-HO-WP-0007-T02
status: todo
status: done
priority: high
state_hub_task_id: "aa32fb8d-adab-41d3-bb8d-13167df7cc44"
```
@ -72,11 +77,16 @@ Prepare the minimum substrate identity and topology data needed for:
Done when the future reefs have a clear source-backed S1 starting point for
identity, membership, and lifecycle context.
2026-07-25: Added `docs/reef-first-wave-source-map.md`, which extracts the
current S1 identity and lifecycle starting facts for `reef-railiance01`,
`reef-coulombcore`, and `reef-ops-workstations` from live inventory, host vars,
and runbook sources.
## T03 - Separate stable substrate facts from transitional labels
```task
id: RAIL-HO-WP-0007-T03
status: todo
status: done
priority: medium
state_hub_task_id: "f5d58dc6-5086-4cc7-9282-d15a6eb51549"
```
@ -87,23 +97,30 @@ transitional nicknames or legacy interpretations must remain provisional.
Done when the future reef repos can start from stable operational facts instead
of from narrative labels.
2026-07-25: The new reef source map now separates stable source-backed facts
from provisional labels such as future grouped-home-reef interpretations or
nickname taxonomies like "associate", "sidecar", and "comet".
## T04 - Prepare the first reef creation handoff
```task
id: RAIL-HO-WP-0007-T04
status: wait
status: done
priority: medium
state_hub_task_id: "0297092c-556d-42f0-bd9d-283db0f375dd"
```
Blocked on T01-T03.
Prepare the handoff for creating the first reef repos and for reducing the S1
duplication risk during that rollout.
Done when the first reef repos can be created without reopening the
`hosts`-versus-`infra` ambiguity.
2026-07-25: `docs/reef-first-wave-source-map.md` now provides the initial reef
creation handoff: source-backed identity, substrate kind, lifecycle stance,
primary rail stance where applicable, and explicit unresolved questions for
each first-wave reef.
## Notes
This workplan is repo-local. The framework-level reef decision and sequencing