# Fase C — Eliminazione dipendenza PowerShell dall'host Linux > **Stato**: **codice completato** (C1–C8 implementati + docs C9, 2026-06-07); > resta solo la parte **operativa** di C9 (cutover ≥1 settimana + `apt-get > remove powershell` sull'host reale). > Vedi [overview](ideas-overview.md) e il > [piano di applicazione](idea-3-implementation-plan.md) (checklist operativa). > > **Analisi rifatta il 2026-06-07** sullo stato reale del repo (la versione > precedente proponeva gruppi CLI inesistenti e ometteva metà della > superficie `pwsh`). --- ## 1. Obiettivo Rendere l'host Linux completamente indipendente da PowerShell Core (`pwsh`). Dopo la Fase B l'orchestrazione ordinaria (job, timer, monitoring, backup, retention, deploy template) è già Python puro. Restano script `.ps1` eseguiti **manualmente** sull'host Linux con `pwsh` per: burn-in di capacità, benchmark di timing, smoke/E2E test, validazione stato host e setup credenziali. Inoltre il job di lint CI usa `shell: pwsh`. **C done**: nessuno script in `scripts/*.ps1` viene più eseguito direttamente sull'host Linux, e nessun job CI che gira su un runner Linux richiede `pwsh`; `pwsh` può essere disinstallato dall'host Linux senza impatti operativi. I `.ps1` restano nel repo come riferimento storico e per l'eventuale runner Windows (fallback dual-boot Passo 9). --- ## 2. Superficie `pwsh` reale sull'host Linux Lo stato CLI attuale (`src/ci_orchestrator/__main__.py`) espone i gruppi: `wait-ready`, `vm`, `build`, `artifacts`, `monitor`, `report`, `retention`, `template`, `job`. **Non esistono** gruppi `bench`, `smoke`, `validate`, `creds` — vanno creati. ### 2.1 Cosa blocca davvero la disinstallazione di `pwsh` | # | Dipendenza | Dove | Tipo | | - | ---------- | ---- | ---- | | 1 | Burn-in di capacità (4 job × N round) | `Test-CapacityBurnIn.ps1` + wrapper `Start-BurnInTest-Linux.ps1` (lanciato via `sudo -u ci-runner -H pwsh …`, vedi PhaseB-user-checklist §B7) | host Linux, manuale | | 2 | Benchmark timing fasi (clone/start/IP/transport/destroy) | `Measure-CIBenchmark.ps1` — **unico consumatore** di `scripts/_Common.psm1` e `scripts/_Transport.psm1` | host Linux, manuale | | 3 | Smoke end-to-end | `Test-Smoke.ps1 -GuestOS Linux` | host Linux, manuale | | 4 | Build E2E reali (validazione pipeline) | `Test-Ns7zipBuild-Linux.ps1`, `Test-NsinnounpBuild-Linux.ps1` | host Linux, manuale | | 5 | Lint CI (PSScriptAnalyzer) | `.gitea/workflows/lint.yml` → `shell: pwsh`, `runs-on: linux-build` | runner Linux, automatico | | 6 | Installazione `pwsh` di default | `setup-host-linux.sh` step 6/6 (opt-out `--skip-pwsh`) | provisioning host | | 7 | Pester (test dei moduli PS) | `tests/_Common.Tests.ps1` | host/CI, manuale | | 8 | Setup credenziali guest | `Set-CIGuestCredential.ps1` (equivalente Linux mancante in CLI) | host Linux, manuale | ### 2.2 Script Windows-only (NON bloccano `pwsh` su Linux) Hardcodano `F:\`, richiedono `#Requires -RunAsAdministrator` o usano il Windows Credential Manager: **non girano sull'host Linux**, quindi non vanno portati per l'obiettivo di Fase C. Restano per il runner Windows. - `Validate-HostState.ps1` — logica Credential Manager/ACL NTFS, path `F:\`. Serve però un **equivalente Linux** (`validate host`), non un porting 1:1. - `Set-CIGuestCredential.ps1` — scrive nel vault SYSTEM via scheduled task. Su Linux le credenziali stanno in `keyrings.alt.file.PlaintextKeyring` (B3, `secret-tool` scartato). Serve un `creds set` Linux-nativo. - `Test-CIGuestWinRM.ps1` — diagnostica WinRM, `RunAsAdministrator`. - `Start-BurnInTest.ps1`, `Test-NsinnounpBuild.ps1`, `Test-E2E-Section3.3.ps1` — wrapper Windows (path `F:\`, template WinBuild). ### 2.3 Già fuori scope (confermato) - `Register-CIScheduledTasks.ps1` — Windows Scheduler. - `Invoke-RetentionPolicy.ps1` / `Backup-CITemplate.ps1` — portati in B5 (`retention run` / `template backup`). - Shim in `scripts/` (3 righe → Python) — restano. - Script guest (`Install-CIToolchain-*`, `Prepare-*`, `Deploy-*`, `template/guest-setup/windows/*`) — girano dentro le VM, non sull'host. --- ## 3. Architettura prevista (nuovi gruppi CLI) ``` python -m ci_orchestrator bench run --guest-os windows|linux --concurrency N # default 4 --rounds N # default 10 --build-command "..." --json-out PATH python -m ci_orchestrator bench measure --guest-os windows|linux --iterations N --json-out PATH # append a benchmark.jsonl python -m ci_orchestrator smoke run --guest-os windows|linux [--build-command "..."] # default: marker no-op python -m ci_orchestrator validate host # vmrun, snapshot template, keyring, # permessi dir, act-runner systemd attivo python -m ci_orchestrator validate guest --host IP [--winrm|--ssh] # diag transport python -m ci_orchestrator creds set --target BuildVMGuest --user ... [--password-stdin] ``` - **`bench run`** unifica `Test-CapacityBurnIn.ps1` + `Start-BurnInTest*.ps1`: lancia N job concorrenti (riusando `commands/job.py` in-process o come subprocess del CLI Python — niente `Start-Job`/`pwsh`), per R round, e asserisce dopo ogni round: tutti exit 0, nessuna clone-dir orfana in `CI_BUILD_VMS`, nessun `vm-start.lock` stale. Emette report JSON. - **`bench measure`** porta `Measure-CIBenchmark.ps1` (fasi clone/start/IP/transport/destroy) → consente di **retirare** `_Common.psm1` e `_Transport.psm1` (nessun altro consumatore). - **`smoke run`** porta `Test-Smoke.ps1` + i `Test-*Build-Linux.ps1` (build E2E reali come preset opzionali del build-command). - **`validate host`** è un nuovo equivalente Linux (non un porting di `Validate-HostState.ps1`): verifica `vmrun`, presenza snapshot template, leggibilità keyring file-based, permessi `/var/lib/ci/...`, unit `act-runner`/`ci-*` attive. - **`creds set`** sostituisce `Set-CIGuestCredential.ps1` su Linux usando direttamente il backend `keyring` letto da `ci_orchestrator`. **Vincolo di design**: i nuovi comandi devono importare `backends.load_backend` e i transport esistenti, **mai** `WorkstationVmrunBackend` diretto (rotta ESXi Fase D aperta). --- ## 4. Nodo aperto — lint PSScriptAnalyzer (dipendenza #5) Gli script `.ps1` restano nel repo (guest + fallback Windows), quindi il lint PSSA ha ancora valore. Ma `lint.yml` lo esegue con `shell: pwsh` su `runs-on: linux-build`, il che reintroduce `pwsh` sul runner Linux. **Decisione applicata (C7, 2026-06-07): opzione 1.** Il job `pssa` gira ora su `runs-on: windows-build`, `shell: powershell` (PS 5.1), con guardia `if: github.event_name == 'workflow_dispatch'` così non si accoda su push/PR se il runner Windows non è registrato. Il job `python` resta su `linux-build`. Nessun job su runner Linux usa più `pwsh`. Tre opzioni considerate: 1. **(Consigliata)** Spostare il job `pssa` su un runner Windows (`runs-on: windows-build`, `shell: powershell` PS 5.1) — coerente col fatto che i `.ps1` target sono Windows-native. Richiede un runner Windows registrato (dual-boot Passo 9) o eseguirlo solo on-demand. 2. Mantenere `pwsh` **solo nel container/runner di lint**, non sull'host orchestratore: l'obiettivo "host Linux senza pwsh" resta soddisfatto se il job gira in un runner isolato. Pragmatica ma ambigua sul "C done". 3. Rimuovere il job PSSA da CI e affidare il lint PS a un hook locale manuale. Riduce copertura. --- ## 5. Aggiornamenti collaterali - `setup-host-linux.sh`: invertire il default dello step 6 (no install `pwsh`; flag `--with-pwsh` per opt-in) o rimuovere lo step. - `.gitea/workflows/lint.yml`: applicare la decisione del §4. - `tests/_Common.Tests.ps1`: rimuovere insieme ai moduli `.psm1` quando `bench measure` li retira (Passo C3); la copertura passa a pytest. - `CLAUDE.md`: la sezione "PowerShell 5.1 Constraints" resta valida per gli script guest Windows; aggiungere nota che l'host Linux non usa più `pwsh`. - `docs/RUNBOOK.md`: aggiornare procedure burn-in / smoke / validazione ai nuovi comandi Python. - `plans/archived/2026-06-07/PhaseB-user-checklist.md` §B7 (archiviato): nota che il comando `pwsh Test-CapacityBurnIn.ps1` è superato da `bench run`. - `TODO.md`: chiudere la voce shim `$IsWindows` bug (f22b142) — sparisce con la rimozione di `Start-Job`/`pwsh` nel burn-in. --- ## 6. Prerequisiti - Fase B completata e stabile (≥1 settimana, Passo 8 ✅). - `pwsh` ancora installato durante il porting (per confronto output A/B). - Nessuna dipendenza da `pwsh` nei timer systemd (già soddisfatta da B5). --- ## 7. Criteri di "C done" - `bench run --concurrency 4 --rounds 10` (Win + Linux) produce esito equivalente a `Test-CapacityBurnIn.ps1` (stesse asserzioni di cleanup). - `bench measure` riproduce le fasi di `Measure-CIBenchmark.ps1`; i moduli `_Common.psm1`/`_Transport.psm1` e `tests/_Common.Tests.ps1` rimossi. - `smoke run --guest-os linux` e `--guest-os windows` passano. - `validate host` esce 0 su host configurato correttamente. - `creds set` sostituisce `Set-CIGuestCredential.ps1` sull'host Linux. - Decisione §4 applicata: nessun job CI su runner Linux richiede `pwsh`. - `setup-host-linux.sh` non installa più `pwsh` di default. - `pwsh --version` può essere assente sull'host Linux senza che alcun test, timer, job CI o procedura di RUNBOOK fallisca. - Suite pytest ≥90% coverage, verde. --- ## 8. Rollback I `.ps1` originali restano nel repo e funzionano su host Windows o su Linux con `pwsh` reinstallato (`setup-host-linux.sh --with-pwsh`). Il rollback è reinstallare `pwsh` e usare gli script esistenti. Nessuna distruzione di dati: il porting aggiunge comandi, non rimuove i `.ps1` finché il burn-in di validazione non è verde.