From 0f21e61668ee5c2e9ddeca89336cdda5765b1a1f Mon Sep 17 00:00:00 2001 From: Simone Date: Sat, 9 May 2026 21:15:43 +0200 Subject: [PATCH] docs(todo): merge CONSIGLI backlog, add P0..P3 priorities and rationale - Unified TODO.md + CONSIGLI.md into single working document - Added priority levels P0 (security/reliability) through P3 (nice-to-have) - Added references to new docs/HOST-SETUP.md, WINDOWS-TEMPLATE-SETUP.md, LINUX-TEMPLATE-SETUP.md - Documented Assert-Step validation flow in Fase B - Updated open items with rationale and priority tagging --- TODO.md | 471 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 444 insertions(+), 27 deletions(-) diff --git a/TODO.md b/TODO.md index 1e992e5..c460091 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,22 @@ # TODO — Local CI/CD System - + + +> Documento unico di lavoro: roadmap, audit trail dei task completati, e backlog post-v1.0 +> con priorità e razionale (assorbito da `CONSIGLI.md`). Le voci aperte sono raggruppate +> per area e marcate **P0..P3**: +> +> **Doc di setup operativi**: +> - [docs/HOST-SETUP.md](docs/HOST-SETUP.md) — bootstrap macchina host (Setup-Host.ps1) +> - [docs/WINDOWS-TEMPLATE-SETUP.md](docs/WINDOWS-TEMPLATE-SETUP.md) — provisioning template Windows (Prepare + Setup-TemplateVM) +> - [docs/LINUX-TEMPLATE-SETUP.md](docs/LINUX-TEMPLATE-SETUP.md) — bozza/TODO template Linux (non implementato) +> +> - **P0** — sicurezza o affidabilità: affrontare prima di estendere il sistema +> - **P1** — operatività quotidiana: automatizzare manutenzione e debug +> - **P2** — performance e qualità del codice +> - **P3** — estensioni nice-to-have + +--- ## Setup & Infrastructure @@ -71,13 +87,24 @@ .\Prepare-TemplateSetup.ps1 -VMIPAddress 192.168.79.128 -SkipWindowsUpdate ``` Installa: WinRM config, utente `ci_build`, .NET SDK 10.0, VS Build Tools 2026, Python 3.13.3. + Lo script esegue validazione automatica ad ogni passaggio (`Assert-Step`): + - Pre-flight: IP ottetti 0-255, TCP/5985 raggiungibile, Setup-TemplateVM.ps1 presente + - Host WinRM: AllowUnencrypted, TrustedHosts + - Guest prep: `C:\CI` esiste, file copiato, size match + - Post-setup remoto (9 check): WinRM, user+admin, UAC, firewall, .NET, Python, MSBuild, CI dirs + Se qualsiasi check fallisce → script termina con errore → **non prendere lo snapshot**. - [x] Setup completato con successo (VS Build Tools 2026 exit code 0). + - [x] `Setup-TemplateVM.ps1` ora esegue validazione `Assert-Step` dopo ogni step interno + (WinRM, Firewall, User, UAC, Dirs, Defender, .NET, Python, VS Build Tools, Toolchain, + Cleanup, Final pre-snapshot gate) — throws se qualsiasi check fallisce (2026-05-09) ### Fase C — Spegni e prendi lo snapshot - [x] VM rimane su **VMnet8 (NAT)** — internet access permanente per build che richiedono pip/nuget/npm - [x] Spegni la VM: Start → Shut down - [x] Prendi snapshot: VM → Snapshot → Take Snapshot **Nome esatto: `BaseClean`** + **Prerequisito: `Prepare-TemplateSetup.ps1` deve essere uscito con exit 0** — tutti + gli `Assert-Step` passati, incluso il Final pre-snapshot gate nel guest. - [x] Lascia la VM spenta — non modificarla mai più dopo questo snapshot ### Fase D — Credenziali e config @@ -115,29 +142,412 @@ - [x] Push commit e verificare job in Gitea Actions UI - [x] Verificare artifact scaricabile da Gitea dopo build riuscita - [x] `gitea/workflows/lint.yml` creato — PSScriptAnalyzer su push/PR che toccano `.ps1` (2026-05-09) -- [ ] Adattare workflow per altri repository (generalizzare `BUILD_COMMAND` e `ARTIFACT_SOURCE`) +- [ ] **[P3] Adattare workflow per altri repository** — generalizzare `BUILD_COMMAND` e `ARTIFACT_SOURCE`. + Vedi anche §6.2 (composite action riutilizzabile). -## Performance & Maintenance +--- -- [ ] Benchmark: tempo creazione clone + tempo WinRM readiness -- [ ] Configurare NuGet package cache su shared folder host (vedi OPTIMIZATION.md) -- [ ] Pianificare refresh semestrale snapshot template VM (KMS lease = 180 giorni): - Boot template su VMnet8 (NAT) → `slmgr /ato` → nuovo snapshot BaseClean -- [ ] Monitoraggio Windows Event Log per fallimenti servizio act_runner -- [ ] Configurare retention artifact (pulizia `F:\CI\Artifacts` più vecchi di N giorni) -- [ ] **Scheduled task per `Cleanup-OrphanedBuildVMs.ps1`** - Creare via Task Scheduler o estendere `Setup-Host.ps1`. Suggerito: ogni 6 ore, `-MaxAgeHours 4`. +## 1. Sicurezza & hardening -## Open Bug Fixes +### 1.1 [P0] Migrare WinRM da HTTP/Basic a HTTPS/5986 +File: [template/Setup-TemplateVM.ps1:179-198](template/Setup-TemplateVM.ps1), [scripts/Invoke-RemoteBuild.ps1:82-91](scripts/Invoke-RemoteBuild.ps1). -- [ ] **Validazione IP ottetti** — `scripts/Invoke-CIJob.ps1` - `ValidatePattern` attuale accetta `999.x.x.x`. Sostituire con validazione per-ottetto 0-255. +**Motivazione**: la combo `AllowUnencrypted=true` + `Auth/Basic=true` invia credenziali del +`ci_build` (admin) in chiaro su VMnet8. Anche in lab isolato, l'host può essere compromesso +via altri vettori e scrapare la rete VMware. Il piano è già in `docs/BEST-PRACTICES.md §2`; +manca solo l'esecuzione. -- [ ] **Verifica SHA256 installer** — `template/Setup-TemplateVM.ps1` - Python, VS BuildTools, `dotnet-install.ps1` scaricati senza verifica hash. Aggiungere - `-ExpectedHash` o hash hardcoded per le versioni pinnate. +**Azioni**: +- [ ] Generare cert self-signed nel template *prima* dello snapshot. +- [ ] Sostituire `New-PSSession -ComputerName $ip` con `-UseSSL -Port 5986` in `Invoke-RemoteBuild.ps1` e `Get-BuildArtifacts.ps1`. +- [ ] Rimuovere `AllowUnencrypted=true` dal `Setup-TemplateVM.ps1`. +- [ ] Tenere `-SkipCACheck` lato host: per cert lab self-signed è accettabile, ma documentare la motivazione inline. +- [ ] Regole firewall — limitare WinRM alla subnet build VM (`192.168.79.0/24` — VMnet8 NAT). -## In-VM Git Clone (Ottimizzazione) +### 1.2 [P0] Restringere `TrustedHosts` lato host +File: probabile `Setup-Host.ps1` (e in vari run setup) — pattern `*` è incompatibile con altri carichi sull'host Windows 11. + +Sostituire con la subnet build: +```powershell +Set-Item WSMan:\localhost\Client\TrustedHosts -Value '192.168.79.*' -Force -Concatenate +``` + +### 1.3 [P0] Pinning hash SHA256 degli installer +File: [template/Setup-TemplateVM.ps1:332-399](template/Setup-TemplateVM.ps1), [template/Setup-TemplateVM.ps1:401-502](template/Setup-TemplateVM.ps1). + +**Motivazione**: Python, `dotnet-install.ps1`, `vs_buildtools.exe` vengono scaricati senza +verifica integrità. Un MITM nella rete dell'host (anche temporaneo) può iniettare binari +compromessi nel template, che poi viene snapshottato e usato da *ogni* build. + +Pattern minimale: +```powershell +$expected = '6F25A7DF...' # SHA256 pinnato per la versione esatta +$actual = (Get-FileHash $pyInstallerPath -Algorithm SHA256).Hash.ToLower() +if ($actual -ne $expected.ToLower()) { throw "Hash mismatch: $actual" } +``` +Aggiungere un blocco hash per ogni download e bloccarli in costanti `$script:Hashes`. +Aggiornare al cambio versione (è raro). + +### 1.4 [P1] Validazione IP per-ottetto +File: [scripts/Invoke-CIJob.ps1:106](scripts/Invoke-CIJob.ps1), [scripts/Invoke-RemoteBuild.ps1:52](scripts/Invoke-RemoteBuild.ps1), [scripts/Get-BuildArtifacts.ps1:42](scripts/Get-BuildArtifacts.ps1), [scripts/Wait-VMReady.ps1:43](scripts/Wait-VMReady.ps1). + +**Motivazione**: `'^(\d{1,3}\.){3}\d{1,3}$'` accetta `999.999.999.999`. Sostituire con regex +per-ottetto: +```powershell +$ipv4 = '^((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$' +[ValidatePattern($ipv4)] +``` +Estrarre la costante in un modulo condiviso `scripts/_Common.psm1` per evitare drift fra i 4 file (vedi §5.2). + +### 1.5 [P1] PAT mai persistito quando si abilita `-UseGitClone` +Quando arriva il momento di implementare il clone in-VM (vedi §3.3 / sezione "In-VM Git Clone"): +- [ ] Recuperare il PAT da Credential Manager dell'host **subito prima** della WinRM session, mai prima. +- [ ] Iniettare via `$using:cred` in `Invoke-Command` e cancellare la variabile in un `finally` interno alla scriptblock. +- [ ] Aggiungere un grep automatico nei log job: se il PAT compare grezzo, fallire la build. + +### 1.6 [P2] Defender + Firewall + UAC tutti disattivati nel template — documentare il modello di minaccia +File: [template/Setup-TemplateVM.ps1:200-329](template/Setup-TemplateVM.ps1). + +Attualmente: `Set-NetFirewallProfile ... -Enabled False`, `EnableLUA=0`, `DisableAntiSpyware=1`, +`DisableRealtimeMonitoring=1`, `LocalAccountTokenFilterPolicy=1`. + +Le scelte sono ragionevoli per un template lab efimero, ma vanno raccolte in un'unica sezione +`BEST-PRACTICES.md §X — Threat Model & Hardening Trade-offs` che indichi: +- Cosa è disattivato e perché (costo build vs. superficie d'attacco). +- Quali condizioni rendono il modello inaccettabile (es. condivisione dell'host, esposizione + VMnet8 a LAN aziendale, build di codice di terze parti non fidate). +- Mitigazioni se uno di quei vincoli salta (Firewall On con regola WinRM esplicita, + Defender con esclusione `C:\CI`, UAC On con `LocalAccountTokenFilterPolicy=1`). + +Senza questa nota, future modifiche possono accumulare ulteriori riduzioni di sicurezza +senza tracciamento. + +### 1.7 [P2] Rotazione password guest VM +- [ ] Trimestrale. Aggiornare credenziale `BuildVMGuest` in Credential Manager + password + effettiva nel template (richiede refresh snapshot — coordinare con §2.5). + +### 1.8 [P2] Verifica Get-StoredCredential +- [ ] Confermare che `Get-StoredCredential` funzioni correttamente in tutti gli script che + lo usano (post-migrazione HTTPS). + +--- + +## 2. Affidabilità & resilienza + +### 2.1 [P0] Race su IP allocation con `capacity: 4` +File: [runner/config.yaml:17](runner/config.yaml), [scripts/Invoke-CIJob.ps1:244-253](scripts/Invoke-CIJob.ps1). + +**Motivazione**: con 4 job paralleli e DHCP VMnet8, due VM possono ottenere lo stesso IP se +la lease pool è stretta o se due `vmrun start` rispondono troppo vicini. +`getGuestIPAddress` ritorna l'IP visto dalla VM stessa, quindi la collisione non viene +rilevata in fase di Wait-VMReady — apparirà come "WinRM risponde ma è la VM sbagliata". + +**Opzioni**: +- **A** — IP allocator file-based con lock: prendere un IP libero da `192.168.79.101..104`, + scriverlo in `F:\CI\State\ip-leases\` e iniettarlo come `bootArgs` o via + `vmrun writeVariable` prima di start. Rilascio nel `finally`. +- **B** — DHCP reservation per MAC nel VMware NAT DHCP server (`vmnetdhcp.conf`): assegnare + 4 MAC noti, hard-coded nei VMX dei cloni. Più semplice ma richiede gestire il VMX clonato. +- **C** — pool fissato a `capacity: 1` finché non si implementa A o B. + +L'opzione A è la più portabile e si integra con il pre-warm pool (§3.4). + +### 2.2 [P1] Cleanup orfani schedulato +File: [scripts/Cleanup-OrphanedBuildVMs.ps1](scripts/Cleanup-OrphanedBuildVMs.ps1) — script pronto, manca lo scheduling. + +Estendere `Setup-Host.ps1` per registrare un Task Scheduler: +```powershell +$action = New-ScheduledTaskAction -Execute 'powershell.exe' ` + -Argument '-NoProfile -NonInteractive -ExecutionPolicy Bypass -File "N:\Code\Workspace\Local-CI-CD-System\scripts\Cleanup-OrphanedBuildVMs.ps1"' +$trigger = New-ScheduledTaskTrigger -Daily -At 4am -RandomDelay (New-TimeSpan -Minutes 30) +$principal = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -RunLevel Highest +Register-ScheduledTask -TaskName 'CI-CleanupOrphans' -Action $action -Trigger $trigger -Principal $principal -Force +``` +Aggiungere anche un trigger `AtStartup` per gestire crash dell'host. +Suggerito: ogni 6 ore, `-MaxAgeHours 4`. + +### 2.3 [P1] Retention artifact + log automatica +File: [docs/OPTIMIZATION.md:160-181](docs/OPTIMIZATION.md) — la logica c'è solo come snippet, non eseguita. + +Stessa pattern di §2.2 ma su `F:\CI\Artifacts` con `-AddDays(-30)` e su `F:\CI\Logs` con la +finestra già configurata in `Invoke-CIJob.ps1`. Aggiungere +`Get-PSDrive F | Where-Object { $_.Free -lt 50GB }` come *guard*: se libero < 50 GB, +retention più aggressiva (7 giorni) e log warning. + +### 2.4 [P1] `Remove-BuildVM.ps1` — supportare `-WhatIf` +File: [scripts/Remove-BuildVM.ps1:28](scripts/Remove-BuildVM.ps1). + +Aggiungere `[CmdletBinding(SupportsShouldProcess)]` come fatto in `Cleanup-OrphanedBuildVMs.ps1`. +Permette debug e dry-run senza forkare un secondo script. + +### 2.5 [P1] Snapshot versionato `BaseClean_` +File: [docs/BEST-PRACTICES.md:142-145](docs/BEST-PRACTICES.md), [scripts/Invoke-CIJob.ps1:100](scripts/Invoke-CIJob.ps1). + +**Motivazione**: quando si refresha il template (KMS lease semestrale, update toolchain), il +flusso attuale richiede di sovrascrivere `BaseClean` — i cloni esistenti diventano invalidi +e non c'è rollback. + +**Strategia**: +- Naming: `BaseClean_20260509`. +- `runner/config.yaml` aggiunge `GITEA_CI_SNAPSHOT_NAME` come env var. +- `Invoke-CIJob.ps1` legge da env, default `'BaseClean'` per compat. +- Pratica: tieni gli ultimi 2 snapshot, cancella il più vecchio dopo 1 settimana di uso pulito del nuovo. + +Si lega al task: refresh semestrale snapshot template VM (KMS lease = 180 giorni). +Boot template su VMnet8 (NAT) → `slmgr /ato` → nuovo snapshot. + +### 2.6 [P2] Backup automatico VMDK template +File: [docs/BEST-PRACTICES.md:130-138](docs/BEST-PRACTICES.md) — solo come snippet manuale. + +Pre-snapshot: copia atomica del `parent` VMDK in `F:\CI\Backups\Template_\`. Su errore +di refresh (es. installer rotto), rollback in 1 minuto. + +### 2.7 [P2] Health check del runner + monitoraggio Event Log +File: [docs/BEST-PRACTICES.md:101-115](docs/BEST-PRACTICES.md) — script presente in doc, non operativo. + +Schedulare ogni 15 min: query `gitea/api/v1/admin/runners`, se `local-windows-runner` non +`online` → `Restart-Service act_runner` + log evento. Limitare a 3 restart/h con cooldown. + +Inoltre: monitoraggio Windows Event Log per fallimenti servizio `act_runner` (alert via +EventLog query schedulata o webhook). + +--- + +## 3. Performance & throughput + +### 3.1 [P1] NuGet/pip cache su shared folder +File: [docs/OPTIMIZATION.md:93-128](docs/OPTIMIZATION.md), [scripts/Invoke-RemoteBuild.ps1:158-194](scripts/Invoke-RemoteBuild.ps1). + +**Motivazione**: `F:\CI\Cache\NuGet` esiste come dir, non viene mai usata. + +Aggiungere a `CI-WinBuild.vmx`: +```ini +sharedFolder0.present = "TRUE" +sharedFolder0.hostPath = "F:\\CI\\Cache\\NuGet" +sharedFolder0.guestName = "nuget-cache" +``` +Poi nello scriptblock di build: +```powershell +$env:NUGET_PACKAGES = '\\vmware-host\Shared Folders\nuget-cache' +``` +Equivalente per pip: +```powershell +$env:PIP_CACHE_DIR = '\\vmware-host\Shared Folders\pip-cache' +``` +Dopo lo snapshot refresh la cache va riscaldata una volta — accettabile. + +### 3.2 [P1] Sostituire `Compress-Archive` con 7-Zip o robocopy +File: [scripts/Invoke-RemoteBuild.ps1:109-122](scripts/Invoke-RemoteBuild.ps1). + +**Motivazione**: `Compress-Archive` è single-threaded e su repo medio-grandi (>100 MB sorgente) +può prendere 20-40 s. + +**Alternative**: +- **7-Zip** (richiede installazione nel template — vedi sezione "In-VM Git Clone" §B): + ```powershell + & 'C:\Program Files\7-Zip\7z.exe' a -mmt=on -mx1 $hostZip "$HostSourceDir\*" + ``` + Vantaggio: multi-thread, ratio simile con `-mx1`. +- **robocopy via admin share UNC** (`\\\C$\CI\build`): nessun zip/unzip, supporto delta, + ma richiede SMB aperto sulla VM — confliggente con §1.2. + +Misurare con un repo reale: probabile risparmio 10-20 s/build su `nsis-plugin-nsinnounp`. + +### 3.3 [P2] In-VM clone (`-UseGitClone`) +Implementazione disegnata di seguito (sezione "In-VM Git Clone — Ottimizzazione"). +Beneficio reale solo per repo > 200 MB con submoduli grandi; misurare prima. + +### 3.4 [P3] Pre-warm pool di cloni +File: [docs/OPTIMIZATION.md:133-156](docs/OPTIMIZATION.md). + +Solo se profilo dimostra che `New-BuildVM` + `Wait-VMReady` (~30-60 s) è il collo di bottiglia. +Con build di 2 minuti, l'overhead è ~40% — vale lo sforzo. Con build di 10+ minuti, no. + +Implementazione minima: scheduled task ogni 5 min mantiene 2 cloni avviati in +`F:\CI\WarmPool\`; `Invoke-CIJob` fa `Move-Item` di un clone caldo nel suo job dir e parte +da Phase 4 saltando Phase 2-3. + +### 3.5 [P2] vCPU/RAM tuning per workload +File: [docs/OPTIMIZATION.md:82-89](docs/OPTIMIZATION.md), VMX template. + +`numvcpus=4`, `memsize=6144` è ragionevole ma non ottimo per ogni build. Per +`nsis-plugin-nsinnounp` (4 build paralleli interni con thread divisi) 4 vCPU sono già saturati. + +Considerare: +- VMX pinning: 6 vCPU per build C++ pesanti, 2 vCPU per build .NET piccoli. +- Esporre `-VMCpu` / `-VMMemory` a `Invoke-CIJob.ps1` con override via workflow. + +### 3.6 [P2] Benchmark baseline +- [ ] Tempo creazione clone + tempo WinRM readiness (per stabilire baseline prima di §3.1/3.2/3.4). + +--- + +## 4. Osservabilità & manutenzione + +### 4.1 [P1] Log strutturati per parsing +File: [scripts/Invoke-CIJob.ps1:178-187](scripts/Invoke-CIJob.ps1). + +**Motivazione**: i log attuali sono `Write-Host` testuale. Per dashboard / alerting servono +log machine-readable. + +Aggiungere a fianco del transcript un secondo file `invoke-ci.jsonl`: +```powershell +function Write-JobEvent { + param([string]$Phase, [string]$Status, [hashtable]$Data = @{}) + $event = @{ + ts = (Get-Date).ToString('o') + jobId = $JobId + phase = $Phase + status = $Status + data = $Data + } + $event | ConvertTo-Json -Compress | Add-Content $jsonLog +} +``` +Emettere in ogni transizione di fase. Permette grafici (durata media per fase, tasso di +fallimento) con `jq` o Loki/Grafana se in futuro. + +### 4.2 [P2] Metriche su Prometheus textfile +Generare `F:\CI\Metrics\runner.prom` da uno scheduled task ogni 60s: +``` +ci_runner_orphan_vms 0 +ci_runner_disk_free_gb 423 +ci_runner_artifacts_total 247 +ci_runner_active_jobs 1 +``` +Se l'homelab ha già Prometheus + node_exporter, basta +`--collector.textfile.directory=F:\CI\Metrics`. + +### 4.3 [P1] Disk space alert +File: estendere `Setup-Host.ps1` o creare `scripts/Watch-DiskSpace.ps1`. + +`F:` riempito = build silenziosamente fallite (linked clone fallirà su `vmrun clone` con +messaggi criptici). Alert via `eventcreate` o webhook Gitea/Discord quando libero < 50 GB. + +### 4.4 [P2] Runbook per incident comuni +File: nuovo `docs/RUNBOOK.md`. + +Documentare con copy-pasta: +- "Runner offline in Gitea UI" → check service, log, restart. +- "Tutte le build falliscono in Phase 2" → `vmrun -T ws list`, parent VMDK lock, snapshot mancante. +- "Build lente" → check disk free, vmware-vmx.exe CPU, rete VMnet8. +- "VMX corrotto post-crash host" → restore from `F:\CI\Backups\Template_`. + +Ogni voce: sintomo, comando di triage, fix, escalation. + +### 4.5 [P3] Dashboard read-only +Una pagina HTML statica generata da `Invoke-CIJob.ps1` (append a `F:\CI\dashboard.html`) +con ultime 50 build, durata, esito, link agli artifact. Servita da IIS Express o solo +file:// — utile per debug a colpo d'occhio senza aprire Gitea UI. + +--- + +## 5. Qualità codice & test + +### 5.1 [P1] Pester smoke tests sugli script +File: nuovo `tests/` directory. + +**Motivazione**: manca un livello di test sotto l'e2e. + +Pester può coprire: +- `New-BuildVM` con vmrun mockato — verifica che il VMX path costruito sia ben formato + per JobId con caratteri speciali. +- `Wait-VMReady` con `Test-WSMan` mockato — verifica timeout, fasi, ritorni. +- `Remove-BuildVM` con `vmrun list` mockato — verifica retry deleteVM. +- Validazione IP regex (§1.4) — table tests. + +Eseguire in CI tramite il runner stesso (workflow `lint.yml` esiste già — espandere). + +### 5.2 [P2] Modulo PowerShell condiviso `scripts/_Common.psm1` +**Duplicazioni da estrarre**: +- `New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck` (3 file). +- `ValidatePattern` IP (4 file — vedi §1.4). +- Risoluzione `vmrun.exe` (3 file). +- `Test-Path` + `New-Item` per dir lazy creation. +- Function `Invoke-VmrunCommand` con gestione `$LASTEXITCODE`. + +Risultato: meno LoC, fix in un punto solo, più facile da testare. + +### 5.3 [P2] Esecuzione `vmrun` con check exit code uniforme +Pattern attuale ripetuto in tutti gli script che invocano `vmrun`: +```powershell +$out = & $VmrunPath ... 2>&1 +if ($LASTEXITCODE -ne 0) { throw "..." } +``` +Wrapping in `Invoke-VmrunCommand -Operation 'clone' -Args @(...)` riduce errori di copy-paste +e centralizza retry/log. + +### 5.4 [P2] PSScriptAnalyzer rules custom +File: [gitea/workflows/lint.yml](gitea/workflows/lint.yml) (già esiste). + +Aggiungere regole specifiche progetto (`PSScriptAnalyzerSettings.psd1` in root): +- `PSAvoidUsingPlainTextForPassword` — rilevante per `Setup-TemplateVM.ps1:55`. +- `PSAvoidUsingInvokeExpression`. +- `PSUseShouldProcessForStateChangingFunctions`. +- Regole custom: vietare hardcoded `F:\CI\` fuori da config (forzare param/env). + +### 5.5 [P3] Type hints nei param block +Già parzialmente fatto. Estendere a tutti gli script per migliorare IntelliSense e +validazione runtime. + +--- + +## 6. Scalabilità & estensioni + +### 6.1 [P2] Linux Build VM +**Documento di pianificazione dedicato**: [docs/LINUX-TEMPLATE-SETUP.md](docs/LINUX-TEMPLATE-SETUP.md) +— bozza completa con fasi A→H, decisioni di design, differenze rispetto al template Windows. + +Vedi anche sezione "Linux Build VM" sotto per il riassunto inline. + +**Considerazione architetturale**: SSH su WSL2 non basta — serve VM vera per parità con il +flusso Windows. Ubuntu 24.04 minimal con script bash diretto (parità con flusso Windows). +Sostituire WinRM con SSH key-based; `Invoke-Command` non funziona — usare `ssh.exe` + +`scp.exe` o il modulo `Posh-SSH`. + +Aggiungere `scripts/_Transport.psm1` con due implementazioni (`WinRM`, `SSH`) dietro la +stessa interfaccia. `Invoke-CIJob.ps1` sceglie dal parametro `-GuestOS`. + +### 6.2 [P3] Workflow generico riutilizzabile (composite action) +File: [gitea/workflow-example.yml](gitea/workflow-example.yml). + +Trasformare in *composite action* Gitea (`.gitea/actions/local-ci-build/action.yml`) +richiamabile da qualsiasi repo: +```yaml +- uses: ./Simone/local-ci-build@v1 + with: + build-command: 'python build_plugin.py --final' + artifact-source: 'dist' + submodules: true +``` +Riduce la duplicazione su nuovi repo e centralizza l'evoluzione del wrapper. + +### 6.3 [P3] Multi-host runner federation +Quando 4 VM in parallelo non bastano, l'opzione naturale è un secondo host Windows con +stesso `Setup-Host.ps1` registrato come secondo runner Gitea (label `windows-build:host-2`). +Già supportato lato Gitea, basta replicare il setup. + +**Premessa**: prima di scalare orizzontale, profilare se il collo di bottiglia è CPU +(i9-10900X 20T è abbondante) o I/O (NVMe). Se è I/O, una seconda NVMe sullo stesso host basta. + +### 6.4 [P3] Build matrix nel workflow +File: [gitea/workflows/build-nsis.yml](gitea/workflows/build-nsis.yml). + +Attualmente single job. Quando arriverà la VM Linux: +```yaml +strategy: + matrix: + target: [windows, linux] +runs-on: ${{ matrix.target }}-build +``` + +### 6.5 [P3] Secret injection workflow-level +Per chiavi di firma (Authenticode, GPG), usare i Gitea secrets nel workflow e passarli a +`Invoke-CIJob.ps1` come param + env, mai loggati. Stesso modello di §1.5 per il PAT. + +--- + +## In-VM Git Clone (Ottimizzazione) — riferimento §3.3 Sfruttare l'accesso internet della VM (VMnet8 NAT) per fare il `git clone` direttamente nella VM, eliminando il ciclo host-clone → zip → WinRM-transfer → unzip. @@ -176,7 +586,7 @@ VM avviata → WinRM: git clone --recurse-submodules https://@gitea/... - [ ] **Setup-TemplateVM.ps1 — altri tool utili** - [ ] **7-Zip**: installer silenzioso — molto più veloce di `Compress-Archive`/`Expand-Archive` - per archivi grandi (es. npm/NuGet cache warm) + per archivi grandi (es. npm/NuGet cache warm). Necessario anche per §3.2. - [ ] **curl.exe**: già presente in Windows 11/Server 2025 (v7.x) — verificare disponibilità - [ ] Valutare: `jq` (parsing JSON in script PowerShell o bash) — opzionale @@ -209,7 +619,7 @@ VM avviata → WinRM: git clone --recurse-submodules https://@gitea/... --- -## Linux Build VM (Future) +## Linux Build VM (Future) — riferimento §6.1 Aggiungere supporto per build su Linux per testare la compilazione cross-platform (es. versione Linux del plugin o build check con GCC/Clang). @@ -225,9 +635,10 @@ Aggiungere supporto per build su Linux per testare la compilazione cross-platfor - [ ] Aggiungere parametro `-GuestOS` (`Windows` / `Linux`) o rilevamento automatico da VMX - [ ] Sostituire WinRM con SSH + SCP per trasferimento zip e raccolta artifacts - [ ] Aggiungere supporto a comandi Linux (`bash`, `make`, `cmake --build`) + - [ ] Astrarre transport in `scripts/_Transport.psm1` (vedi §6.1) - [ ] **Workflow Gitea — build matrix** - - [ ] Definire matrix strategy `[windows-build, linux-build]` nel workflow + - [ ] Definire matrix strategy `[windows-build, linux-build]` nel workflow (vedi §6.4) - [ ] Aggiungere label `linux-build` al runner (o registrare runner separato se necessario) - [ ] Verificare che artifacts da entrambe le piattaforme vengano raccolti correttamente @@ -237,13 +648,19 @@ Aggiungere supporto per build su Linux per testare la compilazione cross-platfor --- -## Security Hardening (Post-MVP) +## Suggerimento di sequencing -- [ ] Passare WinRM da HTTP (5985) a HTTPS (5986) con certificato self-signed -- [ ] Rimuovere `AllowUnencrypted=true` dalla config WinRM dopo migrazione HTTPS -- [ ] Verificare che Get-StoredCredential funzioni correttamente negli script -- [ ] Regole firewall — limitare WinRM alla subnet build VM (192.168.79.0/24 — VMnet8 NAT) -- [ ] Rotazione password guest VM trimestralmente +Sprint progressivi per ridurre rischio / ottenere valore prima: + +1. **Sprint 1 (sicurezza)** — §1.1, §1.2, §1.3, §1.4 — superficie di attacco e bug noti. +2. **Sprint 2 (operatività)** — §2.1, §2.2, §2.3, §2.5 — rendere il sistema "fire and forget". +3. **Sprint 3 (osservabilità)** — §4.1, §4.3, §4.4 — visibilità prima di estendere. +4. **Sprint 4 (perf)** — §3.1, §3.2 misurati su un repo reale (baseline §3.6). +5. **Sprint 5 (qualità)** — §5.1, §5.2 — rifattorizzazione con safety net di test. +6. **Sprint 6+ (estensioni)** — Linux VM, workflow generico/composite action, federation. + +Tenere ogni sprint piccolo: 1-2 voci alla volta, validare e2e dopo ognuna prima di passare +alla successiva. ---