Files
local-ci-cd-system/TODO.md
T
Simone 4f22d11a84
Lint / pssa (push) Failing after 26s
Lint / python (push) Successful in 52s
feat(build): live-stream Linux build output; ns7zip via in-guest clone
- SshTransport.run_streaming: incremental channel recv, forwards
  stdout/stderr live (no more one-block-at-end). _linux_build uses it
  with PYTHONUNBUFFERED so the guest python flushes promptly.
- _tail_lines split out for failure messages (no double print).
- Windows live streaming deferred (TODO 8.2) — pypsrp execute_ps
  returns only at completion.
- build-ns7zip.yml: use-git-clone:'true' (in-guest), repo-url ->
  https://gitea.emulab.it/... (guest-reachable; host SSH alias was
  host-only). Requires GiteaPAT in the LocalSystem keyring or a public
  nsis-plugin-ns7zip.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 20:51:48 +02:00

52 KiB
Raw Permalink Blame History

TODO — Local CI/CD System

Documento unico di lavoro: roadmap, audit trail dei task completati, e backlog post-v1.0 con priorità e razionale. Le voci aperte sono raggruppate per area e marcate P0..P3:

Doc di setup operativi:

  • docs/HOST-SETUP.md — bootstrap macchina host (Setup-Host.ps1)

  • docs/WINDOWS-TEMPLATE-SETUP.md — provisioning template Windows (Deploy + Prepare + Install-CIToolchain-WinBuild2025)

  • docs/LINUX-TEMPLATE-SETUP.md — provisioning template Linux Ubuntu 24.04 (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


Summary

Last updated: 2026-05-11 (post Sprint 15: §7.5 DONE — Rinomina Setup-* → Install-CIToolchain-* (WinBuild2025/2022/Linux2404); post Sprint 14: §6.4+§6.5 DONE)

Stato generale: §1, §2, §4, §5, §7 chiusi. §3 completo. §6 chiuso: 6.1-6.2 DONE, 6.3 deferred, 6.4-6.6 DONE. Prossimi: Test Plan validation con VM reali.

Stato Area Done Open Note
[x] Setup & Infrastructure 8 0 Gitea + runner + dirs + rete tutti operativi
[x] Template VM (Fasi A→D) 4 0 Snapshot BaseClean preso, credenziali in Credential Manager
[x] Scripts Verification 3 0 e2e-008/009 SUCCESS, cleanup orfani + retry deleteVM ok
[x] Runner Configuration 2 0 config.yaml, capacity 4, BuildVMGuest
[x] Gitea Workflow Integration 5 0 tutti completati — example.yml usa composite action
[x] §1 Sicurezza & hardening 3 0 1.1, 1.4, 1.6 done; 1.2/1.3/1.5/1.7/1.8 deferred (home lab)
[x] §2 Affidabilità & resilienza 7 0 tutto done (2.1-2.7)
[x] §3 Performance & throughput 4 0 3.1/3.2/3.3/3.6 done; 3.4/3.5 deferred — §3 CHIUSO
[x] §4 Osservabilità & manutenzione 3 0 4.1/4.3/4.4 done (4.2 Prometheus, 4.5 Dashboard rimossi)
[x] §5 Qualità codice & test 5 0 5.1/5.2/5.3/5.4/5.5 done
[x] §6 Scalabilità & estensioni 5 0 6.1-6.2 done, 6.3 deferred (home lab), 6.4-6.5 done, 6.6 done
[x] §7 Refactor Deploy ↔ Setup 5 0 7.1-7.5 done; Setup-* → Install-CIToolchain-* (2026-05-11)
[x] In-VM Git Clone (§3.3) 4 0 COMPLETATO 2026-05-10 — e2e PASS: 34s/25.7% vs baseline
[x] Linux Build VM (§6.1) 5 0 Deploy/Prepare/Setup/Transport + doc + e2e PASS nsis7z.dll 2272 KB

Prossimi passi consigliati (vedi anche "Suggerimento di sequencing" in fondo):

  1. Test Plan — eseguire Invoke-Pester tests\ -Output Detailed + validare §2.1/§3.1/§3.6 con VM reali
  2. Test Plan — validazione con VM reali (§2.1 IP race, §3.1 shared cache, §3.6 benchmark, §4.1 JSONL) — prossima priorità
  3. Security — Rifiori se condizioni cambiano; vedi sezione "Deferred (Home Lab)"
  4. §3.5 — vCPU/RAM tuning per workload (P2, deferred — home lab optimization)
  5. Validate-SetupState.ps1 — update riferimento a Install-CIToolchain-* se compare il vecchio nome

Setup & Infrastructure

  • Gitea Server — già in esecuzione su http://10.10.20.11:3100 (e https://gitea.emulab.it)

    • Runner registration token ottenuto e usato
    • Create at least one test repository with .gitea/workflows/build.yml (Simone/nsis-plugin-ns7zip — testato e2e, workflow in gitea/workflows/build-ns7zip.yml)
    • Gitea Actions abilitato (runner registrato con successo)
  • act_runner — installato e registrato sull'host Windows

    • Binario gitea-runner v1.0.2 scaricato in F:\CI\act_runner\act_runner.exe
    • Registrato con Gitea (http://10.10.20.11:3100) — runner ID 1, nome local-windows-runner
    • config.yaml copiato in F:\CI\act_runner\config.yaml con label windows-build:host
    • Installato come servizio Windows via NSSM — stato: Running, StartType: Automatic
    • Verificare che il runner appaia "Online" nell'UI Gitea Admin → Actions → Runners
    • Confermare riavvio automatico dopo reboot host
  • Directory CI create su F:\CI\

    • F:\CI\BuildVMs\
    • F:\CI\Artifacts\
    • F:\CI\act_runner\
    • F:\CI\Cache\NuGet\
    • F:\CI\RunnerWork\
    • F:\CI\Templates\WinBuild2025\
    • F:\CI\Logs\ — log per job (retention: 30 giorni)
    • F:\CI\ISO\ — contiene 26100.1742.240906-0331.ge_release_svc_refresh_SERVER_VOL_x64FRE_en-us.iso (Windows Server 2025)
  • CredentialManager PowerShell module v2.0 installato (Scope: CurrentUser)

  • Rete VM: VMnet8 (NAT) — internet access per pip/nuget/npm durante i build

Template VM

  • Provision template VM in VMware Workstation — segui questi passi nell'ordine esatto:

    Fase A — Crea e installa la VM (NIC: NAT per internet)

    • Crea nuova VM in VMware Workstation con queste impostazioni: - 4 vCPU, 6144 MB RAM, disco 80 GB thin - VMX path: F:\CI\Templates\WinBuild2025\WinBuild2025.vmx - NIC: VMnet8 (NAT) ← internet necessario per Windows Update e installer - CD-ROM: F:\CI\ISO\26100.1742.240906-0331.ge_release_svc_refresh_SERVER_VOL_x64FRE_en-us.iso
    • Installa Windows Server 2025 dall'ISO
    • All'interno della VM (come Administrator), abilita WinRM: cmd winrm quickconfig -q powershell Enable-PSRemoting -Force -SkipNetworkProfileCheck Set-Item WSMan:\localhost\Service\Auth\Basic $true -Force # AllowUnencrypted left false — Deploy post-install.ps1 configures HTTPS/5986 listener Set-Item WSMan:\localhost\Client\TrustedHosts -Value '*' -Force
    • Attiva Windows Server 2025 (prima dello snapshot — i linked clone ereditano l'attivazione): cmd slmgr /dli Se non attivato, scegli il metodo appropriato: - KMS (server KMS in rete): slmgr /skms <IP_KMS> poi slmgr /ato - MAK/Retail key: slmgr /ipk XXXXX-XXXXX-XXXXX-XXXXX-XXXXX poi slmgr /ato - KMS pubblico (alternativa lab): vedi https://github.com/robin113x/Windows-Server-Activation/ Verifica: slmgr /xpr — deve mostrare attivazione permanente o scadenza lontana
    • Nota l'IP assegnato dal DHCP di VMnet8 (es. 192.168.79.x) — ipconfig nella VM

    Fase B — Provisioning automatico dall'host

    • Dall'host, esegui: powershell cd n:\Code\Workspace\Local-CI-CD-System\template .\Prepare-WinBuild2025.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/5986 raggiungibile, Install-CIToolchain-WinBuild2025.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.
    • Setup completato con successo (VS Build Tools 2026 exit code 0).
    • Install-CIToolchain-WinBuild2025.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

    • VM rimane su VMnet8 (NAT) — internet access permanente per build che richiedono pip/nuget/npm
    • Spegni la VM: Start → Shut down
    • Prendi snapshot: VM → Snapshot → Take Snapshot Nome esatto: BaseClean Prerequisito: Prepare-WinBuild2025.ps1 deve essere uscito con exit 0 — tutti gli Assert-Step passati, incluso il Final pre-snapshot gate nel guest.
    • Lascia la VM spenta — non modificarla mai più dopo questo snapshot

    Fase D — Credenziali e config

    • Archivia credenziali guest sull'host (PowerShell elevato con CredentialManager): powershell New-StoredCredential -Target "BuildVMGuest" -UserName "ci_build" ` -Password "<your-build-password>" -Persist LocalMachine
    • Verifica GITEA_CI_TEMPLATE_PATH in F:\CI\act_runner\config.yaml — aggiornato a WinBuild2025.vmx (2026-05-08)

Scripts Verification

  • Test New-BuildVM.ps1 standalone — clone Clone_test-002 creato correttamente (2026-05-08)
  • Test Wait-VMReady.ps1 standalone — exit 0 in ~5s, VM pronta (2026-05-08)
  • Test Invoke-RemoteBuild.ps1 — dotnet restore + build OK, artifacts.zip creato in VM (2026-05-08)
  • Test Get-BuildArtifacts.ps1 — artifacts.zip (78 KB) copiato in F:\CI\Artifacts\test-003\ (2026-05-08)
  • Test Remove-BuildVM.ps1 — VM spenta + directory rimossa correttamente (2026-05-08)
  • Test Invoke-CIJob.ps1 end-to-end su una soluzione reale (nsis-plugin-ns7zip)
    • e2e-008: SUCCESS — build OK + artifact raccolto (1632 KB)
    • e2e-009: SUCCESS — cleanup automatico VM + clone confermato (finally block)
  • scripts/Cleanup-OrphanedBuildVMs.ps1 creato e verificato — -WhatIf, soglia -MaxAgeHours, hard stop + deleteVM + rimozione dir (2026-05-09)
  • scripts/Remove-BuildVM.ps1 fix vmrun deleteVM exit -1 — poll vmrun list + retry 3× backoff 0/3/6s (2026-05-09)

Runner Configuration

  • runner/config.yaml aggiornato con percorsi F:\CI\, rete VMnet8 (NAT), label corretti
  • capacity: 4 configurato (64 GB RAM / ~8 GB per VM)
  • Aggiornare GITEA_CI_TEMPLATE_PATH in config.yaml dopo creazione template VM
  • Archiviare credenziali guest in Windows Credential Manager (target: BuildVMGuest)

Gitea Workflow Integration

  • Copiare gitea/workflow-example.yml in .gitea/workflows/build.yml nel repo di test (workflow build-ns7zip.yml già presente e funzionante per nsis-plugin-ns7zip)
  • Push commit e verificare job in Gitea Actions UI
  • Verificare artifact scaricabile da Gitea dopo build riuscita
  • gitea/workflows/lint.yml creato — PSScriptAnalyzer su push/PR che toccano .ps1 (2026-05-09)
  • [P3] Adattare workflow per altri repository — generalizzare BUILD_COMMAND e ARTIFACT_SOURCE. COMPLETATO 2026-05-11: gitea/workflow-example.yml riscritto per usare la composite action Simone/local-ci-cd-system/.gitea/actions/local-ci-build@main. Commenti inline guidano la personalizzazione di build-command, artifact-source, submodules, SSH URL, extra-guest-env-json e artifact-name. Nessuna logica di orchestrazione nei repo chiamanti.

1. Sicurezza & hardening

1.1 [P0] [x] Migrare WinRM da HTTP/Basic a HTTPS/5986 — COMPLETATO 2026-05-10

Azioni:

  • Generare cert self-signed nel template prima dello snapshot (già in Deploy post-install.ps1).
  • Sostituire New-PSSession -ComputerName $ip con -UseSSL -Port 5986 -Authentication Basic in Invoke-RemoteBuild.ps1, Get-BuildArtifacts.ps1, Prepare-WinBuild2025.ps1, Validate-*.ps1.
  • Rimuovere AllowUnencrypted=true da Deploy post-install.ps1 e Install-CIToolchain-WinBuild2025.ps1 (assertion → false).
  • -SkipCACheck/-SkipCNCheck/-SkipRevocationCheck mantenuti nei New-PSSessionOption e New-WSManSessionOption (cert lab self-signed — documentato inline).
  • Regola firewall WinRM-HTTPS in Deploy ristretta a RemoteAddress '192.168.79.0/24'.
  • Wait-VMReady.ps1 usa New-WSManSessionOption + Test-WSMan -Port 5986 -UseSSL.
  • Prepare-WinBuild2025.ps1: preflight TCP/5986, host non imposta più AllowUnencrypted; solo TrustedHosts viene salvato/ripristinato.
  • Validate-DeployState.ps1, Validate-SetupState.ps1: connessione HTTPS/5986, check AllowUnencrypted=false.

1.4 [P1] [x] Validazione IP per-ottetto — COMPLETATO 2026-05-10

Regex per-ottetto sostituita in tutti e 4 i file: '^((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)$'

Estrazione in scripts/_Common.psm1 — vedi §5.2 (P2, backlog).

1.6 [P2] [x] Defender + Firewall + UAC tutti disattivati nel template — documentare il modello di minaccia — COMPLETATO 2026-05-10

File: docs/BEST-PRACTICES.md:§2.1 Threat Model.

COMPLETATO: Sezione "2.1. Threat Model — Disabled Security Features" aggiunta a BEST-PRACTICES.md. Documenta:

  • Stato corrente: Defender, Firewall, UAC disabilitate (costi vs. benefici tabellati).
  • Quando è accettabile: ambiente lab isolato con code trusted.
  • Quando rompe: code non fidate, sharing host, esposizione VMnet8 a LAN.
  • Mitigazioni: come riabilitare Firewall, Defender con esclusioni, UAC con costi specifici.

Future modifiche di sicurezza vanno documentate nello stesso posto.


2. Affidabilità & resilienza

2.1 [P0] [x] Race su IP allocation — COMPLETATO 2026-05-10

File: runner/config.yaml:17, scripts/Invoke-CIJob.ps1:244-253.

Stato osservato: race non riprodotta in e2e-008/009 (un job alla volta). capacity: 4 resta attivo in produzione — bug teorico finché non si esegue stress test parallelo.

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\<jobid> 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] [x] Cleanup orfani schedulato — COMPLETATO 2026-05-10

File: scripts/Cleanup-OrphanedBuildVMs.ps1 — script pronto, scheduling registrato da scripts/Register-CIScheduledTasks.ps1.

Estendere Setup-Host.ps1 per registrare un Task Scheduler:

$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] [x] Retention artifact + log automatica — COMPLETATO 2026-05-10

File: scripts/Invoke-RetentionPolicy.ps1 — script creato; scheduling via scripts/Register-CIScheduledTasks.ps1.

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] [x] Remove-BuildVM.ps1 — supportare -WhatIf — COMPLETATO 2026-05-10

File: scripts/Remove-BuildVM.ps1:28.

[CmdletBinding(SupportsShouldProcess)] aggiunto; op distruttive (stop, deleteVM, Remove-Item) gated su $PSCmdlet.ShouldProcess.

2.5 [P1] [x] Snapshot versionato BaseClean_<yyyyMMdd> — COMPLETATO 2026-05-10

File: docs/BEST-PRACTICES.md:142-145, scripts/Invoke-CIJob.ps1:100.

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] [x] Backup automatico VMDK template — COMPLETATO 2026-05-10

File: scripts/Backup-CITemplate.ps1.

Copia atomica F:\CI\Templates\WinBuildF:\CI\Backups\Template_<yyyyMMdd_HHmmss>\. Ferma act_runner prima, lo riavvia nel finally. Prune automatico (default: mantieni 3). SupportsShouldProcess → supporta -WhatIf. Esecuzione manuale pre-refresh.

2.7 [P2] [x] Health check del runner + monitoraggio Event Log — COMPLETATO 2026-05-10

File: scripts/Watch-RunnerHealth.ps1; task registrato da scripts/Register-CIScheduledTasks.ps1 come CI-RunnerHealth (ogni 15 min).

Controlla Get-Service act_runner. Se non Running: EventId 1002 (Warning) + Restart-Service. Cooldown: max 3 restart/h via JSON state file F:\CI\State\runner-restart-log.json. Oltre il limite: EventId 1004 (Error) + webhook :sos: senza restart. Webhook opzionale Discord/Gitea identico a Watch-DiskSpace.ps1.


3. Performance & throughput

3.1 [P1] [x] NuGet/pip cache su shared folder — COMPLETATO 2026-05-10

File: scripts/Set-TemplateSharedFolders.ps1, scripts/Invoke-RemoteBuild.ps1.

Set-TemplateSharedFolders.ps1: edita il VMX template aggiungendo due shared folder (nuget-cacheF:\CI\Cache\NuGet, pip-cacheF:\CI\Cache\pip), idempotente, .bak del VMX originale mantenuto, SupportsShouldProcess.

Invoke-RemoteBuild.ps1: aggiunto -UseSharedCache switch. Quando attivo, inietta $env:NUGET_PACKAGES nel scriptblock dotnet restore/build e $env:PIP_CACHE_DIR nel scriptblock custom build command.

Attivazione:

  1. Fermare template VM.
  2. .\Set-TemplateSharedFolders.ps1 (una tantum, pre-snapshot).
  3. Passare -UseSharedCache a Invoke-RemoteBuild.ps1 nei job dotnet/pip.

Dopo snapshot refresh: cache si riscalda al primo build — accettabile.

3.2 [P1] [x] Sostituire Compress-Archive con 7-Zip — COMPLETATO 2026-05-10

File: scripts/Invoke-RemoteBuild.ps1 (3 rimpiazzi Compress-Archive → 7-Zip + fallback).

Implementazione:

  • Host-side: nuova funzione Compress-BuildArtifact (check 7-Zip, fallback Compress-Archive) usata per comprimere source tree
  • Guest-side (custom build): inline 7-Zip check in scriptblock per artifact compression
  • Guest-side (dotnet build): inline 7-Zip check in scriptblock per output directory compression
  • Usa -mmt=on -mx1 per multi-thread con ratio simile a Compress-Archive

Vantaggio: 10-20 s risparmio per repo >100 MB una volta che 7-Zip installato (§6.6). Attuale: Fallback a Compress-Archive finché 7-Zip non nel template — zero overhead.

3.3 [P2] [x] In-VM clone (-UseGitClone) — COMPLETATO 2026-05-10

File: scripts/Invoke-CIJob.ps1, scripts/Invoke-RemoteBuild.ps1.

Implementazione:

  • Invoke-CIJob.ps1: -UseGitClone switch + conditional Phase 1 (skip host clone)
  • Invoke-RemoteBuild.ps1: Mode 1 (host) vs Mode 2 (guest) + params (CloneUrl, CloneBranch, CloneCommit, CloneSubmodules)
  • Guest clone: git clone direttamente nel VM, PAT da Credential Manager (§1.5 no-log cleanup)
  • Prerequisiti satisfatti: Git + 7-Zip in template (§6.6, completato)

Beneficio: Elimina host-zip-transfer overhead (rilevante per repo > 200 MB con submoduli). Prossimo: E2E test con nsis-plugin-ns7zip (-UseGitClone flag) per misurare impatto.

3.5 [P2] [ ] vCPU/RAM tuning per workload — DEFERRED (home lab)

File: docs/OPTIMIZATION.md:82-89, VMX template.

numvcpus=4, memsize=6144 è ragionevole ma non ottimo per ogni build. Per nsis-plugin-ns7zip (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.

Deferred: Non necessario per home lab; priorità bassa fino a che performance non è bottleneck.

3.6 [P2] [x] Benchmark baseline — COMPLETATO 2026-05-10

File: scripts/Measure-CIBenchmark.ps1.

Misura 5 fasi per iterazione: clone, start, IP acquire, WinRM ready, destroy. Output: tabella console + append a F:\CI\Logs\benchmark.jsonl (JSONL, una riga per iterazione). Supporta -Iterations N per ridurre varianza. Importa _Common.psm1 (Invoke-Vmrun, Resolve-VmrunPath).

Uso: .\Measure-CIBenchmark.ps1 prima e dopo §3.1/§3.2 per misurare impatto.


4. Osservabilità & manutenzione

4.1 [P1] [x] Log strutturati per parsing — COMPLETATO 2026-05-10

File: scripts/Invoke-CIJob.ps1:178-187.

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:

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.3 [P1] [x] Disk space alert — COMPLETATO 2026-05-10

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] [x] Runbook per incident comuni — COMPLETATO 2026-05-10

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_<latest>.

Ogni voce: sintomo, comando di triage, fix, escalation.


5. Qualità codice & test

5.1 [P1] [x] Pester smoke tests sugli script — COMPLETATO 2026-05-10

File: tests/_Common.Tests.ps1, tests/New-BuildVM.Tests.ps1, tests/Remove-BuildVM.Tests.ps1, tests/Wait-VMReady.Tests.ps1.

Test con fake vmrun .cmd (exit code via %FAKE_VMRUN_EXIT% env var — nessuna VM reale):

  • _Common.psm1: New-CISessionOption TLS flags, Resolve-VmrunPath throw/return, Invoke-Vmrun ExitCode/Output/ThrowOnError
  • New-BuildVM.ps1: throw su template mancante, throw + cleanup su clone fail, formato nome Clone_{JobId}_{timestamp}
  • Remove-BuildVM.ps1: no-op su VMX mancante, cleanup dir parziale, -WhatIf non distrugge, destroy rimuove dir
  • Wait-VMReady.ps1: throw su vmrun mancante, throw su timeout, ValidatePattern IP (accetta/rifiuta)

Eseguire: Invoke-Pester tests\ -Output Detailed

5.2 [P2] [x] Modulo PowerShell condiviso scripts/_Common.psm1 — COMPLETATO 2026-05-10

File: scripts/_Common.psm1.

Esporta: New-CISessionOption (WinRM self-signed TLS), Resolve-VmrunPath (valida vmrun.exe), Invoke-Vmrun (wrapper uniforme -T ws, ritorna {ExitCode, Output}, supporta -ThrowOnError).

Importato da: Invoke-RemoteBuild.ps1, Get-BuildArtifacts.ps1, New-BuildVM.ps1.

5.3 [P2] [x] Esecuzione vmrun con check exit code uniforme — COMPLETATO 2026-05-10

Invoke-Vmrun in _Common.psm1. New-BuildVM.ps1 refactored per usarlo. Invoke-RemoteBuild.ps1 e Get-BuildArtifacts.ps1 usano New-CISessionOption.

5.4 [P2] [x] PSScriptAnalyzer rules custom — COMPLETATO 2026-05-10

File: PSScriptAnalyzerSettings.psd1.

Regole attive: PSAvoidUsingInvokeExpression, PSUseShouldProcessForStateChangingFunctions, PSUsePSCredentialType, PSAvoidUsingPlainTextForPassword, PSAvoidUsingConvertToSecureStringWithPlainText, PSAvoidGlobalVars, PSUseConsistentIndentation (4 spazi), PSUseConsistentWhitespace. Soppresso progetto-wide: PSAvoidUsingWriteHost (output strutturato per act_runner).

5.5 [P3] [x] Type hints nei param block — COMPLETATO 2026-05-10

File: tutti script in scripts/ — 15 file, tutti con type hints.

Coverage: Tutti param hanno type hints ([string], [int], [switch]) + validation ([ValidateRange], [ValidatePattern], [ValidateScript]) + [Parameter(Mandatory)] dove necessario.


6. Scalabilità & estensioni

6.1 [P2] [x] Linux Build VM

Documento di pianificazione dedicato: docs/LINUX-TEMPLATE-SETUP.md — bozza completa con fasi A→H, decisioni di design, differenze rispetto al template Windows.

Implementato — vedi 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] [x] Workflow generico riutilizzabile (composite action)

File: gitea/actions/local-ci-build/action.yml.

Status: COMPLETATO 2026-05-11 — Composite action implementata.

Inputs: build-command (required), artifact-source, submodules, guest-os, use-git-clone, configuration, template-path, snapshot-name, artifact-name, artifact-retention-days. Outputs: artifact-path, artifact-name. Inputs passati via variabili d'ambiente (no injection). Upload artifact incluso nell'action.

Usage da qualsiasi repo:

jobs:
  build:
    runs-on: windows-build   # or linux-build
    steps:
      - uses: actions/checkout@v4
      - uses: Simone/local-ci-cd-system/.gitea/actions/local-ci-build@main
        with:
          build-command: 'python build_plugin.py --final --dist-dir dist'
          artifact-source: 'dist'
          submodules: 'true'

6.3 [DEFERRED — home lab, bassissima priorità] 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.

Deferred: in un home lab single-host questa funzionalità non serve. Non pianificare.

6.4 [P3] [x] Build matrix nel workflow

File: gitea/workflows/build-ns7zip.yml.

Status: COMPLETATO 2026-05-11 — build-ns7zip.yml riscritto con matrix strategy.

Matrix target: [windows, linux], runs-on: ${{ matrix.target }}-build, fail-fast: false. Usa la composite action con job-id-suffix: ${{ matrix.target }} per artifact dir separate e repo-url: ssh://gitea-ci/Simone/nsis-plugin-ns7zip.git. Artifact separati: nsis-plugin-ns7zip-windows-<tag> e nsis-plugin-ns7zip-linux-<tag>.

6.5 [P3] [x] Secret injection workflow-level

Status: COMPLETATO 2026-05-11 — ExtraGuestEnv [hashtable] aggiunto a:

  • Invoke-CIJob.ps1 (param -ExtraGuestEnv, forwarded a Invoke-RemoteBuild)
  • Invoke-RemoteBuild.ps1 (param -ExtraGuestEnv, iniettato nei guest):
    • Windows: [System.Environment]::SetEnvironmentVariable nel session ScriptBlock prima del build command
    • Linux: export KEY='val'; prefisso prima della cd && buildcmd
  • action.yml: input extra-guest-env-json (JSON object), parsato via ConvertFrom-Json, mai loggato

Usage dal workflow:

- uses: Simone/local-ci-cd-system/.gitea/actions/local-ci-build@main
  with:
    build-command: 'python sign_and_build.py'
    extra-guest-env-json: '{"SIGN_PASS":"${{ secrets.SIGN_PASS }}","CERT_THUMBPRINT":"${{ secrets.CERT_THUMBPRINT }}"}'

6.6 [P2] [x] Toolchain Tier-1 + Tier-2 in Install-CIToolchain-WinBuild2025

File: template/Install-CIToolchain-WinBuild2025.ps1, template/Prepare-WinBuild2025.ps1.

Status: COMPLETATO 2026-05-11 — Step 11 (Tier-1: Git + 7-Zip) + Step 12 (Tier-2: 8 tools) implementati.

Motivazione: toolchain attuale (.NET SDK, Python, VS Build Tools) copre solo C#/Python/MSBuild. Aggiungere tools generici-CI riduce il bisogno di installazione ad-hoc nei workflow e abilita build più ampi senza toccare il template.

Tier-1 — Step 11 (implementato)

Tool Versione Razionale
Git for Windows 2.54.0.windows.1 Self-clone in VM, submodule fetch, fallback §3.2
7-Zip 26.01 Unpack/zip universale; usato da Step 12 stesso (vcpkg)
PowerShell 7.x 7.6.1 Parallel pipelines, operatori moderni, pwsh in CI
NSIS 3.12 Build installer Windows (es. nsis-plugin-ns7zip)
gh CLI 2.92.0 Upload artifact a release Gitea/GitHub, comment PR

Tier-2 — Step 12 (implementato)

Tool Versione Razionale
CMake 3.31.6 Build system C/C++ cross-platform
Node.js LTS 22.14.0 Frontend/Electron pipelines, npm toolchain
WiX Toolset 4.0.5 (dotnet tool) MSI building da .NET projects
Sysinternals latest (CDN Microsoft) Diagnostica process/handle quando build flaky
vcpkg HEAD (shallow clone) Package manager C++ per dipendenze native

Approccio:

  • Pinning hash SHA256 per ogni installer (vedi §1.3)
  • Convenzione path guest: tool in C:\BuildTools\<tool>\ (separato da C:\CI\ runtime — C:\CI\ resta per artefatti job e worker temp; C:\BuildTools\ per software statico). Documentare in docs/BEST-PRACTICES.md prima di implementare.
  • Aggiungere a PATH machine-wide
  • Defender già off → no scan overhead durante install
  • Step esegue in seriale dopo Toolchain cross-check esistente, prima di Cleanup
  • Final pre-snapshot gate: aggiungere check where.exe per ogni tool
  • Cross-link: Git for Windows e 7-Zip sono richiesti anche da §3.2 e dalla sezione "In-VM Git Clone" — implementare qui per evitare doppio lavoro

Validazione per-tool:

  • Eseguibile risolvibile via where.exe
  • Versione exact match al param -<Tool>Version
  • (per gh) gh --version returns 0
  • (per vcpkg) vcpkg.exe version

Param da aggiungere a Setup + Prepare:

  • -GitVersion, -7ZipVersion, -Pwsh7Version, -NSISVersion, -CMakeVersion, -NodeJSVersion, -WiXVersion, -GhCliVersion, -VcpkgRev (rev SHA del repo)

Tier-2 (opzionali, separati): Java JDK, Maven/Gradle, Rust, Go, LLVM, Docker, Azure/AWS CLI, WinDbg. Non includere in Setup base — workflow-level via choco install o download diretto.


7. Refactor confine Deploy ↔ Setup

Obiettivo: separazione netta delle responsabilità — Deploy produce template OS stand-alone, Setup fa build customization (user, dirs, toolchain). Eliminare drift e duplicazioni; ogni concern ha una sola sorgente di verità.

Stato attuale (duplicati): UAC, Explorer LaunchTo, Server Manager off, DisableCAD, OOBE telemetry, WU services disable — entrambi gli script li toccano.

7.1 [P1] [x] Spostare base OS hardening da Setup a Deploy

File: template/Deploy-WinBuild2025.ps1, template/Install-CIToolchain-WinBuild2025.ps1.

  • Aggiungere Set-NetFirewallProfile -Enabled False (tutti i profili) in Deploy post-install.ps1
  • Aggiungere MaxMemoryPerShellMB=2048, IdleTimeOut=7200000, MaxProcessesPerShell=25, StartupType=Automatic in Deploy dopo Enable-PSRemoting
  • Aggiungere in Deploy items mancanti rispetto a Setup 5c: lock screen (NoLockScreen), SM GPO policy key (DoNotOpenAtLogon), SM scheduled task disable, DisableCAD in Winlogon, OOBE non-policy key
  • Setup Step 1 (Firewall) → Assert-Step only
  • Setup Step 2 (Defender) → già validation-only (refactor 2026-05-09)
  • Setup Step 3 (WinRM tuning) → Assert-Step only (rimuovi Enable-PSRemoting, winrm set, Set-Item, Set-Service)
  • Setup Step 4b (UAC) → Assert-Step only
  • Setup Step 5b (Explorer LaunchTo) → Assert-Step only
  • Setup Step 5c (Server Manager / DisableCAD / OOBE) → Assert-Step only
  • E2e validation — completata §7.4 (2026-05-10)

7.2 [P1] [x] WU lifecycle — strategia B (Deploy: GPO + Manual; Setup: lifecycle)

File: template/Deploy-WinBuild2025.ps1, template/Install-CIToolchain-WinBuild2025.ps1.

Strategia B: Deploy lascia servizi WU start=demand (Manual, default Windows) e scrive solo GPO NoAutoUpdate=1 + DisableWindowsUpdateAccess=1. Setup Step 6 clears i GPO locks (Step A), avvia WU via SchTask SYSTEM, poi Step 6b disabilita servizi permanentemente post-update.

  • Deploy: rimuovere sc.exe config wuauserv start= disabled (e UsoSvc, WaaSMedicSvc)
  • Deploy: aggiungere GPO DisableWindowsUpdateAccess=1 (era mancante; NoAutoUpdate=1 già presente)
  • Setup Step 6 Step A: già rimuove DisableWindowsUpdateAccess + NoAutoUpdate prima del COM API — nessuna modifica necessaria
  • Setup Step 6 Step D: già fa Set-Service start=Manual + Start-Service — idempotente con servizi già Manual
  • Setup Step 6b: già disabilita wuauserv/UsoSvc + GPO keys — nessuna modifica necessaria
  • E2e validation — completata §7.4 (2026-05-10)

7.3 [P2] [x] Update header docs di entrambi gli script

7.4 [P2] [x] Test e2e refactor — COMPLETATO 2026-05-10

  • Deploy stand-alone su VM test → Get-NetFirewallProfile tutti Enabled=False, Get-Service wuauserv | Select StartTypeManual, NoAutoUpdate=1 GPO presente
  • Prepare dopo Deploy con -SkipWindowsUpdate → tutti Assert-Step passano [OK] senza eseguire Set (log mostra solo validation output)
  • Prepare senza -SkipWindowsUpdate → WU (0 update trovati, ResultCode=0), Step 6b disabilita wuauserv/UsoSvc (StartType=Disabled)
  • Final gate del guest passa su tutti e 7 i check; snapshot BaseClean preso

Fix emersi durante §7.4 (applicati):

  • Deploy: UsoSvc impostato a Manual esplicitamente (default Server 2025 = Automatic)
  • Setup cleanup: Set-Service -StartupType Disabled ri-applicato su wuauserv/UsoSvc dopo DISM StartComponentCleanup (DISM/WaaSMedicSvc può resettare StartType)
  • Deploy + Setup: autologin Administrator (AutoAdminLogon=1) aggiunto in post-install.ps1 e validato in Assert-Step 5c
  • Nuovi script: template/Validate-DeployState.ps1, template/Validate-SetupState.ps1

7.5 [P3] [x] Rinomina Setup-* → Install-CIToolchain-* (2026-05-11)

Rinominati i tre script guest-side:

  • template/Setup-WinBuild2025.ps1template/Install-CIToolchain-WinBuild2025.ps1
  • template/Setup-WinBuild2022.ps1template/Install-CIToolchain-WinBuild2022.ps1
  • template/Setup-LinuxBuild2404.shtemplate/Install-CIToolchain-Linux2404.sh

Tutti i riferimenti aggiornati in: Prepare-WinBuild2025/2022.ps1, Prepare-LinuxBuild2404.ps1, Deploy-WinBuild2025/2022.ps1, Deploy-LinuxBuild2404.ps1, README.md, TODO.md, docs/WINDOWS-TEMPLATE-SETUP.md, docs/LINUX-TEMPLATE-SETUP.md, docs/TEST-PLAN-v1.3-to-HEAD.md, gitea/actions/local-ci-build/action.yml.


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.

Strategia

Flusso attuale:

host: git clone  →  host: Compress-Archive  →  WinRM: copia zip  →  VM: Expand-Archive  →  VM: build

Flusso proposto:

VM avviata  →  WinRM: git clone --recurse-submodules https://<token>@gitea/...  →  VM: build

Punti chiave:

  • Il PAT non deve essere nello snapshot — viene iniettato a runtime come env var via WinRM (git clone https://Simone:<pat>@gitea.emulab.it/<repo>.git) e non viene mai persistito
  • Git deve essere installato nel template (Install-CIToolchain-WinBuild2025.ps1) — ora è assente per design
  • L'implementazione deve essere non-breaking: nuovo switch opt-in -UseGitClone in Invoke-CIJob.ps1
  • Si perde il parallelismo parziale (clone host avviene mentre VM boota), ma si elimina tutto l'overhead di zip/transfer (rilevante su repo grandi o con molti submoduli)
  • Submoduli funzionano nativamente con --recurse-submodules (nessun workaround)

Task

  • Tool prerequisiti nel template — implementati in §6.6 (Tier-1 Toolchain):

    • Git for Windows + 7-Zip + gh CLI installati con hash pinning e Assert-Step
    • Rimuovere il commento "Git is NOT installed" dal docblock di Install-CIToolchain-WinBuild2025.ps1 una volta applicato §6.6
    • curl.exe: già presente in Windows Server 2025 — verificare con where.exe curl
  • Invoke-CIJob.ps1 — aggiungere switch -UseGitClone

    • Quando -UseGitClone è attivo:
      • Saltare Phase 1 (host git clone) e la creazione del HostSourceDir temporaneo
      • Dopo Wait-VMReady, leggere PAT da Windows Credential Manager sull'host (es. target git:https://gitea.emulab.it/... o un target dedicato CI)
      • Passare PAT a Invoke-RemoteBuild.ps1 rispettando i vincoli sicurezza di §1.5
    • Comportamento default invariato (-UseGitClone = $false) — nessuna regressione
  • Invoke-RemoteBuild.ps1 — modalità in-VM clone

    • Aggiungere parametri: -CloneUrl, -CloneBranch, -CloneCommit, -GitPat (tutti opzionali, usati solo quando -UseGitClone è attivo)
    • Quando presenti: anziché copiare zip, eseguire nella VM: powershell git clone --recurse-submodules ` "https://Simone:$env:CI_GIT_PAT@gitea.emulab.it/Simone/<repo>.git" ` C:\CI\build git -C C:\CI\build checkout $CloneCommit # pin al commit esatto
    • Implementare iniezione/pulizia PAT secondo §1.5 (env var sessione, no argv, no log, cleanup [System.Environment]::SetEnvironmentVariable('CI_GIT_PAT', $null, 'Process'))
  • Test e2e con -UseGitClone — COMPLETATO 2026-05-10

    • Aggiornare snapshot BaseClean con Git installato
    • Eseguire e2e-010 con -UseGitClone su nsis-plugin-ns7zip (ha submoduli)
    • Confrontare tempo totale con e2e-009 (senza -UseGitClone) — 34s / 25.7% più veloce
    • Verificare che il PAT non appaia nei log di Invoke-CIJob.ps1

Linux Build VM — riferimento §6.1 [IMPLEMENTATO]

Supporto build su Linux aggiunto con le seguenti fasi completate:

  • Template VM Linux — script di provisioning per Ubuntu Server 24.04 LTS

    • template/Deploy-LinuxBuild2404.ps1 — crea VM da cloud VMDK, cloud-init, SSH wait
    • template/Install-CIToolchain-Linux2404.sh — installa toolchain CI (GCC, Clang, CMake, Python 3, git, 7z), hardening SSH, swap off, timer apt off
    • template/Prepare-LinuxBuild2404.ps1 — SCP script, esegue via SSH, valida, snapshot BaseClean-Linux
  • Invoke-CIJob.ps1 — branch Linux

    • Parametro -GuestOS (Windows/Linux/Auto) con auto-detect dal VMX guestOS field
    • Transport SSH via scripts/_Transport.psm1 (Invoke-SshCommand, Copy-SshItem, Test-SshReady)
    • Phase 4/5/6 branch su GuestOS: SSH per Linux, WinRM per Windows (nessuna regressione)
  • Workflow Gitea — build matrix

    • Label linux-build:host aggiunto a runner/config.yaml
    • GITEA_CI_LINUX_TEMPLATE_PATH e GITEA_CI_SSH_KEY_PATH aggiunti alle env vars del runner
    • Matrix strategy cross-platform (windows + linux) documentata in gitea/workflow-example.yml
  • Doc updates

    • docs/ARCHITECTURE.md — SSH transport, _Transport.psm1, Linux VM boxes, topology SSH :22
    • docs/CI-FLOW.md — Step 0: Linux template + SSH key; Step 6 SSH transport note; Steps 7-8 Linux branch
    • docs/HOST-SETUP.md — directory layout: keys\ + LinuxBuild2404; SSH key gen step; Reference Paths Linux
    • docs/LINUX-TEMPLATE-SETUP.md — Status: implementato; tutte le checkbox Fasi A-E marcate [x]
  • Test e2e Linux — COMPLETATO 2026-05-11 — Test-Ns7zipBuild-Linux.ps1 4× PASS

    • Confermare che la build di esempio funzioni su Linux — nsis7z.dll 2272 KB prodotto
    • Confrontare artifact Linux con quelli Windows — 2272 KB su entrambe le piattaforme

Deferred (Home Lab)

Nel contesto di un home lab isolato, i seguenti security task hanno costi eccessivi relativi ai benefici in questo ambiente. Rifiori se le condizioni cambiano (code non fidata, sharing host, esposizione di rete, etc.).

1.2 [P1] [ ] Audit TrustedHosts setting

File: docs/BEST-PRACTICES.md:§2.

Verificare che host Windows abbia WSMan:\localhost\Client\TrustedHosts configurato per 192.168.79.* instead of *. Attualmente impostato a * durante setup template.

Stato attuale: Accettabile per lab — WinRM è isolato su VMnet8 NAT. Rifiori se: Host esposto a LAN / internet.

1.3 [P0] [ ] Pinning hash SHA256 degli installer

File: template/Install-CIToolchain-WinBuild2025.ps1.

SHA256 hash per dotnet-install.ps1, Python installer, vs_buildtools.exe.

Stato attuale: Struttura aggiunta, valori placeholder — funziona con warning. Rifiori quando: Build di codice di terze parti non fidate che scaricano installer.

1.5 [P1] [ ] PAT mai persistito per -UseGitClone

File: sezione "In-VM Git Clone (Ottimizzazione)" in TODO.

Vincoli: PAT da Credential Manager subito prima sessione, non in argv/log, cancellato in finally, grep post-job se compare in transcript.

Stato attuale: Struttura documentata, non implementata. Rifiori quando: -UseGitClone implementato (§3.3).

1.7 [P2] [ ] Rotazione password guest VM

Aggiornare BuildVMGuest in Credential Manager + nel template ogni trimestre.

Stato attuale: Password manuale. Rifiori quando: Change management/compliance lo richiede.

1.8 [P2] [ ] Verifica Get-StoredCredential

Confermare che Get-StoredCredential (CredentialManager module) funzioni in tutti gli script che lo usano post-migrazione HTTPS.

Stato attuale: Usato in template ma non testato in unit test. Rifiori quando: Script fallisce su recovery da Credential Manager.

3.4 [P3] [ ] Pre-warm pool di cloni

File: F:\CI\WarmPool\ (hypothetical); scheduled task via scripts/Register-CIScheduledTasks.ps1.

Mantenere 2 cloni avviati in background, pronti per il binding a job. Salta la fase di New-BuildVM + Wait-VMReady (~30-60s) nel percorso critico. Richiede una VM "watcher" che monitora il pool e ricrea cloni dopo uso.

Stato attuale: Disegnato ma non implementato. Dipende da §2.1 (IP allocator). Rifiori quando: Profiling mostra che New-BuildVM+Wait-VMReady è bottleneck >30% nel tempo totale di job. Con build >2 minuti, overhead stimato ~40% (rilevante solo per 1-min builds).

3.5 [P2] [ ] vCPU/RAM tuning per workload

File: docs/OPTIMIZATION.md, VMX template config.

Esporre parametri -VMCpu / -VMMemory a Invoke-CIJob.ps1 per permettere override da workflow. Attualmente fisso a numvcpus=4, memsize=6144 — subottimo per build leggeri (waste) e pesanti (throttle).

Stato attuale: Progettato, non implementato. Template supporta la modifica. Rifiori quando: Performance profiling mostra contentione CPU/RAM è bottleneck per la workload target. Per home lab, 4 vCPU/6 GB è ragionevole compromesso.

8.1 [P3] [ ] Mirror GitHub Actions su Gitea locale (rimuovi dipendenza github.com)

File: .gitea/workflows/lint.yml, Gitea (org actions).

Dipendenza residua da github.com: actions/checkout@v4 in lint.yml (2×) — il codice dell'action è scaricato da github.com a runtime (con [actions] DEFAULT_ACTIONS_URL = github). La dipendenza per gli artifact è già stata eliminata (upload/download-artifact rimossi; handoff via filesystem host — vedi commit refactor(ci): drop upload/download-artifact). Questo task è l'alternativa "fix 1" non scelta: mirrorare le action GitHub usate (checkout) in una org actions sull'istanza Gitea e referenziarle via URL Gitea completo, eliminando del tutto github.com.

Stato attuale: Deferred. Artifact già github-free (scelta "fix 2" applicata). Resta solo actions/checkout@v4 in lint; act_runner la cacha dopo il primo fetch, quindi outage GitHub impatta solo cold cache. Rifiori quando: Host air-gapped, GitHub non raggiungibile dall'host CI, o si vuole indipendenza totale da github.com (anche per checkout).

8.2 [P3] [ ] Streaming live output build su Windows (WinRM)

File: src/ci_orchestrator/transport/winrm.py, src/ci_orchestrator/commands/build.py.

Linux/SSH ora streamma l'output del build in tempo reale (SshTransport.run_streaming — recv incrementale + PYTHONUNBUFFERED). Windows resta log-a-fine-job: pypsrp.Client.execute_ps ritorna solo a comando concluso; _windows_build usa _report_build_output (blocco unico) + coda nel messaggio d'errore.

Stato attuale: Deferred. Streaming WinRM richiede API basso livello RunspacePool/PowerShell con poll di ps.output/stream invece di execute_ps, semantica PSRP più complessa; output unbuffered dei tool nativi (MSBuild) scomodo. Diagnostica già adeguata (output completo a fine job + ultime righe nell'errore). Rifiori quando: Build Windows lunghi rendono l'assenza di progress live un problema operativo reale, o si standardizza lo streaming cross-OS.


Suggerimento di sequencing

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.


Reference Paths

Item Path / Value
vmrun.exe C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe
act_runner F:\CI\act_runner\act_runner.exe (servizio: act_runner)
act_runner config F:\CI\act_runner\config.yaml
act_runner logs F:\CI\act_runner\logs\
Template VMX F:\CI\Templates\WinBuild2025\WinBuild2025.vmx
Snapshot name BaseClean
Clone base dir F:\CI\BuildVMs\
Artifact dir F:\CI\Artifacts\
Log dir F:\CI\Logs\ (retention: 30 giorni)
Gitea URL (LAN) http://10.10.20.11:3100
Gitea URL (ext) https://gitea.emulab.it
Runner name local-windows-runner (ID: 1)
Build VM subnet 192.168.79.0/24 (VMnet8 — NAT, internet access per build)
Credential Manager target BuildVMGuest
Guest username ci_build — configurato e verificato