# Fase A1 — Closeout operativo Checklist per chiudere lo step **A1** di [implementation-plan-A-B](implementation-plan-A-B.md) prima di iniziare A2. Il codice è già committato sul branch `feature/python-rewrite-phase-a` (commit `9fbe952`); manca solo la validazione contro l'ambiente reale. ## Stato attuale - [x] Codice + 35 unit test (coverage 82.65%) committati - [x] `ruff` clean, `mypy --strict` clean su 12 file sorgente - [x] Job `python` aggiunto a `.gitea/workflows/lint.yml` - [x] Job `python` di `lint.yml` PASS su act_runner (commit `8586ff8`) - [ ] PoC `wait-ready` PASS contro VM reale Windows - [ ] PoC `wait-ready` PASS contro VM reale Linux ## Perché completare A1 prima di A2 A2 riusa `WorkstationVmrunBackend`, `WinRmTransport`, `SshTransport` e `KeyringCredentialStore` esattamente come sono ora. Se uno di questi ha un bug di integrazione (TLS, encoding, parsing output `vmrun list`, permessi venv, ecc.), trovarlo dopo A2 costa: **1 fix nei moduli core + retest di tutti i 6 comandi portati in A2**. Trovarlo ora costa: 1 fix. ## 1. PoC `wait-ready` su VM Windows reale **Obiettivo**: validare il path `vmrun.is_running` → `get_ip` → WinRM HTTPS con cert self-signed end-to-end. ```powershell # 1. Setup venv (una tantum) sull'host CI python -m venv F:\CI\python\venv F:\CI\python\venv\Scripts\python.exe -m pip install --upgrade pip F:\CI\python\venv\Scripts\python.exe -m pip install -e ".[dev]" # 2. Clone manuale di una VM smoke da template $vmrun = 'C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe' $tpl = 'F:\CI\Templates\WinBuild2025\WinBuild2025.vmx' $dst = 'F:\CI\BuildVMs\smoke-a1\smoke-a1.vmx' & $vmrun -T ws clone $tpl $dst linked -snapshot=BaseClean -cloneName=smoke-a1 if ($LASTEXITCODE -ne 0) { throw "clone fallito" } & $vmrun -T ws start $dst nogui if ($LASTEXITCODE -ne 0) { throw "start fallito" } # 3. PoC wait-ready $env:PYTHONIOENCODING = 'utf-8' F:\CI\python\venv\Scripts\python.exe -m ci_orchestrator wait-ready ` --vmx $dst --guest-os windows --timeout 300 # 4. Cleanup & $vmrun -T ws stop $dst hard & $vmrun -T ws deleteVM $dst ``` **Atteso**: - Exit code `0` - Ultima riga stdout: `[wait-ready] WinRM ready.` - Tempo totale tra start VM e WinRM ready: 60–180 s **Failure mode più probabili e fix**: | Sintomo | Causa probabile | Fix | | -------------------------------------------------- | ------------------------------------------------------ | -------------------------------------------------------------------------------------------------- | | `is_running` resta `False` per sempre | Path mismatch in `vmrun list` (slash diversi, casing) | Aggiungere normalizzazione `os.path.normcase` in `WorkstationVmrunBackend.is_running` | | `get_ip` ritorna sempre `None` | VMware Tools non ancora pronti | Atteso nei primi 30–60 s; se persiste >180 s, problema nel template | | `WinRM probe failed: ... certificate verify` | `cert_validation=False` non basta su TLS handshake | Ispezionare cipher; eventualmente pinnare versione `pypsrp` o passare `auth='ntlm'` esplicito | | `KeyError: 'BuildVMGuest'` | Credenziale non leggibile dall'utente che lancia il PoC | Eseguire come l'utente del runner (`runas /user:ci-runner ...`) o re-store credential nel suo profilo | | `KeyringCredentialStore` ritorna username vuoto | Backend keyring usa `get_password`-only | Verificato in `test_credentials.py::test_get_falls_back_to_password`; in tal caso impostare username separatamente nel target | ## 2. PoC `wait-ready` su VM Linux reale ```powershell $tpl = 'F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx' $dst = 'F:\CI\BuildVMs\smoke-a1-lnx\smoke-a1-lnx.vmx' & $vmrun -T ws clone $tpl $dst linked -snapshot=BaseClean-Linux -cloneName=smoke-a1-lnx & $vmrun -T ws start $dst nogui $env:CI_SSH_KEY_PATH = 'F:\CI\keys\ci_linux' F:\CI\python\venv\Scripts\python.exe -m ci_orchestrator wait-ready ` --vmx $dst --guest-os linux --ssh-user ci_build --timeout 300 & $vmrun -T ws stop $dst hard & $vmrun -T ws deleteVM $dst ``` **Atteso**: ultima riga `[wait-ready] SSH ready.` entro 60–120 s. **Failure mode più probabili**: | Sintomo | Causa | Fix | | ------------------------------------ | ---------------------------------------------------- | ---------------------------------------------------------------------------------- | | `SSH connection ... timed out` | DHCP collision (vedi `AGENTS.md` errore #11) | Verificare snapshot `BaseClean-Linux` con machine-id resettato | | `paramiko.AuthenticationException` | Permessi chiave SSH errati (Windows ACL su `ci_linux`) | `icacls F:\CI\keys\ci_linux /inheritance:r /grant:r ":R"` | | `is_ready()` False ma SSH manuale OK | `BatchMode=yes` lato `ssh.exe` non equivalente in paramiko | Già coperto: paramiko non chiede prompt; verificare `look_for_keys=False` settato | ## 3. Job `python` di `lint.yml` su act_runner ```powershell # Push del branch git push -u origin feature/python-rewrite-phase-a ``` Poi su Gitea: aprire una PR contro `main` (o trigger manuale del workflow). Verificare che il job `python` completi entro `timeout-minutes: 15`. **Failure mode più probabili**: | Sintomo | Causa | Fix | | ------------------------------------------------------ | -------------------------------------------------------- | ------------------------------------------------------------------------------ | | `python: command not found` | `python` non in PATH dell'utente del runner | Installare Python 3.11+ machine-wide o aggiornare `PATH` del servizio | | `pip install -e .[dev]` >15 min al primo run | Cache assente, network lento | Bumpare `timeout-minutes: 30` solo per il primo run; cache stabile dopo | | `Access denied` su `F:\CI\python\venv` | Utente del runner senza scrittura su `F:\CI\python` | `icacls F:\CI\python /grant ":(OI)(CI)F"` | | Coverage <70% | Differenza Python 3.14 (locale) vs 3.11 (CI) | Rilanciare con `--cov-report=term-missing` per identificare branch mancante | ## 4. Definizione di "A1 done" Spuntabile solo quando **tutti** e tre i punti sopra sono PASS: - [ ] PoC Windows: `wait-ready` exit 0 contro `WinBuild2025` reale - [ ] PoC Linux: `wait-ready` exit 0 contro `LinuxBuild2404` reale - [ ] CI: workflow `lint.yml` job `python` PASS su act_runner A quel punto: 1. Aggiornare la checklist master in [implementation-plan-A-B](implementation-plan-A-B.md) spuntando le righe `[A1]`. 2. Mergeare `feature/python-rewrite-phase-a` su `main` (o lasciare il branch live se A2 verrà committato sopra). 3. Procedere con A2 (script "foglia": `Wait-VMReady`, `Remove-BuildVM`, `Cleanup-OrphanedBuildVMs`, `Watch-DiskSpace`, `Watch-RunnerHealth`, `Get-CIJobSummary`). ## 5. Workaround se A1 non si può chiudere ora Se l'hardware/VM template non sono accessibili in questo momento: - **Non rimuovere** alcuno script PS in A2. - Marcare A1 come "code-complete, validation pending" in [implementation-plan-A-B](implementation-plan-A-B.md). - Procedere con A2 ma trattare ogni bug scoperto su `WorkstationVmrunBackend` / `WinRmTransport` / `SshTransport` come **fix di A1** (commit separato, no nuove feature A2 nello stesso commit). - Riservare una sessione dedicata di smoke testing prima di A3 (pipeline di build), perché A3 introduce `clone_linked` + `start` reali.