docs: software factory README, server reference, architecture, RUNBOOK

This commit is contained in:
2026-09-18 20:00:28 +02:00
committed by Lukas Greve
parent f2ea8a8f04
commit 1c6d9e064c
3 changed files with 252 additions and 0 deletions
+82
View File
@@ -0,0 +1,82 @@
# Software factory architecture
GitHub-style CI for Phyllome OS, self-hosted on the project's own forge and
iron.
## Goal
Runs CI/CD for Phyllome OS repos on `git.phyllo.me` (Gitea + Gitea Actions)
with a self-hosted runner, without depending on any third-party CI service.
## Components
```mermaid
flowchart LR
subgraph forge["git.phyllo.me (Cloudron app, Gitea 1.40.2)"]
act[Gitea Actions]
pkg[(Package Registry)]
rel[Releases]
end
subgraph runbox["runner VM (on the phyllome Cloudron host)"]
r1[act_runner daemon]
host[HOST labels: run-on-host jobs<br>mock / livemedia-creator / pykickstart]
img[CONTAINER labels:<br>docker://git.phyllo.me/devops/fedora-runner-image]
end
repo[Product repos: roots/* , devops/*]<br>.gitea/workflows/*.yml → runs-on: fedora
dev[devcontainer git.phyllo.me/roots/fedora-iso-creation:42]
repo --> act
act -->|picks runner| r1
r1 --> host
r1 --> img
act --> pkg
act --> rel
dev --> act
```
## How a run works
1. A push/PR/tag to a Product repo triggers Gitea Actions.
2. `runs-on: fedora` matches the self-hosted runner labeled `fedora`.
3. Two execution modes, chosen per job:
- **container** — steps run inside `devops/fedora-runner-image` (clean,
hermetically sealed; good for pure build/lint/test jobs).
- **host** — steps run directly on the runner VM (needed for jobs that rely
on `mock`/QEMU nesting, kernel-level features, or the local build cache).
4. Steps use the mirrored actions (`devops/checkout@v5`,
`devops/action-gh-release@v2`) so nothing reaches out to github.com at
runtime.
## Products and their pipelines
| Repo | Pipeline | Job type | Notes |
|---|---|---|---|
| `roots/phyllomeos` | `make lint``make test``make validate` | container | pykickstart data pipeline; generated recipes/dishes are untracked build products |
| `roots/xml-definition-for-domains` | xmllint check | container | libvirt XML definitions |
| `roots/rpm-sources` | mock smoke build | host | needs mock chroots (host-only cache) |
| `devops/create-iso` | mock + livemedia-creator ISO build → release | host | already has a workflow (label `fedora`) |
| `devops/test-actions` | checkout smoke tests | both | CI playground, already label `fedora` |
## Image inventory (Package Registry)
| Image | Used by |
|---|---|
| `devops/fedora-runner-image:latest` | default job container on the runner |
| `devops/fedora-oci` | base Fedora image |
| `devops/qemu-libvirt-oci-image` | QEMU/libvirt tooling (VM-in-CI experiments) |
| `roots/fedora-iso-creation:42` | devcontainer referenced by test workflows |
## Security posture
- **Self-contained actions**: all `uses:` point at `git.phyllo.me/...` mirrors —
no third-party action code, no github.com calls.
- **Runner host**: dedicated VM on the phyllome Cloudron host; `act_runner`
runs as unprivileged `act_runner` system user; Docker access for container
jobs only.
- **Secrets**: CI secrets live in Gitea (repo/org) — never in the runner config.
Registration token is UI-generated and consumed once.
- **Read-only infra automation**: the `automation` repo's MCP servers scope
Cloudron/Gitea reads and writes by credential pair (read token / write token),
and opencode gates writes behind a dedicated `ops` agent.
+63
View File
@@ -0,0 +1,63 @@
# Phyllome Cloudron server (`my.phyllo.me`)
The Phyllome OS project's Cloudron platform. This is the *project* infrastructure
server — distinct from the home-LAN Cloudron (`my.lesloutres.ch`, see the
`inventory-of-devices` repo, which is personal-resource scoped and intentionally
does **not** document this box).
## At a glance
| Field | Value |
|---|---|
| Platform | Cloudron **10.0.5** |
| Admin URL | `https://my.phyllo.me` |
| Host OS | Ubuntu (managed by Cloudron installer) |
| Location | Not on the home LAN — out-of-LAN host; public DNS via IPv6 (`2001:41d0:1008:44d::1`) + the box behind the project's hosting |
| DNS provider | Gandi (PAT, `phyllo.me` + `phyllome.org`) |
| TLS | Let's Encrypt, wildcard (production `letsencrypt-prod`) |
| Domains | `phyllo.me`, `phyllome.org` |
| Backup | Cloudron box + app backups nightly; cleanup job keeps a rolling window (see event log `backup.cleanup.finish`) |
Remote-management interfaces:
- **Cloudron API / UI** — `cloudron-phyllome` (read) and `cloudron-phyllome-write`
(write) MCP servers from the `automation` repo.
- **Gitea forge** — `git.phyllo.me`, Gitea **1.40.2** app (id `io.gitea.cloudronapp`).
Read via `gitea-phyllome`, write via `gitea-phyllome-write`. Git-over-SSH on
port **29418** (e.g. `ssh://git@git.phyllo.me:29418/owner/repo.git`).
## Apps
Cloudron app inventory on this box (subset relevant to the factory):
| FQDN | App | State | Role in the factory |
|---|---|---|---|
| `git.phyllo.me` | Gitea | running | Code host + Gitea Actions bus |
| `minio.phyllo.me` (+ `minio-api.phyllo.me`) | MinIO | running | S3 object storage (factory artifact staging candidate) |
| `kanboard.phyllo.me` / `kanboard.phyllome.org` | Wekan | running / stopped (preprod dup) | Project kanban |
| `wiki.phyllo.me` / `wiki.phyllome.org` | Wiki.js | running / stopped | Docs (live = wiki.phyllome.org) |
| `llamas.phyllo.me` | Open WebUI | stopped | AI chat (on demand) |
| `ks.phyllome.org` | Kutt | stopped | URL shortener (preprod) |
| `phyllo.me`, `www.phyllo.me` | Grav | running | Project website |
Full inventory is one `cloudron-phyllome_list_apps` call away; this file only
documents what the factory depends on.
## Factory-relevant services
- **Package registry** (Gitea Packages) holds the container images:
- `devops/fedora-runner-image` (with `latest`) — runner job container
- `devops/fedora-oci`, `devops/qemu-libvirt-oci-image` — builder images
- `roots/fedora-iso-creation:42` — devcontainer referenced by test-actions
- **Gitea Actions** is enabled on the product repos.
- **Runners**: none registered yet → see `RUNBOOK.md`. Expected label: `fedora`.
## Access model
- `git.phyllo.me` user `lukas` (id 4, **not** Gitea admin) — used by the read and
write API tokens.
- Runner registration requires a **runner registration token** from the Gitea UI
(Settings → Actions → Runners) — admin/owner action, see RUNBOOK.
- Cloudron ownership is via an OIDC/owner account `superuser@phyllo.me`; API
tokens (`tower-read`, `tower`, …) are created/deleted via the Cloudron UI
(visible in the event log).