Adversary M1 verdict: PASS. Evidence:
- results.json: level=5, install+upgrade+custom+lint PASS, backup_restore intentional skip,
clean_teardown=True, no_secret_leak=True, no unintentional skips
- SCM test has teeth: ran against dep gitea @ gite-557a83 (not production); client_id
2a4dfaba matches dep-provisioned app; wrong domain/path/client_id would fail
- DG4.1 satisfied: deploy-count=2 (expect 2)
- ADV-drone-02 CLOSED: fallback teardown from $CCCI_DEPS_FILE in finally else-branch;
2 new unit tests; 19/19 pass; teardown-sacred §9 satisfied
- ADV-drone-03 CLOSED: _count_deploy=False reverted; run 5 confirms no violation
- All three adversary findings now closed; no open findings
Builder may proceed to M2: recipe mirrors + !testme CI run.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ADV-drone-02 fixed in 0aa46db (teardown fallback from $CCCI_DEPS_FILE in finally);
ADV-drone-03 fixed in 5384f5c (removed _count_deploy=False; dep deploys count per formula).
Harness run 5 evidence: deploy-count=2/2 (DG4.1 PASS), level=5,
install/upgrade/custom all PASS. 19/19 unit tests pass.
BUILDER-INBOX-drone.md consumed (both ADV-drone-02 + ADV-drone-03 already addressed).
ADVERSARY-INBOX-drone.md written requesting M1 PASS verdict.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
deps.py module docstring says "Dep deploys DO count toward DG4.1; expected = 1 + n_cold_deps"
but deploy_deps passes _count_deploy=False, so deps never increment the counter. With gitea
as cold dep: actual=1, expected=2 → DG4.1 fires → overall=1 → CI FAIL even when all tiers
pass and level=5.
Confirmed in Builder's run 4 (/tmp/drone-m1-run4.log): install+upgrade+custom green, L5,
but deploy-count 1 != 2 (DG4.1 violation). Run exits 1.
Fix: remove _count_deploy=False from deps.py:deploy_deps (one line). Deps SHOULD count.
ADV-drone-02 also filed (dep orphan on SSO-enrichment failure). Both must be fixed before
M1 can be claimed. BUILDER-INBOX updated with priority order.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When _enrich_deps_with_sso raises after deploy_deps succeeds (e.g., gitea API
call fails), deps_state stays {} and the finally block's `if deps_state:` guard
skips teardown, orphaning the dep at its deterministic domain.
Fix: add an `else` branch after the `if deps_state:` block that reads
$CCCI_DEPS_FILE (the legacy-list written by deploy_deps) and calls
teardown_deps on the cold entries so no dep is left running.
Unit tests: test_load_run_state_provides_fallback_for_enrichment_failure and
test_fallback_skips_warm_entries verify the data-flow that the fallback relies on.
19/19 unit tests pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All implementation items checked. Run 5 (DG4.1 fix applied) in flight on cc-ci.
ADV-drone-01 fix verified by Adversary. DG4.1 deploy-count fix explained and committed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
If deploy_deps succeeds (gitea up + healthy) but _enrich_deps_with_sso subsequently raises,
deps_state stays {} in main(). The finally block's `if deps_state:` guard is falsy and gitea
teardown is skipped entirely — violates §9 teardown-sacred invariant.
BACKLOG-drone.md: ADV-drone-02 filed (MEDIUM) with exact failure path trace, risk analysis,
and three fix options. REVIEW-drone.md: ADV-drone-02 summary + standing break-it probes updated
(negative-control, secrets-in-logs, concurrent-run probes analysed structurally). BUILDER-INBOX
created with must-fix notice and suggested minimal patch.
Must be fixed + tested before M1 can be claimed. Adversary veto standing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The DG4.1 formula in run_recipe_ci.py is:
expected_deploy_count = 1 + deps_deployed_count
So when gitea dep deploys, the expected count becomes 2 (1 recipe + 1 dep).
The _count_deploy=False fix made dep deploys NOT count, giving actual=1 vs
expected=2 → DG4.1 violation even though the run was correct.
Original error "deploy-count 2 != 1" was because deps_state was empty when
the DG4.1 check ran (provisioning had failed), giving expected=1 while count
was already 2 from an early dep deploy. The proper fix is for _provision_deps
to succeed (which it now does), not to suppress counting.
Revert _count_deploy=False in deps.py; update docstrings for clarity.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All M1 implementation tasks are done (setup_gitea_oauth, _enrich_deps_with_sso,
recipe_meta.py files, install_steps.sh, functional test, PARITY.md, unit tests).
ADV-drone-01 fixed. Mirror/!testme PR tasks moved to M2. Harness run 4 in flight.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
test_scm_configured.py was following ALL redirects via urlopen; gitea redirects
unauthenticated users from /login/oauth/authorize → /user/login, so the path
assertion always failed even for a correctly-wired drone.
Fix: _CaptureOneRedirect urllib handler stops after drone's first 303 and reads
the Location header directly, before gitea's own redirect chain runs.
- Consume BUILDER-INBOX.md (ADV-drone-01 finding delivered and addressed)
- Close ADV-drone-01 in BACKLOG-drone.md
- Update test_gitea_dep.py terminology: "location_url" not "final_url"
- All 10 unit tests pass
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
If a dep run uses the same deterministic gitea domain against a stale
volume from a prior failed teardown, ci_admin may already exist with a
different password. Reset it via `gitea admin user change-password` so
the subsequent API call authenticates correctly. This is idempotent and
does not affect clean (fresh-volume) runs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two issues found during first manual harness run:
1. gitea `--must-change-password false` (space form) leaves a pending
password-change for the ci_admin user, blocking the OAuth2 API call.
Fix: use `--must-change-password=false` (equals form, required by
gitea's BoolFlag with default=true).
2. dep deploy_app() calls incremented the DG4.1 "one deploy per run"
counter, causing a false violation when gitea dep + drone both deploy.
Fix: lifecycle.deploy_app gains _count_deploy=True param (default
backward-compat); deps_mod.deploy_deps passes _count_deploy=False so
only the recipe-under-test counts toward DG4.1.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The cc-ci server already runs on Hetzner (migration done; nix/hosts/cc-ci-hetzner
landed directly on main 2026-05-31). PR#2's host config was superseded by newer
main commits, but its terraform/ provisioning scaffolding (cpx32 + nixos-infect)
was never preserved. Add it here as the infrastructure-of-record so the box is
reproducible. .gitignore keeps tfstate + secret tfvars out; HCLOUD_TOKEN is an
env var at apply time (no secrets committed). PR#2 closed as superseded.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
STATUS/BACKLOG/REVIEW/JOURNAL for bsky/conc/dstamp/kuma/lvl5/mailu/rcust/shot
(32 files) were at the repo root; move them into machine-docs/ to match the
mandated file-location rule (DECISIONS/DEFERRED/INBOX + older phases already
live there). AGENTS.md gains an explicit File-location rule. No content change.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>