# STATUS — phase drone (drone enrollment with gitea SCM dep)

**Phase plan:** `/srv/cc-ci/cc-ci-plan/plan-phase-drone-enroll.md`
**Builder:** autonomic-bot / Claude (Builder loop)
**Started:** 2026-06-11T21:30Z

---

## DONE

**Adversary M2 PASS @2026-06-11T22:30Z** (commit `7b4081c`)

All phase DoD satisfied. Phase drone complete. PR open for operator merge.

**Operator summary:**
- Drone 1.9.0 enrolled with gitea 3.5.3 as SCM dep; full lifecycle proven via real `!testme` CI
- Gitea dep provisioned per-run (admin user + OAuth2 app); wired to drone at install time via `install_steps.sh`
- SCM-configured functional test (`test_login_redirects_to_gitea_dep`) verifies per-run dep, not production gitea
- Upgrade tier: 1.8.0+2.25.0 → 1.9.0+2.26.0 reconverges cleanly
- Backup structural skip: drone is not backup-capable (no backupbot labels); documented in PARITY.md
- Build-creation API gap accepted as proportionate deferral (Adversary §7.1 sign-off); remaining DEFERRED item

**Build #506 evidence (M2 CI run):**

```
recipe=drone  ref=049438e1cb47  pr=1  event=custom (!testme via bridge)
deploy-count = 2 (expect 2)     # DG4.1 PASS
  deps deployed: ['gitea']
  install : pass                 # test_serving PASSED
  upgrade : pass                 # test_upgrade_reconverges PASSED (1.8.0+2.25.0 → 1.9.0+2.26.0)
  backup  : skip                 # intentional: not backup-capable
  restore : skip                 # intentional: not backup-capable
  custom  : pass                 # test_login_redirects_to_gitea_dep PASSED
  lint    : pass
level=5, clean_teardown=true, no_secret_leak=true
```

Screenshot: `machine-docs/screenshots/drone-m2-build506.png`

---

## M2 CLAIMED (superseded by DONE above)

**Evidence:** CI build #506, 2026-06-11T22:21Z — event: custom (!testme on PR #1, recipe-maintainers/drone)

```
recipe=drone ref=049438e1cb47 pr=1
deploy-count = 2 (expect 2)     # DG4.1 PASS
  deps deployed: ['gitea']
  install : pass                 # test_serving PASSED
  upgrade : pass                 # test_upgrade_reconverges PASSED (1.8.0+2.25.0 → 1.9.0+2.26.0)
  backup  : skip                 # intentional: not backup-capable
  restore : skip                 # intentional: not backup-capable
  custom  : pass                 # test_login_redirects_to_gitea_dep PASSED
  lint    : pass
level=5, clean_teardown=true, no_secret_leak=true
```

Gitea dep provisioned at `gite-4c9694.ci.commoninternet.net`:
- Admin user `ci_admin` created
- OAuth2 app created (client_id=`d144083e-5ba5-4d1e-aed2-5e8f8331923a`)
- SCM wired via `install_steps.sh`; test confirmed redirect to dep (not production gitea)
- Dep torn down cleanly post-run

Screenshot: `machine-docs/screenshots/drone-m2-build506.png`  
Build URL: `https://drone.ci.commoninternet.net/recipe-maintainers/cc-ci/506`  
Results: `/var/lib/cc-ci-runs/506/results.json` (level=5)

Mirror PRs:
- `git.autonomic.zone/recipe-maintainers/drone/pulls/1` — `testme-1.9.0-cc-ci` branch
- `git.autonomic.zone/recipe-maintainers/gitea/pulls/1` — dependency mirror in place

---

## M1 CLAIMED

**Evidence:** Harness run 5, 2026-06-11T22:18Z on cc-ci host (`/root/drone-test-clone` @ `0aa46db`)

```
== cc-ci run: recipe=drone ref=None pr=0 stages=['custom', 'install', 'upgrade']
deploy-count = 2 (expect 2)                  # DG4.1 PASS
  deps deployed: ['gitea']
  install : pass
  upgrade : pass
  custom  : pass
results.json written: ... (level=5 of 5)
```

Log: `/tmp/drone-m1-run5.log` on cc-ci  
Results: `/var/lib/cc-ci-runs/manual/results.json`

**All fixes applied:**
- ADV-drone-01 (`7e7e84d`): `_CaptureOneRedirect` no-follow; Adversary verified CLOSED
- DG4.1 count (`5384f5c`): reverted `_count_deploy=False`; dep deploys count per formula
- ADV-drone-02 (`0aa46db`): finally-block fallback teardown from `$CCCI_DEPS_FILE`; 19/19 unit tests PASS

---

## Current state

**P0 prerequisite:** VERIFIED — `/etc/timezone` exists (content `UTC`) on cc-ci host.

**Gate M1:** PASS — Adversary PASS @2026-06-11T22:22Z (commit `3de5925`)  
**Gate M2:** PASS — Adversary PASS @2026-06-11T22:30Z (commit `7b4081c`) — **DONE**

---

## DoD tracker (M1)

- [x] P0 verified on host — `/etc/timezone` = `UTC`
- [x] `tests/gitea/recipe_meta.py` — gitea enrolled as dep provider (health + sqlite3 EXTRA_ENV)
- [x] `runner/harness/sso.py` — `setup_gitea_oauth()` function (admin user + OAuth2 app)
- [x] `runner/run_recipe_ci.py` — `_enrich_deps_with_sso` extended for gitea
- [x] `tests/drone/recipe_meta.py` — drone with `DEPS=["gitea"]`, health/timeouts
- [x] `tests/drone/install_steps.sh` — wires gitea OAuth into drone deploy
- [x] `tests/drone/functional/test_scm_configured.py` — no-follow redirect; ADV-drone-01 fixed `7e7e84d`
- [x] `tests/drone/PARITY.md` — backup structural-skip justification documented
- [x] Unit tests — 19/19 PASS cold (test_gitea_dep.py + test_deps.py)
- [x] No gate weakening; declared skips justified (backup structural skip per PARITY.md)
- [x] Harness run 5 GREEN — deploy-count 2/2, level=5, install+upgrade+custom+lint PASS
- [x] ADV-drone-02 fixed + unit tested (`0aa46db`)

---

## Verification recipe (for Adversary M1 check)

```bash
# On the orchestrator host (this machine) or from any machine with SSH to cc-ci:
ssh cc-ci "cat /var/lib/cc-ci-runs/manual/results.json" | python3 -c "
import json, sys
r = json.load(sys.stdin)
assert r['level'] == 5, f'level={r[\"level\"]} != 5'
assert r['results']['install'] == 'pass'
assert r['results']['upgrade'] == 'pass'
assert r['results']['custom'] == 'pass'
assert r['rungs']['lint'] == 'pass'
assert r['rungs']['backup_restore'] == 'skip'
assert r['skips']['intentional']['backup_restore']
print('M1 evidence VERIFIED')
"

# Unit tests (19/19):
cd /srv/cc-ci-orch/cc-ci && \
  /nix/store/rag15ca0cyi4nqbw6x6w1fqkvq5wmibj-python3-3.12.8-env/bin/pytest \
  tests/unit/test_deps.py tests/unit/test_gitea_dep.py -v

# Negative-control structural argument (no live deploy needed):
# A drone WITHOUT install_steps.sh (empty deps file) would not have GITEA_DOMAIN set,
# so /login would not redirect to a gitea domain. The SCM test checks parsed.netloc == gitea_domain;
# wrong netloc → AssertionError. The test is falsified by misconfiguration.
```

---

## Blocked items

(none)
