Files
cc-ci-orchestrator/.opencode/skills/recipe-enroll/SKILL.md
T
autonomic-bot 91179f872c skills: add /recipe-enroll — end-to-end enrollment of a new maintained recipe
Codifies the full path walked for the 2026-08-03 wordpress enrollment (cc-ci PR #14):
survey -> mirror create+sync from coopcloud -> author test suite (health floor +
non-vacuous recipe-specific tests incl. sec4.3 create-an-object round-trip, recipe-local
setup helper, PARITY.md) -> bridge POLL_REPOS -> used-recipes.md weekly row +
upstream/<recipe>.md registry -> full-suite-green verification with the new tests ->
bridge deploy via test-before-switch -> merge-on-green + report (PR-visibility policy).
Includes the traps hit live: creds injection over stdin for cc-ci-side helpers, fresh-
deploy wizard state in HEALTH_OK, repo-dev-shell ruff, swarm serialization, stale bridge
secret 401s silently dropping !testme.
2026-08-03 22:41:16 +00:00

138 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: recipe-enroll
description: Add a NEW recipe to cc-ci's maintained set, end to end — create + sync the recipe-maintainers mirror from coopcloud upstream, author a real test suite (health floor + non-vacuous recipe-specific tests incl. a create-an-object round-trip), enroll it in the !testme bridge (POLL_REPOS) and the weekly /upgrade-all inventory (used-recipes.md weekly row + upstream registry), then VERIFY the whole thing: full harness suite green with the new tests, bridge deployed (test-before-switch) and healthy. Opens the cc-ci PR for visibility and merges it directly once verification is green (the skill invocation is the authorization); the report lists merged PR links + what changed. Invoke as /recipe-enroll <recipe>.
---
# recipe-enroll
Enroll a coopcloud recipe as a **maintained** recipe: mirrored, test-covered, `!testme`-triggerable,
and picked up by the weekly `/upgrade-all`. This is the full end-to-end path — worked example:
the 2026-08-03 wordpress enrollment (cc-ci PR #14).
**"Maintained" = ALL of:**
1. Mirror `recipe-maintainers/<recipe>` exists, `main` = coopcloud upstream main, tags synced.
2. `tests/<recipe>/` enrolled in the cc-ci repo (this is what `/upgrade-all` + `ci-test-review`
enumerate).
3. `POLL_REPOS` in `nix/modules/bridge.nix` includes the mirror (the `!testme` bridge).
4. `cc-ci-plan/used-recipes.md` has a `<recipe> weekly` row (orchestrator repo — `/upgrade-all`
skips recipes without it or tagged `external`).
5. `cc-ci-plan/upstream/<recipe>.md` registry entry (release-notes URLs + standing notes).
## Preconditions
- The recipe exists upstream: `ssh cc-ci 'script -qec "abra recipe fetch <recipe>" /dev/null'`
succeeds (every recipe must have a coop-cloud correspondent).
- `GITEA_*` creds in `/srv/cc-ci/.testenv` (orchestrator side; the cc-ci host does NOT have this
file — inject creds over stdin when running helper scripts there, see step 2).
- The shared Swarm is quiescent for step 6 (verification deploys the recipe) — do NOT verify
concurrent with `/upgrade-all` or other verify runs; author everything first, verify when clear.
## Procedure
### 1. Survey the recipe (read-only)
On cc-ci, after `abra recipe fetch <recipe>`, read `~/.abra/recipes/<recipe>/`:
- `compose.yml` — services + images (for the upstream registry), healthcheck (`start_period`
informs `DEPLOY_TIMEOUT`), traefik labels.
- `.env.sample` — is the app self-initializing, or does a fresh deploy sit in a setup wizard
(e.g. wordpress without `POST_DEPLOY_CMDS core_install`)? The tests must handle the state a
fresh CI deploy actually lands in.
- Auth model — how will a test create an object? (REST + token, session login, XML-RPC, …)
Check overlay configs (htaccess/nginx templates) for blocked endpoints before relying on one.
### 2. Create + sync the mirror
Create `recipe-maintainers/<recipe>` (Gitea API: `POST /orgs/recipe-maintainers/repos`,
`{"name":…,"private":true,"default_branch":"main","auto_init":false}`), then force-sync from
coopcloud with the existing helper **run on cc-ci with creds injected via stdin** (the host has
no `.testenv`):
```
set -a; . /srv/cc-ci/.testenv; set +a
{ printf 'export GITEA_USERNAME=%q GITEA_PASSWORD=%q GITEA_URL=%q\n' "$GITEA_USERNAME" "$GITEA_PASSWORD" "$GITEA_URL";
cat /srv/cc-ci-orch/.claude/skills/recipe-upgrade/open-recipe-pr.sh; } \
| ssh cc-ci 'bash -s -- <recipe> --reconcile-only'
```
Expect: repo created (or exists), `main` force-synced to upstream, published tags pushed.
### 3. Author the test suite (dedicated cc-ci clone + branch)
```
git clone ssh://git@git.autonomic.zone:2222/recipe-maintainers/cc-ci.git /home/loops/work/cc-ci-tests-<recipe>
cd … && git checkout -b test/<recipe>-enroll-$(date -u +%Y%m%d)
```
`tests/<recipe>/` contents (template: `tests/uptime-kuma/`, `tests/wordpress/`):
- **`recipe_meta.py`** — `HEALTH_PATH` / `HEALTH_OK` (accept the fresh-deploy state, e.g. a
302 to a setup wizard), `DEPLOY_TIMEOUT` (recipe healthcheck `start_period` + DB init +
first-boot copy, be generous), `HTTP_TIMEOUT`, `WARM_CANONICAL = True` (canon §2.B — all
recipes enroll as data-warm canonicals, operator 2026-06-17).
- **`custom/`** — the health floor + **≥2 recipe-specific, non-vacuous tests**, one of which is
the §4.3 **create-an-object + read-it-back** (write through the app's real API, read back via
a *different* path where possible — e.g. wordpress: XML-RPC write → REST read → permalink
HTML). If the app needs setup/auth, put it in a recipe-local `_<recipe>.py` helper
(idempotent `ensure_*` so test ordering doesn't matter; run-scoped class-B credentials —
the app is destroyed at teardown). Design assertions to name the broken layer (e.g. assert
both the rewrite-dependent and rewrite-independent API routes separately).
- **`PARITY.md`** — table of tests × what's verified × why non-vacuous; note there's no
recipe-maintainer parity corpus if so.
- Lint with the **repo dev-shell ruff**: `nix develop -c ruff check tests/<recipe>/ && nix
develop -c ruff format tests/<recipe>/` (pre-existing drift in other files is not yours).
### 4. Bridge enrollment (same branch)
`nix/modules/bridge.nix`: append `,recipe-maintainers/<recipe>` to the `POLL_REPOS=` CSV.
### 5. Inventory + registry (orchestrator repo, direct to main)
- `cc-ci-plan/used-recipes.md`: add `<recipe> weekly` row (alphabetical).
- `cc-ci-plan/upstream/<recipe>.md`: images table (source repo + releases/changelog links) +
standing notes (setup-wizard behavior, auth caveats, known upgrade traps).
- Commit + push (doc commits go direct to main in this repo).
### 6. Verify end-to-end — full suite GREEN with the new tests (swarm-serialized)
Open the cc-ci PR first (visibility): `TITLE=… BODY_FILE=… bash
/srv/cc-ci-orch/.claude/skills/ci-test-review/open-cc-ci-pr.sh`. The body: what's enrolled,
the test design rationale, the verify + deploy plan.
Then, when the swarm is clear:
```
ssh cc-ci 'rm -rf /root/cc-ci-test-verify && git clone --branch test/<recipe>-enroll-<date> \
ssh://git@git.autonomic.zone:2222/recipe-maintainers/cc-ci.git /root/cc-ci-test-verify && \
cd /root/cc-ci-test-verify && git submodule update --init secrets 2>/dev/null || true'
RECIPE=<recipe> REMOTE_ROOT=/root/cc-ci-test-verify \
bash /srv/cc-ci-orch/.claude/skills/ci-test-review/verify-pr.sh # no REF — recipe main
```
Required: **cold full-suite green** (install/upgrade/backup/restore/custom). Iterate the tests
(bounded, ≤3 attempts) if red — fix the TESTS to match real app behavior, never weaken. Clean up
`/root/cc-ci-test-verify` after.
### 7. Deploy the bridge change to the cc-ci host (test-before-switch)
The `POLL_REPOS` change only takes effect via a host rebuild. Per `/cc-ci-server-update` steps
5a-e: stage the branch to `/root/cc-ci-deploy` (+ secrets copy), `nixos-rebuild build`, detached
`nixos-rebuild test`, verify reachable + healthy, then `switch`. Confirm the bridge is polling
the new repo: `ssh cc-ci 'docker service inspect ccci-bridge_app --format "{{json
.Spec.TaskTemplate.ContainerSpec.Env}}"' | grep <recipe>` and the bridge task is 1/1 with no
auth errors in its logs (a stale Gitea secret 401s silently — see the 2026-08-03 finding).
### 8. Merge + report
Merge the cc-ci PR (invocation = authorization; PR is the visible record — comment the
verification evidence first). Report to the operator: merged PR link + change summary, the
verify log path, and the note that the **next weekly `/upgrade-all` picks the recipe up
automatically** (it enumerates `tests/<recipe>/` dirs × `weekly` rows).
## Guardrails
- **Full-suite green is the enrollment gate** — an enrolled-but-red recipe poisons every future
sweep. Don't merge on partial green.
- **Never weaken**: the tests assert the app's real current behavior, incl. asserting removed
auth paths are rejected where that's the upstream intent.
- **Single-writer**: dedicated clones/branches; never push `main` of cc-ci; never touch
`/root/builder-clone` or the loops' clones; `/root/cc-ci-test-verify` is yours — remove after.
- **Serialize on the swarm**: authoring is free, verification + bridge deploy wait for
`/upgrade-all`/other runs to finish.
- **abra over ssh needs the pseudo-TTY wrap**: `ssh cc-ci 'script -qec "abra …" /dev/null'`.
- **PRs for visibility, merged directly once verified**; failed enrollment leaves the PR open
with an explanatory comment and the report says exactly what's missing.