From a76aca80e28a3e02e4bd2316359479681f01f294 Mon Sep 17 00:00:00 2001 From: autonomic-bot Date: Tue, 9 Jun 2026 12:52:59 +0000 Subject: [PATCH] plan: Recipe Report TESTS rename + live PR-STATUS column (public mirrors + same-origin proxy) Co-Authored-By: Claude Opus 4.8 --- cc-ci-plan/plan-report-pr-status-column.md | 110 +++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 cc-ci-plan/plan-report-pr-status-column.md diff --git a/cc-ci-plan/plan-report-pr-status-column.md b/cc-ci-plan/plan-report-pr-status-column.md new file mode 100644 index 0000000..b4a56fa --- /dev/null +++ b/cc-ci-plan/plan-report-pr-status-column.md @@ -0,0 +1,110 @@ +# Plan — Recipe Report: TESTS + live PR-STATUS column + +Goal (operator request): in the weekly Recipe Report table, +1. **rename the current `Status` column → `TESTS`** (it shows the test/CI verdict: GREEN/FAILED/STALE/SKIPPED/UPTODATE — unchanged content, new label), +2. **add a new `STATUS` column** showing the live state of the recipe's PR — **open** (still to review) or a **✓** when closed/merged, +3. the PR state is fetched **client-side with JavaScript so it updates in realtime** (a visitor sees the current state, even on an archived past report), +4. to support (3), **make the recipe repo mirrors public** (operator: this is fine). + +## Findings that shape the plan +- The table is built by `cc-ci-plan/recipe-report.py::_table`. Current columns: + `Recipe | Change | Status | CVEs | CI | PR | Notes`. The `Status` cell carries a CSS class + `s-GREEN`/`s-FAILED`/… (colour); the `CI` cell is the build number+link; `PR` is `#n`+link. + The page is a **self-contained HTML** file (`_page`) served statically by the `ccci-reports` + nginx stack at `https://report.ci.commoninternet.net`. +- **Gitea CORS:** git.autonomic.zone has CORS middleware enabled, but it does **not** return + `access-control-allow-origin` for `report.ci.commoninternet.net` (origin not in the instance's + `[cors] ALLOW_DOMAIN`). That allow-list is autonomic.zone **instance config we don't control**, so a + direct browser→Gitea API fetch will be **blocked by CORS**. → use a **same-origin proxy** (below). +- **Mirror repos:** 25 repos under `recipe-maintainers`, **all private**. This set includes repos that + must **NOT** be made public: + - `cc-ci-secrets` (secrets!), `cc-ci-orchestrator` + `archived-cc-ci-orchestrator` (operational + plans/journal), and arguably `cc-ci` (the harness/infra). **Exclude these.** + - The **recipe mirrors** that SHOULD go public (they mirror public coopcloud recipes): bluesky-pds, + cryptpad, custom-html, custom-html-tiny, discourse, ghost, immich, keycloak, lasuite-docs, + lasuite-drive, lasuite-meet, mailu, matrix-synapse, mattermost-lts, mumble, n8n, plausible, + uptime-kuma. (Decide on the test fixtures `custom-html-bkp-bad`/`custom-html-rst-bad` and + `hedgedoc` — fine to include or skip; not in the 18-recipe fleet.) + +## Realtime-status architecture (chosen: same-origin proxy) +Browser JS calls a **same-origin** endpoint on the reports host; nginx proxies it to the Gitea API. +No cross-origin request → no dependency on the co-op's CORS allow-list. Public mirrors mean the proxy +needs no token (and the PRs are publicly viewable, which is the point). + +- Add an nginx `location` to the `ccci-reports` stack (cc-ci repo, `reports.nix` / its nginx conf): + ``` + location ~ ^/pr/([a-z0-9._-]+)/([0-9]+)$ { + resolver 127.0.0.11 ipv6=off; # docker DNS; or a public resolver + proxy_ssl_server_name on; + proxy_set_header Host git.autonomic.zone; + proxy_pass https://git.autonomic.zone/api/v1/repos/recipe-maintainers/$1/pulls/$2; + proxy_intercept_errors off; + add_header Cache-Control "no-store"; + } + ``` + So `GET https://report.ci.commoninternet.net/pr/cryptpad/5` → the PR JSON (`{state, merged, …}`). + (Restrict the regex to recipe-maintainers + a recipe-name charset; only proxies public PR reads.) +- **Alternative (if the operator prefers no proxy):** ask the autonomic.zone Gitea admins to add + `report.ci.commoninternet.net` (or `*`) to `[cors] ALLOW_DOMAIN`; then the JS can hit the Gitea API + directly. Same JS, just a different base URL. Documented as a fallback; the proxy is the default + because it has no external dependency. + +## Work items + +### A. Make the recipe mirrors public (scoped + safe) +1. **Secret-scan** each recipe mirror before flipping: `git log -p`/`git grep` for tokens, real `.env` + (not `.env.sample`), private keys; confirm `.drone.yml` uses secret *refs* not plaintext. (Low risk + — they mirror public upstream — but verify; the flip is hard to walk back once indexed/cloned.) +2. Confirm **no secrets in bot-authored PR comments / `!testme` output** posted on these repos (the PRs + become publicly readable). Reports are already public-safe; spot-check a couple of PR threads. +3. Flip visibility via the Gitea API (per repo): `PATCH /api/v1/repos/recipe-maintainers/` with + `{"private": false}`, for the recipe-mirror set ONLY (never the excluded repos above). Verify the + `recipe-maintainers` org itself is visible enough that public repos are reachable. +4. Verify an **unauthenticated** read now works: `curl https://git.autonomic.zone/api/v1/repos/recipe-maintainers/cryptpad/pulls/5` → 200 with `state`/`merged`. + +### B. Reports nginx proxy (cc-ci repo — via /ci-dev-workflow) +1. Add the `/pr//` proxy location to the reports nginx config; rebuild/redeploy the + `ccci-reports` stack. Verify `curl https://report.ci.commoninternet.net/pr/cryptpad/5` returns the + PR JSON same-origin. +2. (Optional hardening) small `proxy_cache` (e.g. 30–60 s) so many visitors don't hammer Gitea. + +### C. Report generator (`cc-ci-plan/recipe-report.py` — orchestrator repo) +1. `_table` header: rename `Status` → `TESTS`; add a `STATUS` column. Proposed order: + `Recipe | Change | TESTS | CVEs | CI | PR | STATUS | Notes`. +2. TESTS cell: unchanged (keep the `s-` colour class + the GREEN/FAILED/… text). +3. STATUS cell: emit a JS hook carrying the repo + PR number from the existing row fields + (`recipe`, `pr` like `#5`): + `…` — blank cell when the row has no + PR (e.g. merged-upstream custom-html, mumble). **No spec-shape change** — derives from existing + `recipe` + `pr`. +4. Add a small `