claim(3 U3): YunoHost-style PR comment LIVE on custom-html PR#2 (comment 13792) — 🌻 + level badge + summary card images linked, updates in place on re-!testme, no secrets; R2 satisfied
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
autonomic-bot
2026-05-31 09:47:00 +00:00
parent 14aa785f55
commit c7b5dc04cc
3 changed files with 94 additions and 7 deletions

View File

@ -0,0 +1,17 @@
# ADVERSARY-INBOX (Builder → Adversary)
## 2026-05-31T09:45Z — U3 CLAIMED (YunoHost-style PR comment); live demo artifact map
U3 is claimed in STATUS-3 (`claim(3 U3)`). Everything you need to cold-verify is in the STATUS-3 U3
section (WHAT/HOW/EXPECTED/WHERE). Quick pointers:
- **Live demo:** `recipe-maintainers/custom-html` **PR #2**, bot comment **id 13792** (the one
marked `<!-- cc-ci:testme -->`). It cycled ⏳placeholder→result on the first `!testme` (build #3)
and again on a re-`!testme` (build #4) — same comment id, never stacked.
- **Served artifacts:** `https://ci.commoninternet.net/runs/{3,4}/{summary.png,badge.svg,screenshot.png,results.json}`.
- **Heads-up (not a verdict ask):** I had to **reactivate `recipe-maintainers/cc-ci` in Drone** — the
Hetzner-migration DB reset left it inactive (bridge `drone trigger failed 404`), so the build counter
reset to 1 (hence builds #1#4, not the Phase-1 numbering). Repo is `active=true` now, so you can
post your own `!testme` on PR #2 to cold-reproduce; it refreshes comment 13792. Self-heal hardening
filed as BACKLOG-3 U3.3.
- The embedded app screenshot is custom-html's "Welcome to nginx!" page — no secret values.

View File

@ -41,9 +41,16 @@ Milestones U0U5 (plan §5); each ends with an Adversary gate. DoD items R1
latest-level badge endpoint → U5.
### U3 — YunoHost-style PR comment (R2)
- [ ] U3.1 — Bridge posts a placeholder comment on run start (⏳ + live-logs link).
- [ ] U3.2 — On completion, update the SAME comment to 🌻 + level/status badge + summary card image,
both linking to the run/dashboard. Re-`!testme` refreshes it. Fallback to text on render failure.
- [x] U3.1 — Bridge posts a placeholder comment on run start (⏳ + live-logs link). `start_comment_body`,
reuses the marked comment if present (re-`!testme` refreshes to placeholder).
- [x] U3.2 — On completion, update the SAME comment to 🌻 + level/status badge + summary card image,
both linking to the run/dashboard. Re-`!testme` refreshes it. Fallback to text on render failure
(`result_comment_body` + `artifact_available` HEAD check). Deployed (bridge img 6377f9571f3b).
- [ ] U3.3 — Fold Drone repo activation into the drone reconcile so a DB reset self-heals: `POST
/api/repos/recipe-maintainers/cc-ci` (idempotent) BEFORE the timeout PATCH in drone.nix. Found
during the U3 live demo — the Hetzner-migration DB reset left the repo inactive (bridge `drone
trigger failed 404`); I reactivated by hand to run the demo. Not a U3 DoD item (cosmetics/comment
shape is); robustness hardening — fold in at U5 or flag to operator.
- GATE U3: live on a scratch PR — comment shows badge + card + screenshot, updates on re-run, no secrets.
### U4 — Dashboard polish (R5)

View File

@ -165,11 +165,74 @@ The cardinal U2 invariant: the rendered card/level/badge are a faithful, never-g
results.json + the actual test outcomes, served at a stable URL, generated best-effort so a render
failure never blocks the run.
## Gate: U3 — CLAIMED, awaiting Adversary (YunoHost-style PR comment; R2)
**WHAT.** On a `!testme` run the bridge now posts/updates ONE Gitea PR comment in the YunoHost shape:
on run start a 🌻 + ⏳ **placeholder** ("level pending", live-logs link); on completion it edits the
**SAME** comment in place to 🌻 + a **level badge** image + a **summary card** image, BOTH linked to
the full run, plus full-logs/dashboard links. A re-`!testme` refreshes that same comment (back to ⏳,
then to the new result) — never stacks a new one (R2 "one comment per PR, updated in place"). Falls
back to a compact text verdict if the rendered card isn't served (R7). DoD **R2** satisfied; U3
acceptance ("live on a scratch PR — comment shows badge + card + screenshot, updates on re-run, no
secrets") demonstrated on a real scratch PR. (This also lands R3's "embedded in the comment"
sub-requirement; R3 still needs "in dashboard" at U4.)
**WHERE (commits / files).**
- `9a47aa2` `bridge/bridge.py` — `COMMENT_MARKER` (hidden HTML comment `<!-- cc-ci:testme -->`),
`start_comment_body` (⏳ placeholder), `result_comment_body` (🌻 + badge + card, linked; text
fallback), `find_existing_comment` (marker → update-in-place), `artifact_available` (HEAD existence
check → image-vs-text), `watch_and_reflect` now edits to `result_comment_body`. Card/badge URLs are
`${DASH_URL}/runs/<DRONE_BUILD_NUMBER>/{summary.png,badge.svg}` (run_id == Drone build number, see
`runner/harness/results.py::run_id`).
- `9a47aa2` `dashboard/dashboard.py` — `do_HEAD` (shared `_route` with GET) so HEAD existence-checks +
strict image clients get 200, not 501 (closes Adversary A3-1, already re-verified @8807240).
- `9a47aa2` `tests/unit/test_bridge_trigger.py` — covers placeholder shape, image-forward result,
**text fallback when card missing**, marker-based find/update-in-place.
- **Deployed:** bridge swarm image `cc-ci-bridge:6377f9571f3b` == `sha256(bridge.py)` first-12 (content
tag, confirmed live); dashboard image live with `do_HEAD`.
**HOW to verify (cold, from your clone / the VM).**
1. **Unit tests** (on cc-ci): `cc-ci-run -m pytest tests/unit/test_bridge_trigger.py tests/unit/test_card.py -q` → `15 passed`.
2. **Deployed bridge == source:** `ssh cc-ci 'sha256sum /etc/cc-ci/bridge/bridge.py | cut -c1-12'` →
`6377f9571f3b`; `ssh cc-ci 'docker service ls | grep ccci-bridge'` shows image tag `6377f9571f3b`.
3. **LIVE demo on scratch PR** `recipe-maintainers/custom-html` **PR #2** (recipe == repo name; the
bridge poller, 30s, fires on a NEW `!testme`). The bot comment carrying the marker is **id 13792**:
`curl -s -u "$GITEA_USERNAME:$GITEA_PASSWORD" https://git.autonomic.zone/api/v1/repos/recipe-maintainers/custom-html/issues/comments/13792`
→ body has `<!-- cc-ci:testme -->`, 🌻, `✅ passed`, `[![cc-ci result card](…/runs/4/summary.png)](…/4)`,
`[![level](…/runs/4/badge.svg)](…/4)`, full-logs+dashboard links. (You may post your own `!testme`
on PR #2 — the repo is active in Drone; it will refresh **the same** comment 13792.)
4. **Images render (served):** `for f in summary.png badge.svg screenshot.png results.json; do
curl -s -o /dev/null -w "$f %{http_code}\n" https://ci.commoninternet.net/runs/4/$f; done` → all 200.
5. **Updates in place / no stacking:** the marked-comment set on PR #2 stays exactly `[13792]` across
runs #3 (first `!testme`) and #4 (re-`!testme`); the comment cycled ⏳→result both times. (Filter
comments for `<!-- cc-ci:testme -->` — there is exactly one.)
6. **No secrets:** scan the comment body + `/var/lib/cc-ci-runs/{3,4}/{results.json,summary.html}` for
`password|secret|token|passwd|api_key|privkey|PRIVATE` → only the `no_secret_leak` flag-name matches;
the embedded app screenshot is custom-html's **"Welcome to nginx!"** page (no values).
7. **No inflation:** the card for run #4 shows `level 4` / `capped: L5 integration N/A`, all
install/upgrade/backup/restore/custom rows ✔ — matches `/runs/4/results.json` verbatim.
**EXPECTED.**
1. `15 passed`. 2. tag `6377f9571f3b` both places. 3. comment 13792 body exactly as above (run 4).
4. all four `/runs/4/` files 200 (`summary.png` ~178 KB, `badge.svg` 342 B, `screenshot.png` 35707 B).
5. exactly one marked comment (`13792`); no new comment stacked on re-run. 6. zero real secret hits.
7. card level 4, all rows ✔, == results.json (`recipe=custom-html`, `level=4`, all tiers pass,
`flags.clean_teardown=true,no_secret_leak=true`).
The cardinal U3 invariant: ONE comment per PR, refreshed in place; the embedded card/badge are a
faithful never-greener projection of the run; image-gen failure degrades to text and never blocks the
run or the verdict.
## In flight
- U3 — YunoHost-style PR comment (IN PROGRESS): bridge posts 🌻 + ⏳ start comment, edits same comment
on completion to 🌻 + level badge image + summary card image (both linking to the run/dashboard),
text fallback on render failure. URLs: `/runs/<DRONE_BUILD_NUMBER>/{badge.svg,summary.png}`. Also
adding dashboard `do_HEAD` (Adversary polish item + cheap bridge existence-check).
(none — U3 claimed; U4 dashboard polish next, unblocked work can start while parked at the U3 gate)
## Blocked
(none)
## Note — Drone repo reactivation (infra, recorded for the Adversary)
The Hetzner-migration Drone DB reset left `recipe-maintainers/cc-ci` **inactive** (bridge log `drone
trigger failed 404`); the bridge can't trigger builds when the repo is inactive. I reactivated it
(in-scope reconfig of my own CI, reversible): `POST /api/user/repos?async=false` then `POST
/api/repos/recipe-maintainers/cc-ci` → `active=true`, config_path `.drone.yml`, timeout 60. This is
why builds #1#4 above exist (counter reset to 1 by the DB reset). Self-heal hardening filed as
BACKLOG-3 U3.3 (fold activation into the drone reconcile) — not a U3 DoD item.