chore: bootstrap cc-ci loop state
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
# local secrets / env — never commit
|
||||
.testenv
|
||||
*.key
|
||||
*.pem
|
||||
!docs/**/*.pem
|
||||
# python
|
||||
__pycache__/
|
||||
*.pyc
|
||||
.venv/
|
||||
.pytest_cache/
|
||||
# run-scoped ephemeral state (per §4.4 sidecars)
|
||||
runs/
|
||||
# nix
|
||||
result
|
||||
result-*
|
||||
62
BACKLOG.md
Normal file
62
BACKLOG.md
Normal file
@ -0,0 +1,62 @@
|
||||
# BACKLOG — cc-ci
|
||||
|
||||
Two single-writer sections (§6.1): Builder edits only `## Build backlog`; Adversary edits only
|
||||
`## Adversary findings`. Closing an item = checking the box in your own section.
|
||||
|
||||
## Build backlog
|
||||
|
||||
### M0 — Foundations
|
||||
- [ ] Author flake.nix (NixOS host cc-ci) + hosts/cc-ci/{configuration,hardware}.nix from baseline
|
||||
- [ ] Deploy mechanism decision + first rebuild from repo (DECISIONS.md)
|
||||
- [ ] sops-nix wiring: host age key, secrets/secrets.yaml, decrypt a test secret on host
|
||||
- [ ] Gate: M0 — `ssh cc-ci 'systemctl is-system-running'` healthy after rebuild from repo
|
||||
|
||||
### M1 — Swarm + abra target
|
||||
- [ ] Docker + single-node swarm via Nix
|
||||
- [ ] Traefik (file provider → /var/lib/ci-certs/live/) + per-run wildcard router
|
||||
- [ ] abra installed; deploy + tear down a trivial recipe by hand over HTTPS
|
||||
- [ ] Gate: M1 — recipe reachable over HTTPS at *.ci.commoninternet.net, torn down clean
|
||||
|
||||
### M2 — Drone online
|
||||
- [ ] Drone server + exec runner via Nix; Gitea OAuth app
|
||||
- [ ] hello-world .drone.yml runs green; logs in Drone UI
|
||||
- [ ] Gate: M2 — push to cc-ci triggers visible green build
|
||||
|
||||
### M3 — Comment bridge
|
||||
- [ ] comment-bridge service: HMAC verify, !testme exact match, collaborator check, Drone API call
|
||||
- [ ] PR comment posting with run link
|
||||
- [ ] Gate: M3 — live demo on scratch PR; auth enforced
|
||||
|
||||
### M4 — Harness + install stage
|
||||
- [ ] run_recipe_ci.py + conftest; install stage for recipe #1 + Playwright assertion; teardown
|
||||
- [ ] Gate: M4 — green install run, no orphaned app/volume
|
||||
|
||||
### M5 — Upgrade + backup/restore stages
|
||||
- [ ] Add upgrade + backup/restore stages for recipe #1
|
||||
- [ ] Gate: M5 — upgrade preserves data; backup→mutate→restore returns original
|
||||
|
||||
### M6 — Recipe-local tests + second recipe
|
||||
- [ ] Discover/run recipe-repo tests/; enroll DB-backed recipe #2
|
||||
- [ ] Gate: M6 — both green; recipe-local tests merged
|
||||
|
||||
### M6.5 — Breadth ramp (recipes 3→6)
|
||||
- [ ] Enroll recipes 3–6 covering remaining D10 categories, no harness surgery
|
||||
- [ ] Gate: M6.5 — recipes 3–6 three-stage green
|
||||
|
||||
### M7 — Secrets hardening (D6)
|
||||
- [ ] Full sops model, rotation doc, log redaction + leak test
|
||||
- [ ] Gate: M7 — secret-grep finds nothing
|
||||
|
||||
### M8 — Dashboard (D7)
|
||||
- [ ] Overview page + badges + PR-comment outcome reflection
|
||||
- [ ] Gate: M8 — overview matches reality; outcomes mirrored
|
||||
|
||||
### M9 — Reproducibility + docs (D8/D9)
|
||||
- [ ] docs/install.md from-scratch rebuild; all docs complete
|
||||
- [ ] Gate: M9 — Adversary rebuilds from docs on throwaway host
|
||||
|
||||
### M10 — Proof (D10)
|
||||
- [ ] All six recipes green via real !testme PRs; flip STATUS to DONE
|
||||
|
||||
## Adversary findings
|
||||
<!-- Adversary-only section. Builder must not edit below this line. -->
|
||||
33
DECISIONS.md
Normal file
33
DECISIONS.md
Normal file
@ -0,0 +1,33 @@
|
||||
# DECISIONS — cc-ci Builder
|
||||
|
||||
Architecture decisions and dead-ends. One line of rationale each. (§0, §8)
|
||||
|
||||
## Settled
|
||||
|
||||
- **Wildcard TLS:** operator pre-issues wildcard cert at `/var/lib/ci-certs/live/`; Traefik file
|
||||
provider serves it; **no ACME** for commoninternet.net. (Plan §4.0/§8 — fixed.)
|
||||
- **Repo:** `git.autonomic.zone/recipe-maintainers/cc-ci`, private. Bot is org admin. (Bootstrap.)
|
||||
- **Git credentials:** helper script in repo-local git config sources `/srv/cc-ci/.testenv` at call
|
||||
time — no secret values stored in `.git/config` or commits.
|
||||
|
||||
## Open (defaults from §8, to confirm as reality lands)
|
||||
|
||||
- **Deploy mechanism:** TBD in M0. Leaning `nixos-rebuild switch --flake` run *on cc-ci itself*
|
||||
(repo cloned on host) rather than `--target-host`/deploy-rs from the sandbox, to avoid copying
|
||||
large Nix closures over the userspace-tailscaled SOCKS proxy. Atomic-rollback is preserved by
|
||||
Nix generations. Will record final choice + rationale when M0 lands.
|
||||
- **Webhook scope:** default per-repo via enroll script.
|
||||
- **Drone runner type:** default exec (must drive host abra).
|
||||
- **Secret tool:** default sops-nix.
|
||||
- **D10 recipe set:** lock six early. Candidates favouring already-mirrored: custom-html (simple),
|
||||
cryptpad (stateful no-DB), keycloak (SSO/DB), matrix-synapse (DB+media), lasuite-docs (multi+S3),
|
||||
bluesky-pds (TLS-passthrough) — covers all five categories. Confirm during M4–M6.5.
|
||||
|
||||
## Risks
|
||||
|
||||
- **Disk:** cc-ci has only ~3.8 GiB free on an 8.9 GiB root. Multiple recipe images + volumes may
|
||||
exhaust it during M6.5 breadth. Mitigation: aggressive teardown + image prune; if insufficient,
|
||||
request operator grow the VM disk (Incus, recreatable per the incus skill). Not yet blocking.
|
||||
|
||||
## Dead-ends
|
||||
- (none yet)
|
||||
24
JOURNAL.md
Normal file
24
JOURNAL.md
Normal file
@ -0,0 +1,24 @@
|
||||
# JOURNAL — cc-ci Builder (append-only)
|
||||
|
||||
## 2026-05-26 — Bootstrap (§1)
|
||||
|
||||
**Access verification (all pass):**
|
||||
- `ssh cc-ci 'hostname && whoami && nixos-version'` → `nixos` / `root` / `24.11.719113.50ab793786d9 (Vicuna)`
|
||||
- `curl https://git.autonomic.zone/api/v1/version` → `{"version":"1.24.2"}`
|
||||
- Gitea bot auth (`curl -u $GITEA_USERNAME:$GITEA_PASSWORD .../api/v1/user`) → `login: autonomic-bot`, id 64
|
||||
- `getent hosts probe-$RANDOM.ci.commoninternet.net` → `143.244.213.108` (the gateway IP, as expected — TLS passthrough)
|
||||
- Cert present: `ls /var/lib/ci-certs/live/` → `fullchain.pem` (2909 b), `privkey.pem` (227 b, mode 640)
|
||||
- recipe-maintainers org exists (private); `recipe-maintainers/cc-ci` → 404 (created below)
|
||||
- Mirrored recipes already present: bluesky-pds, lasuite-docs, custom-html, custom-html-tiny, n8n,
|
||||
keycloak, lasuite-meet, matrix-synapse, cryptpad
|
||||
|
||||
**Baseline (docs/baseline.md):** fresh NixOS 24.11 Incus VM, 2 vCPU, 3.5 GiB RAM, 8.9 GiB disk
|
||||
(3.8 GiB free). No docker/swarm/abra. Channel-based `/etc/nixos/configuration.nix` (no flake).
|
||||
|
||||
**Actions:**
|
||||
- Created repo `recipe-maintainers/cc-ci` (private) via Gitea API.
|
||||
- `git init` in /srv/cc-ci/cc-ci; credential helper reads creds from /srv/cc-ci/.testenv (no
|
||||
secrets stored in git config).
|
||||
- Seeded skeleton layout (§3) + loop-state files + docs/baseline.md.
|
||||
|
||||
**Next:** commit + push bootstrap, then M0 (flake + base config + sops test secret).
|
||||
39
README.md
Normal file
39
README.md
Normal file
@ -0,0 +1,39 @@
|
||||
# cc-ci — Co-op Cloud recipe CI server
|
||||
|
||||
Comment **`!testme`** on a PR in an enrolled Co-op Cloud recipe repo and cc-ci deploys the recipe
|
||||
at that commit onto a real single-node Docker Swarm, runs install / upgrade / backup-restore tests
|
||||
(Python + Playwright) end-to-end, and reports a live, tail-able run with pass/fail back to the PR.
|
||||
|
||||
This repo declares the **entire server** as a NixOS flake and holds the test harness, the
|
||||
per-recipe test trees, and the docs to enroll a recipe or rebuild the box from scratch.
|
||||
|
||||
> Status: under active autonomous construction. See `STATUS.md` for the live phase and
|
||||
> `plan.md`-driven milestones in `BACKLOG.md`. Definition of Done is D1–D10 (see the build plan).
|
||||
|
||||
## Layout
|
||||
|
||||
```
|
||||
flake.nix NixOS host(s) + devshell
|
||||
hosts/cc-ci/ the cc-ci machine config
|
||||
modules/ drone, comment-bridge, swarm, dashboard, secrets (Nix modules)
|
||||
secrets/ sops-encrypted infra secrets
|
||||
bridge/ !testme webhook listener source
|
||||
runner/ run_recipe_ci.py + shared pytest harness
|
||||
dashboard/ results overview generator
|
||||
tests/<recipe>/ per-recipe install/upgrade/backup tests + playwright/
|
||||
docs/ install, enroll-recipe, secrets, architecture, runbook, baseline
|
||||
```
|
||||
|
||||
## Docs
|
||||
|
||||
- `docs/install.md` — rebuild the server from scratch (D8)
|
||||
- `docs/enroll-recipe.md` — add a recipe under CI (D5)
|
||||
- `docs/secrets.md` — secret model + rotation (D6)
|
||||
- `docs/architecture.md`, `docs/runbook.md` — design + debugging failed runs
|
||||
- `docs/baseline.md` — bootstrap snapshot / rollback reference
|
||||
|
||||
## Loop state (autonomous build)
|
||||
|
||||
`STATUS.md` (phase/blockers), `BACKLOG.md` (work + adversary findings), `REVIEW.md` (independent
|
||||
verification), `JOURNAL.md` (build log), `DECISIONS.md` (architecture choices). See the build plan
|
||||
for the two-loop Builder/Adversary protocol.
|
||||
7
REVIEW.md
Normal file
7
REVIEW.md
Normal file
@ -0,0 +1,7 @@
|
||||
# REVIEW — cc-ci Adversary (append-only)
|
||||
|
||||
This file is owned by the **Adversary** loop (§6.1). The Builder seeds this stub at bootstrap and
|
||||
does not edit it afterward. Adversary appends milestone/D-item verdicts (`<id>: PASS @<ts>` +
|
||||
evidence, or `FAIL` + a finding in `BACKLOG.md ## Adversary findings`), and may write `## VETO`.
|
||||
|
||||
<!-- Adversary verdicts below -->
|
||||
17
STATUS.md
Normal file
17
STATUS.md
Normal file
@ -0,0 +1,17 @@
|
||||
# STATUS — cc-ci Builder
|
||||
|
||||
**Phase:** M0 — Foundations
|
||||
**In-flight:** Bootstrap complete; starting M0 (flake + base config + sops test secret).
|
||||
**Last updated:** 2026-05-26 (bootstrap)
|
||||
|
||||
## Gates
|
||||
- (none claimed yet)
|
||||
|
||||
## Blocked
|
||||
- (none)
|
||||
|
||||
## Notes
|
||||
- cc-ci baseline: Incus VM, 2 vCPU, 3.5 GiB RAM, **3.8 GiB free disk** — tight for multi-recipe
|
||||
docker deploys; watch disk pressure, may need operator to grow the VM disk before M6.5 breadth.
|
||||
- Server config is currently channel-based `/etc/nixos/configuration.nix` (no flake). M0 converts
|
||||
to a flake checked out from this repo on the host.
|
||||
0
bridge/.gitkeep
Normal file
0
bridge/.gitkeep
Normal file
0
dashboard/.gitkeep
Normal file
0
dashboard/.gitkeep
Normal file
48
docs/baseline.md
Normal file
48
docs/baseline.md
Normal file
@ -0,0 +1,48 @@
|
||||
# Baseline — cc-ci starting environment (rollback reference)
|
||||
|
||||
Captured at bootstrap, 2026-05-26, before any Builder changes. This is the state to roll back to.
|
||||
|
||||
## Host
|
||||
|
||||
- Hostname: `nixos` (Tailscale node `cc-nix-test`, tailnet IP **100.90.116.4**, tailnet
|
||||
`taila4a0bf.ts.net`).
|
||||
- OS: **NixOS 24.11** `24.11.719113.50ab793786d9 (Vicuna)`.
|
||||
- Virtualisation: **Incus VM** (imports `virtualisation/incus-virtual-machine.nix`), incus agent on.
|
||||
- Resources: **2 vCPU, 3.5 GiB RAM, 8.9 GiB root disk (4.7 GiB used / 3.8 GiB free)**.
|
||||
- Access: SSH as **root** (PermitRootLogin yes), reached from sandbox via userspace-tailscaled
|
||||
SOCKS proxy `127.0.0.1:1055` → `ssh cc-ci`.
|
||||
|
||||
## Installed / present
|
||||
|
||||
- Config: **channel-based**, no flake. `/etc/nixos/`:
|
||||
- `configuration.nix` — incus VM module, cloud-init, tailscale (auth-key file), openssh,
|
||||
base pkgs (curl git jq openssh), firewall (trust tailscale0, allow tcp/22), DHCP,
|
||||
nameservers 1.1.1.1/8.8.8.8, `nix.settings.experimental-features = [nix-command flakes]`,
|
||||
`system.stateVersion = "24.11"`.
|
||||
- `incus-base.nix` — tailscale auth-key + hostname from `/etc/ts-hostname`.
|
||||
- `setup.sh` — original provisioning script (channel add + `nixos-rebuild boot` + sysrq reboot).
|
||||
- **No** docker, **no** swarm, **no** abra installed.
|
||||
- Tailscale up and authenticated (state persists; reconnects without key).
|
||||
|
||||
## Provided infra inputs (operator-owned, do not improvise — §4.4 class A1)
|
||||
|
||||
- Wildcard TLS cert at **`/var/lib/ci-certs/live/{fullchain.pem,privkey.pem}`**
|
||||
(`*.ci.commoninternet.net` + `ci.commoninternet.net`, LE 90-day, next renewal ~2026-08-24).
|
||||
Agent serves it via Traefik file provider; **never** runs ACME for this domain.
|
||||
- DNS: wildcard `*.ci.commoninternet.net` (+ bare `ci.commoninternet.net`) → **gateway**
|
||||
`143.244.213.108` (Gandi-hosted public zone). Gateway TLS-passthroughs the whole wildcard to
|
||||
cc-ci by SNI; TLS terminates on cc-ci's Traefik. Per-run subdomains need no DNS/gateway/cert work.
|
||||
- Gitea bot `autonomic-bot` (id 64), admin on private org `recipe-maintainers`.
|
||||
- Tailscale auth key (reusable) — in `/srv/cc-ci/.testenv`.
|
||||
|
||||
## Recipes already mirrored to recipe-maintainers (at bootstrap)
|
||||
|
||||
`bluesky-pds`, `cryptpad`, `custom-html`, `custom-html-tiny`, `keycloak`, `lasuite-docs`,
|
||||
`lasuite-meet`, `matrix-synapse`, `n8n`. Others (hedgedoc, authentik, immich, lasuite-drive) are
|
||||
pulled from upstream git.coopcloud.tech and mirrored via the recipe mirror+PR flow (§4.1) as needed.
|
||||
|
||||
## Rollback
|
||||
|
||||
The original config is preserved above and in the host's Nix generations
|
||||
(`nixos-rebuild --rollback` / boot menu). To fully revert, restore `/etc/nixos/*` to the channel
|
||||
config above and `nixos-rebuild switch`.
|
||||
0
hosts/cc-ci/.gitkeep
Normal file
0
hosts/cc-ci/.gitkeep
Normal file
0
runner/harness/.gitkeep
Normal file
0
runner/harness/.gitkeep
Normal file
0
secrets/.gitkeep
Normal file
0
secrets/.gitkeep
Normal file
0
tests/_template/.gitkeep
Normal file
0
tests/_template/.gitkeep
Normal file
Reference in New Issue
Block a user