feat: provision Alpine LXC 136 running Atheos, wired to Gitea

Provisions a LAN-only browser code editor (Atheos) in an Alpine 3.23 LXC on the
scotty PVE node, with armistace/blog cloned and ready to edit. Built via the
AI-DLC workflow; the full process trail is in aidlc-docs/.

Deliverables
- scripts/provision.sh          rebuild the guest from scratch (re-runnable)
- scripts/update-atheos.sh      move Atheos to latest upstream and RE-PIN
- scripts/build-and-test.sh     captures evidence for every acceptance criterion
- files/atheos.conf             nginx vhost (socket path byte-matches the FPM pool)
- files/ssh-config              ~atheos/.ssh/config deploy-key alias
- RUNBOOK.md                    operational guide (START AT STEP 1)
- docs/security-notes.md        credential model + wider-web hardening TODOs
- docs/resiliency-notes.md      what a non-PoC deployment would need

Design decisions
- D1 no git identity is configured by the agent; the operator sets it. Git will
  refuse the first commit until then, which is deliberate (requirement FR-11).
- D2 Atheos pinned to commit f90cd18 (build 611) with a verified tarball sha256,
  plus update-atheos.sh as the deliberate escape hatch.
- D3 nginx :80, web root /var/www/atheos, php-fpm over a unix socket.
- D6 git auth is a per-repository DEPLOY KEY scoped to armistace/blog, not a
  personal access token (a PAT's write:repository scope reaches every repo the
  account can write).

Verified on the live guest (40 checks, 0 failures)
- AC-2  Atheos served over HTTP 200 by nginx+php-fpm; socket paths byte-match
- AC-3  20 posts + themes/cleanblog present; owned by the php-fpm user
- AC-4  all five writable paths writable as the service user
- AC-5  remote targets armistace/blog; deploy key authenticates over SSH
- AC-6  survival proven with a real container restart, marker byte-identical
- AC-8  no python/pelican/pip/make and no DB engine - scope boundary enforced
- FR-11 git identity is empty; deploy key mode 600 owned by the service user

Traps documented in the RUNBOOK (each cost real debugging time)
- The Gitea SSH user is `gitea`, NOT `git` (app.ini SSH_USER=gitea). With `git`,
  sshd answers "Invalid user git" and rejects before reading authorized_keys,
  which is indistinguishable from a bad key.
- The Gitea SSH endpoint is the LAN address (:22 is not forwarded publicly).
- `uptime` and `free` report the PVE HOST inside an LXC without lxcfs, so a
  container that just restarted can claim days of uptime.
This commit is contained in:
2026-09-29 15:44:11 +10:00
commit c2897ed660
26 changed files with 2333 additions and 0 deletions
@@ -0,0 +1,75 @@
# Application Design Plan — atheos-blog-lxc
**Stage**: INCEPTION — Application Design (**minimal depth**)
**Date**: 2026-09-29
## Rationale for minimal depth
There is no application code to design — this project provisions a guest and installs an existing
PHP application. "Application Design" here means recording the **runtime component map and its
interfaces**, so that (a) the unit boundaries are defensible and (b) a later agent inheriting the
repo can see how the pieces talk to each other without re-deriving it.
## Plan (checkboxes)
- [ ] Generate `components.md` — component definitions + responsibilities
- [ ] Generate `component-methods.md` — the *interfaces* between components (not business logic)
- [ ] Generate `services.md` — orchestration / request flow
- [ ] Generate `component-dependency.md` — dependency matrix + data flow
- [ ] Generate `application-design.md` — consolidated design
- [ ] Validate design completeness and consistency
## Design questions
Most design decisions were already fixed in requirements.md. Below is the one that is genuinely
open, plus two where I state my decision so you can veto it rather than having to choose blind.
---
### Q1 (genuine — blocks U4) — what git committer identity should Atheos use?
Atheos's git integration commits as a configured user. You told me you'll own the `armistace`
credentials (**FR-11** — I must not create them). But `git` will refuse to commit at all without
*some* identity, so leaving it entirely unset risks a broken first commit for you.
- **A)** Set a **neutral non-armistace** identity, e.g. `Atheos <atheos@atheos.local>`, purely so
commits don't hard-fail; **you** override it with your own identity when you set up credentials.
*(Recommended — leaves the tool working without impersonating you.)*
- **B)** Set **nothing at all** — leave `user.name`/`user.email` unset, and the RUNBOOK tells you to
set them as your first action after SSH-ing in. *(Purest reading of FR-11; first commit fails until you do.)*
- **C)** Use a **placeholder under your name** (e.g. `armistace <ar17787@gmail.com>`) so commits are
attributed to you out of the box. *(Note: this creates an armistace identity, which is what FR-11
says I should not do — only pick this if you want to override that.)*
- **X)** Other (describe after the tag)
`[Answer]:`
---
### Q2 (decision stated — veto if wrong) — pin Atheos to a specific upstream commit
Upstream Atheos is an actively-moving master branch with no releases. For a reproducible
re-provision (FR-9), I propose pinning to a **specific verified commit SHA** resolved at build
time and recorded in the script + RUNBOOK, rather than tracking `master`.
`[Answer]:` *(leave blank to accept)*
---
### Q3 (decision stated — veto if wrong) — where things live
- Web root: `/var/www/atheos` (Atheos app)
- Atheos workspace: `/var/www/atheos/workspace` → this is where `blog` is cloned
- nginx listens on **:80**, `root /var/www/atheos`, `index index.php`
- php-fpm via **unix socket** (`/run/php-fpm83/...`) — not a TCP port, so nothing extra listens on the LAN
`[Answer]:` *(leave blank to accept)*
---
## Assumptions carried
- Atheos is served at the **site root** (`http://<ip>/`), not a subdirectory.
- The operator completes Atheos's first-run installer in the browser (creates the admin user);
the agent seeds neither the admin nor any Atheos user.
- `blog` is pre-cloned into `workspace/` so it appears as a ready-to-open project (your Q6).