M2 GATE: green build via push (Drone + exec runner); OAuth bootstrap script + docs
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Build #1 success (clone+hello on exec runner). Drone<->Gitea OAuth scripted as one-time bootstrap-drone-oauth.sh. M2 claimed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -26,9 +26,12 @@ Two single-writer sections (§6.1): Builder edits only `## Build backlog`; Adver
|
||||
CLAIMED 2026-05-26, awaiting Adversary.
|
||||
|
||||
### 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
|
||||
- [x] Drone server (coop-cloud recipe, reconcile oneshot) + exec runner via Nix; Gitea OAuth app.
|
||||
Server healthz 200 via gateway; runner polling (capacity=2, type=exec).
|
||||
- [x] hello-world .drone.yml runs green; logs visible (Drone UI + API). Build #1 success: clone +
|
||||
hello (echo/whoami=root/abra 0.13.0-beta/swarm=active), both exit 0.
|
||||
- [x] Gate: M2 — push to cc-ci triggers visible green build → CLAIMED 2026-05-26, awaiting Adversary.
|
||||
OAuth link via one-time `scripts/bootstrap-drone-oauth.sh` (documented in install.md §2).
|
||||
|
||||
### M3 — Comment bridge
|
||||
- [ ] comment-bridge service: HMAC verify, !testme exact match, collaborator check, Drone API call
|
||||
|
||||
21
JOURNAL.md
21
JOURNAL.md
@ -245,3 +245,24 @@ cc-ci repo activated in Drone, which requires the bot's Gitea OAuth login (brows
|
||||
Drone a Gitea token (to sync repos + set the push webhook). Next tick: script the OAuth login to mint
|
||||
a Drone token, activate cc-ci, push .drone.yml, confirm green. (DRONE_USER_CREATE made autonomic-bot
|
||||
the admin.)
|
||||
|
||||
## 2026-05-26 — M2 GATE MET: green build via push (Drone + exec runner)
|
||||
|
||||
**Drone↔Gitea OAuth (scripted, the one manual bootstrap):** logged the bot into Gitea (CSRF cookie
|
||||
→ form), drove Drone `/login` → Gitea authorize consent (POST `/login/oauth/grant` with _csrf+state+
|
||||
granted=true) → code callback → Drone `_session_`. Captured the whole flow in
|
||||
`scripts/bootstrap-drone-oauth.sh` (reads bot creds from env; documented in install.md §2; one-time,
|
||||
token persists in Drone's data volume).
|
||||
|
||||
**Repo activation:** `GET /api/user` → autonomic-bot admin=true; `GET /api/user/repos?latest=true`
|
||||
synced 12 repos; `POST /api/repos/recipe-maintainers/cc-ci` → active=true, config_path .drone.yml
|
||||
(sets the Gitea push webhook).
|
||||
|
||||
**Green build:** added `.drone.yml` (exec pipeline), pushed (0d89e28). Polled
|
||||
`/api/repos/recipe-maintainers/cc-ci/builds` → build #1 pending→running→**success**. Steps:
|
||||
clone success exit 0; hello success exit 0 — log shows `whoami=root`, `abra 0.13.0-beta-06a57de`,
|
||||
`swarm=active` (ran on the host via the exec runner). **M2 gate met; CLAIMED.**
|
||||
|
||||
**Next:** M3 — comment-bridge service: Gitea issue_comment webhook → verify HMAC + `!testme` exact +
|
||||
collaborator → resolve PR head repo/SHA → trigger a parameterized Drone build; post a PR comment with
|
||||
the run link. Need a Drone API token for the bridge (mint from the bot's Drone account).
|
||||
|
||||
13
STATUS.md
13
STATUS.md
@ -1,8 +1,8 @@
|
||||
# STATUS — cc-ci Builder
|
||||
|
||||
**Phase:** M1 complete & CLAIMED → starting M2 (Drone). M0 PASS (Adversary @21:35Z). M1 awaiting verdict.
|
||||
**In-flight:** M2 — Drone server + exec runner via Nix + Gitea OAuth app (first M2 task).
|
||||
**Last updated:** 2026-05-26 (M1 claimed)
|
||||
**Phase:** M2 complete & CLAIMED → starting M3 (comment bridge). M0+M1 PASS (Adversary). M2 awaiting verdict.
|
||||
**In-flight:** M3 — comment-bridge service (!testme webhook → Drone build trigger).
|
||||
**Last updated:** 2026-05-26 (M2 claimed, green build #1)
|
||||
|
||||
## Gates
|
||||
- **Gate: M0 — CLAIMED, awaiting Adversary** (2026-05-26). Evidence: flake rebuilds cc-ci from repo
|
||||
@ -16,7 +16,12 @@
|
||||
deployed by hand → HTTP 200 over HTTPS via gateway at cchtml1.ci.commoninternet.net with the
|
||||
wildcard cert; torn down clean (services/volumes/secrets/containers all 0). Repro:
|
||||
`scripts/deploy-proxy.sh` + `abra app new/deploy/undeploy`. Starting M2 as independent work; will
|
||||
not flip M2's gate until M1 shows PASS.
|
||||
not flip M2's gate until M1 shows PASS. → **M1 PASS** @2026-05-26T22:20Z.
|
||||
- **Gate: M2 — CLAIMED, awaiting Adversary** (2026-05-26). Evidence: Drone server (coop-cloud recipe,
|
||||
reconcile oneshot, Gitea SSO) healthz 200 via gateway; exec runner polling (capacity=2). cc-ci repo
|
||||
activated (push webhook). Pushing `.drone.yml` triggered build #1 → **success** (clone + hello exec
|
||||
steps, exit 0; ran abra/docker on the host). Repro: `nixos-rebuild switch` + one-time
|
||||
`scripts/bootstrap-drone-oauth.sh`. Starting M3 as independent work; won't flip M3 gate until M2 PASS.
|
||||
|
||||
## Blocked
|
||||
- (none)
|
||||
|
||||
@ -49,7 +49,22 @@ curl -ks --resolve drone.ci.commoninternet.net:443:<gateway-ip> \
|
||||
> it survives a momentary drop, and **use the absolute flake path** (systemd units run with cwd `/`):
|
||||
> `systemd-run --unit=ccci-sw --property=Type=oneshot nixos-rebuild switch --flake /root/cc-ci#cc-ci`
|
||||
|
||||
## 2. (later milestones) comment-bridge, dashboard, recipe enrollment
|
||||
## 2. One-time: link Drone ↔ Gitea (OAuth grant)
|
||||
|
||||
The only manual post-rebuild step. Drone needs the bot's Gitea OAuth token (granted by an
|
||||
interactive login) before it can sync/clone repos; this can't be Nix-declared without putting the
|
||||
bot password on the box. The token then persists in Drone's `data` volume.
|
||||
|
||||
```sh
|
||||
GITEA_USERNAME=autonomic-bot GITEA_PASSWORD=… bash scripts/bootstrap-drone-oauth.sh
|
||||
# -> "drone login ok (admin=true)" / "repo recipe-maintainers/cc-ci active=true"
|
||||
```
|
||||
|
||||
Verify a build runs green: push any commit to the cc-ci repo and watch
|
||||
`https://drone.ci.commoninternet.net` (or the API) — the push webhook (set on activation) triggers
|
||||
the `.drone.yml` self-test on the exec runner.
|
||||
|
||||
## 3. (later milestones) comment-bridge, dashboard, recipe enrollment
|
||||
|
||||
See `docs/enroll-recipe.md` (D5), `docs/secrets.md` (D6), `docs/runbook.md`. Each new piece of infra
|
||||
is added as another idempotent reconcile oneshot, so this install stays a single `nixos-rebuild`.
|
||||
|
||||
53
scripts/bootstrap-drone-oauth.sh
Normal file
53
scripts/bootstrap-drone-oauth.sh
Normal file
@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env bash
|
||||
# One-time Drone<->Gitea OAuth bootstrap (the ONLY manual post-`nixos-rebuild` step).
|
||||
#
|
||||
# Drone can only sync/clone repos once it holds the bot's Gitea OAuth token, which is granted by
|
||||
# an interactive OAuth login. This cannot be Nix-declared without putting the bot's Gitea password
|
||||
# on cc-ci, so it's a one-time operator step. The token then persists in Drone's `data` volume, so
|
||||
# reconcile redeploys keep working. Re-run only if that volume is wiped.
|
||||
#
|
||||
# Usage (run ON cc-ci, as root):
|
||||
# GITEA_USERNAME=autonomic-bot GITEA_PASSWORD=… bash scripts/bootstrap-drone-oauth.sh
|
||||
# Optionally ACTIVATE a repo: REPO=recipe-maintainers/cc-ci (default).
|
||||
set -euo pipefail
|
||||
: "${GITEA_USERNAME:?set GITEA_USERNAME}"; : "${GITEA_PASSWORD:?set GITEA_PASSWORD}"
|
||||
GITEA="${GITEA:-https://git.autonomic.zone}"
|
||||
DRONE="${DRONE:-https://drone.ci.commoninternet.net}"
|
||||
CLIENT_ID="${CLIENT_ID:-ab4cdb9d-ee96-4867-875f-87384505fc52}"
|
||||
REPO="${REPO:-recipe-maintainers/cc-ci}"
|
||||
RES=(--resolve "drone.ci.commoninternet.net:443:127.0.0.1")
|
||||
export PATH=/run/current-system/sw/bin:"$PATH"
|
||||
|
||||
cj=$(mktemp); dj=$(mktemp); az=$(mktemp)
|
||||
trap 'rm -f "$cj" "$dj" "$az"' EXIT
|
||||
|
||||
# 1) Gitea web login (CSRF cookie -> form field).
|
||||
curl -s -c "$cj" "$GITEA/user/login" -o /dev/null
|
||||
gcsrf=$(awk '/_csrf/{v=$NF} END{print v}' "$cj")
|
||||
curl -s -b "$cj" -c "$cj" -o /dev/null \
|
||||
--data-urlencode "_csrf=$gcsrf" \
|
||||
--data-urlencode "user_name=$GITEA_USERNAME" \
|
||||
--data-urlencode "password=$GITEA_PASSWORD" \
|
||||
"$GITEA/user/login"
|
||||
|
||||
# 2) Drone /login -> Gitea authorize URL.
|
||||
loc=$(curl -sk -c "$dj" -o /dev/null -D - "${RES[@]}" "$DRONE/login" \
|
||||
| awk 'tolower($1)=="location:"{print $2}' | tr -d '\r')
|
||||
curl -sk -b "$cj" -c "$cj" -o "$az" "$loc"
|
||||
|
||||
# 3) Grant consent -> code callback -> complete Drone login (sets Drone session).
|
||||
acsrf=$(grep -oE 'name="_csrf" value="[^"]*"' "$az" | head -1 | sed -E 's/.*value="([^"]*)".*/\1/')
|
||||
state=$(grep -oE 'name="state" value="[^"]*"' "$az" | head -1 | sed -E 's/.*value="([^"]*)".*/\1/')
|
||||
cb=$(curl -sk -b "$cj" -c "$cj" -o /dev/null -D - \
|
||||
--data-urlencode "_csrf=$acsrf" --data-urlencode "client_id=$CLIENT_ID" \
|
||||
--data-urlencode "state=$state" --data-urlencode "scope=" --data-urlencode "nonce=" \
|
||||
--data-urlencode "redirect_uri=$DRONE/login" --data-urlencode "granted=true" \
|
||||
"$GITEA/login/oauth/grant" | awk 'tolower($1)=="location:"{print $2}' | tr -d '\r')
|
||||
curl -sk -b "$dj" -c "$dj" -o /dev/null -L "${RES[@]}" "$cb"
|
||||
|
||||
# 4) Verify + sync + activate the repo.
|
||||
admin=$(curl -sk -b "$dj" "${RES[@]}" "$DRONE/api/user" | jq -r '.admin')
|
||||
echo "drone login ok (admin=$admin)"
|
||||
curl -sk -b "$dj" "${RES[@]}" "$DRONE/api/user/repos?latest=true" >/dev/null
|
||||
active=$(curl -sk -b "$dj" "${RES[@]}" -X POST "$DRONE/api/repos/$REPO" | jq -r '.active')
|
||||
echo "repo $REPO active=$active"
|
||||
Reference in New Issue
Block a user