From 720ae1f28f5a4161bdb880026adc9a1222849847 Mon Sep 17 00:00:00 2001 From: autonomic-bot Date: Wed, 27 May 2026 01:51:15 +0100 Subject: [PATCH] review: file [adversary] A4 (same-recipe concurrent checkout collision); M6 verify in progress --- BACKLOG.md | 17 +++++++++++++++++ REVIEW.md | 20 ++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/BACKLOG.md b/BACKLOG.md index 1522ee5..b97cc58 100644 --- a/BACKLOG.md +++ b/BACKLOG.md @@ -116,3 +116,20 @@ Two single-writer sections (§6.1): Builder edits only `## Build backlog`; Adver remove the `.env` after a confirmed undeploy, or undeploy-by-stack-name as a fallback that doesn't need the `.env`. *Re-test:* run install, kill the process mid-deploy, verify the next run (or janitor) leaves zero residual service/volume/secret. Adversary closes after re-test. + +- [ ] **[adversary] A4 — Concurrent same-recipe runs collide on the shared recipe checkout.** + Found by review (M6 verify); to confirm empirically. Per-run isolation is correct for the app + **domain/volume/secret** (hashed `-<6hex(recipe|pr|ref)>`), but the recipe *source + checkout* is a single shared path `~/.abra/recipes/`: `run_recipe_ci.fetch_recipe` + does `rm -rf ~/.abra/recipes/` then `git clone`+`checkout `, and abra itself + re-checks-out the recipe to a version tag mid-deploy. There is **no per-run abra home + (`ABRA_DIR`/`HOME`), no lock, and no Drone concurrency cap** (runner capacity=2). So two + concurrent runs of the **same recipe at different refs** (e.g. `!testme` on two PRs of one + recipe) race on that dir — one can deploy/test the other's code, or fail mid-fetch. (Benign + when both want identical content, which is why an earlier accidental same-recipe overlap + didn't visibly break — masking the bug.) This weakens the §6 "two concurrent runs don't + collide" guarantee and matters for D10 (6 recipes via real PRs). *Repro:* start two runs of + one recipe with different REFs simultaneously; check each deploys its own ref's code (add a + per-ref marker) and neither errors mid-fetch. *Fix:* per-run abra home/recipe dir (e.g. + `ABRA_DIR=$(mktemp -d)` or `~/.abra-runs/`), or a per-recipe lock, or cap Drone to + serialize same-recipe builds. Adversary confirms + closes after re-test. diff --git a/REVIEW.md b/REVIEW.md index f345192..4a273f7 100644 --- a/REVIEW.md +++ b/REVIEW.md @@ -169,3 +169,23 @@ and not softened): reused per stage). Verdict: **M5 PASS.** + +## M6 — Recipe-local tests + second recipe: VERIFICATION IN PROGRESS (no verdict yet) @2026-05-27T01:48Z + +M6 CLAIMED. Host has been continuously busy (Builder M6.5 ramp), so deploy-based checks are +deferred to an idle window; static + evidence review so far: +- **custom-html 3-stage:** already verified cold by me (see M5 PASS) — green + clean teardown. +- **D4 recipe-local discovery — code genuine:** `run_recipe_ci.snapshot_recipe_tests` copies the + recipe-shipped `tests/` before abra re-checkouts to a version tag, then `run_recipe_local` deploys + the app and runs those tests against the LIVE app via `CCCI_BASE_URL`/`CCCI_APP_DOMAIN`, merged as + a separate stage with guaranteed teardown. Demo branch `recipe-maintainers/custom-html@ + ci/d4-recipe-local` confirmed to ship `tests/test_recipe_local.py` (Gitea API). Will run it cold to + confirm the stage executes+passes. +- **keycloak (#2) install — test genuine:** `/realms/master` 200 health + real Playwright admin + console login (waits for the username field). `recipe_meta.py` (HEALTH_PATH/timeouts) confirms D5 + "no harness surgery". Empirical keycloak reproduction deferred (heavy deploy; idle window). +- **Filed [adversary] A4** (concurrency): same-recipe concurrent runs share `~/.abra/recipes/` + with no isolation/lock/concurrency-cap — a collision vector for the §6 concurrency check; to + confirm empirically. + +Pending for idle host: cold D4 run, keycloak reproduce, A2/A3 kill-probe re-test, A4 concurrency test.