Clean-room finding caught by the e2e: DRONE_USER_CREATE had no token: => a fresh-DB rebuild's Drone
auto-generates a random bot token, so the committed (sops) bridge_drone_token gets 401 and the bridge
can't trigger builds. The original cc-ci only matched because its token was captured out-of-band. Now
the bot's machine token == bridge_drone_token deterministically on every rebuild. (Evolves the toplevel
again; re-establish byte-identical on cc-ci after the e2e + Adversary re-verifies C1.)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
On a FRESH host the reconcile oneshots ran abra concurrently against an uninitialised ~/.abra and
raced on catalogue/recipe init, leaving deploy-proxy/deploy-drone failed after a blank-VM rebuild
(observed on the W4 throwaway). Ordering-only `after` chain serializes them so a single
nixos-rebuild switch converges. Logically correct too (all need the proxy/abra state first).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cc-ci /var/lib/sops-nix/key.txt provisioned = host-derived age key (pub == &host recipient), so
adding keyFile is safe (sops-install-secrets aborts if a configured keyFile is missing).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- secrets/ is now the private cc-ci-secrets repo (submodule). defaultSopsFile path unchanged.
- secrets.nix: add wildcard_cert/wildcard_key sops secrets -> path=/var/lib/ci-certs/live/*.
- proxy.nix: cert is sops-from-git, not an operator file drop (reframed; FATAL guard kept as decrypt-path check).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fetch_recipe (SRC+REF/PR path) now read-only fetches published version tags from the public upstream
into the mirror clone, so the upgrade stage finds a previous published version (mirror PR branches
carry no tags → upgrade would skip). Guardrail-safe: only fetches tags, never pushes to the recipe
repo; plain git so the bot token isn't sent to upstream. Adds the 6 D10 recipes to the bridge
POLL_REPOS so !testme on their PRs triggers runs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After triggering a build, the bridge spawns a watcher thread that polls the Drone build to
completion and edits its run-link PR comment to ✅ passed / ❌ <status> (Gitea PATCH
issues/comments/{id}, verified). post_comment now returns the comment id. Also gives the bridge
image a content-hash tag so the swarm service actually rolls on bridge.py changes (was stuck on
:latest). Completes the D7 'PR comment reflects outcome' requirement.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Stdlib HTTP service (like the bridge): polls the Drone API for recipe-CI builds (event=custom),
groups latest-run-per-recipe, renders a YunoHost-CI-like overview table with pass/fail/running
badges + links to the canonical Drone run, plus /badge/<recipe>.svg. Nix-built OCI image, swarm
service on proxy, traefik Host(ci.commoninternet.net) (the bridge's /hook rule stays higher
priority by length). Reuses the Drone token (read-only). Reconcile oneshot like bridge/drone.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
backup-bot-two's .env.sample ends with a newline-less comment, so set_env's bare
append concatenated RESTIC_REPOSITORY onto it (commenting it out). The backupbot
container then lacked RESTIC_REPOSITORY and 'abra app backup create' KeyError'd —
breaking the backup stage for recipes without a custom backup hook (cryptpad).
set_env now ensures a trailing newline before appending (applied to drone.nix too,
same latent bug). Re-verify keycloak backup, which earlier passed off an older deploy.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bound live test apps on the single 28GiB node. DRONE_RUNNER_CAPACITY=1 (MAX_TESTS)
caps concurrent builds; Drone auto-queues the rest natively. deploy-drone reconcile
sets the cc-ci repo build timeout to 60m (best-effort PATCH, non-fatal) so a hung
build is killed and frees its slot. Janitor remains the backstop for SIGKILL'd builds.
Verified on host: DRONE_RUNNER_CAPACITY=1; repo timeout=60 via Drone API.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Polling is now the primary, read-only trigger (always-on thread); the /hook
webhook is an optional admin-registered push optimization deduped by comment id.
Authorize commenters via GET /orgs/{owner}/members/{user} (204, read-level) +
optional allowlist, replacing the admin-requiring /collaborators permission
endpoint. Bot never self-registers webhooks. Enroll = POLL_REPOS + tests/<recipe>/.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3-stage run green (install/upgrade/backup), clean teardown. backupbot deployed
via reconcile oneshot; PTY (script) for abra backup/restore; -m for secret generate
(no value leak). M5 CLAIMED.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bridge healthz 200 over public DNS; HMAC verified. Gitea sends no deliveries
(suspect webhook host allowlist). Recorded in STATUS Blocked + operator options.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Orchestrator decision: deploy canonical coop-cloud traefik via abra instead of a
hand-rolled module. abra packaged in Nix (pinned). custom-html deployed over HTTPS
(200) via the gateway and torn down clean. docs/install.md seeded.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Host decrypts /run/secrets/test_secret via its ssh host key (age identity);
off-box master recovery recipient. sops-nix pinned to a buildGoModule-era rev
for nixpkgs 24.11 compat.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>