- git mv Setup-TemplateVM.ps1 Setup-WinBuild2025.ps1
- git mv Prepare-TemplateSetup.ps1 -> Prepare-WinBuild2025.ps1 (name already in place)
- Updated all references across the workspace:
template/Prepare-WinBuild2025.ps1 (script copy, assertions, comments)
template/Setup-WinBuild2025.ps1 (self-references in docblock and final message)
README.md (directory tree)
TODO.md (all inline links and task descriptions)
docs/WINDOWS-TEMPLATE-SETUP.md (table, step descriptions, phase header, troubleshooting)
docs/LINUX-TEMPLATE-SETUP.md (Windows equivalent reference)
34 KiB
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 — bootstrap macchina host (Setup-Host.ps1)
docs/WINDOWS-TEMPLATE-SETUP.md — provisioning template Windows (Prepare + Setup-WinBuild2025)
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
-
Gitea Server — già in esecuzione su
http://10.10.20.11:3100(ehttps://gitea.emulab.it)- Runner registration token ottenuto e usato
- Create at least one test repository with
.gitea/workflows/build.yml(Simone/nsis-plugin-nsinnounp— testato e2e, workflow ingitea/workflows/build-nsis.yml) - Gitea Actions abilitato (runner registrato con successo)
-
act_runner — installato e registrato sull'host Windows
- Binario
gitea-runner v1.0.2scaricato inF:\CI\act_runner\act_runner.exe - Registrato con Gitea (
http://10.10.20.11:3100) — runner ID 1, nomelocal-windows-runner config.yamlcopiato inF:\CI\act_runner\config.yamlcon labelwindows-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
- Binario
-
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\WinBuild\F:\CI\Logs\— log per job (retention: 30 giorni)F:\CI\ISO\— contiene26100.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\WinBuild\WinBuild.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 -qpowershell Enable-PSRemoting -Force -SkipNetworkProfileCheck Set-Item WSMan:\localhost\Service\Auth\Basic $true -Force Set-Item WSMan:\localhost\Service\AllowUnencrypted $true -Force Set-Item WSMan:\localhost\Client\TrustedHosts -Value '*' -Force - Attiva Windows Server 2025 (prima dello snapshot — i linked clone ereditano l'attivazione):
cmd slmgr /dliSe non attivato, scegli il metodo appropriato: - KMS (server KMS in rete):slmgr /skms <IP_KMS>poislmgr /ato- MAK/Retail key:slmgr /ipk XXXXX-XXXXX-XXXXX-XXXXX-XXXXXpoislmgr /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) —ipconfignella 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 -SkipWindowsUpdateInstalla: WinRM config, utenteci_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-WinBuild2025.ps1 presente - Host WinRM: AllowUnencrypted, TrustedHosts - Guest prep:C:\CIesiste, 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).
Setup-WinBuild2025.ps1ora esegue validazioneAssert-Stepdopo 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:
BaseCleanPrerequisito:Prepare-WinBuild2025.ps1deve essere uscito con exit 0 — tutti gliAssert-Steppassati, 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_PATHinF:\CI\act_runner\config.yaml— aggiornato aCI-WinBuild.vmx(2026-05-08)
- Crea nuova VM in VMware Workstation con queste impostazioni:
- 4 vCPU, 6144 MB RAM, disco 80 GB thin
- VMX path:
Scripts Verification
- Test
New-BuildVM.ps1standalone — cloneClone_test-002creato correttamente (2026-05-08) - Test
Wait-VMReady.ps1standalone — 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.ps1end-to-end su una soluzione reale (nsis-plugin-nsinnounp)- e2e-008: SUCCESS — build OK + artifact raccolto (1632 KB)
- e2e-009: SUCCESS — cleanup automatico VM + clone confermato (finally block)
scripts/Cleanup-OrphanedBuildVMs.ps1creato e verificato —-WhatIf, soglia-MaxAgeHours, hard stop + deleteVM + rimozione dir (2026-05-09)scripts/Remove-BuildVM.ps1fixvmrun deleteVMexit -1 — pollvmrun list+ retry 3× backoff 0/3/6s (2026-05-09)
Runner Configuration
runner/config.yamlaggiornato con percorsiF:\CI\, rete VMnet8 (NAT), label corretticapacity: 4configurato (64 GB RAM / ~8 GB per VM)- Aggiornare
GITEA_CI_TEMPLATE_PATHinconfig.yamldopo creazione template VM - Archiviare credenziali guest in Windows Credential Manager (target:
BuildVMGuest)
Gitea Workflow Integration
- Copiare
gitea/workflow-example.ymlin.gitea/workflows/build.ymlnel repo di test (workflowbuild-nsis.ymlgià presente e funzionante pernsis-plugin-nsinnounp) - Push commit e verificare job in Gitea Actions UI
- Verificare artifact scaricabile da Gitea dopo build riuscita
gitea/workflows/lint.ymlcreato — PSScriptAnalyzer su push/PR che toccano.ps1(2026-05-09)- [P3] Adattare workflow per altri repository — generalizzare
BUILD_COMMANDeARTIFACT_SOURCE. Vedi anche §6.2 (composite action riutilizzabile).
1. Sicurezza & hardening
1.1 [P0] Migrare WinRM da HTTP/Basic a HTTPS/5986
File: template/Setup-WinBuild2025.ps1:179-198, scripts/Invoke-RemoteBuild.ps1:82-91.
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.
Azioni:
- Generare cert self-signed nel template prima dello snapshot.
- Sostituire
New-PSSession -ComputerName $ipcon-UseSSL -Port 5986inInvoke-RemoteBuild.ps1eGet-BuildArtifacts.ps1. - Rimuovere
AllowUnencrypted=truedalSetup-WinBuild2025.ps1. - Tenere
-SkipCAChecklato 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).
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:
Set-Item WSMan:\localhost\Client\TrustedHosts -Value '192.168.79.*' -Force -Concatenate
1.3 [P0] Pinning hash SHA256 degli installer
File: template/Setup-WinBuild2025.ps1:332-399, template/Setup-WinBuild2025.ps1:401-502.
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:
$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-RemoteBuild.ps1:52, scripts/Get-BuildArtifacts.ps1:42, scripts/Wait-VMReady.ps1:43.
Motivazione: '^(\d{1,3}\.){3}\d{1,3}$' accetta 999.999.999.999. Sostituire con regex
per-ottetto:
$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:credinInvoke-Commande cancellare la variabile in unfinallyinterno 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-WinBuild2025.ps1:200-329.
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 conLocalAccountTokenFilterPolicy=1).
Senza questa nota, future modifiche possono accumulare ulteriori riduzioni di sicurezza senza tracciamento.
1.7 [P2] Rotazione password guest VM
- Trimestrale. Aggiornare credenziale
BuildVMGuestin Credential Manager + password effettiva nel template (richiede refresh snapshot — coordinare con §2.5).
1.8 [P2] Verifica Get-StoredCredential
- Confermare che
Get-StoredCredentialfunzioni 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, scripts/Invoke-CIJob.ps1:244-253.
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 inF:\CI\State\ip-leases\<jobid>e iniettarlo comebootArgso viavmrun writeVariableprima di start. Rilascio nelfinally. - 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: 1finché 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 — script pronto, manca lo scheduling.
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] Retention artifact + log automatica
File: docs/OPTIMIZATION.md:160-181 — 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.
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_<yyyyMMdd>
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.yamlaggiungeGITEA_CI_SNAPSHOT_NAMEcome env var.Invoke-CIJob.ps1legge 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 — solo come snippet manuale.
Pre-snapshot: copia atomica del parent VMDK in F:\CI\Backups\Template_<date>\. 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 — 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, scripts/Invoke-RemoteBuild.ps1:158-194.
Motivazione: F:\CI\Cache\NuGet esiste come dir, non viene mai usata.
Aggiungere a CI-WinBuild.vmx:
sharedFolder0.present = "TRUE"
sharedFolder0.hostPath = "F:\\CI\\Cache\\NuGet"
sharedFolder0.guestName = "nuget-cache"
Poi nello scriptblock di build:
$env:NUGET_PACKAGES = '\\vmware-host\Shared Folders\nuget-cache'
Equivalente per pip:
$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.
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):
Vantaggio: multi-thread, ratio simile con
& 'C:\Program Files\7-Zip\7z.exe' a -mmt=on -mx1 $hostZip "$HostSourceDir\*"-mx1. - robocopy via admin share UNC (
\\<vmIP>\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.
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, 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/-VMMemoryaInvoke-CIJob.ps1con 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.
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.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_<latest>.
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-BuildVMcon vmrun mockato — verifica che il VMX path costruito sia ben formato per JobId con caratteri speciali.Wait-VMReadyconTest-WSManmockato — verifica timeout, fasi, ritorni.Remove-BuildVMconvmrun listmockato — 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).ValidatePatternIP (4 file — vedi §1.4).- Risoluzione
vmrun.exe(3 file). Test-Path+New-Itemper dir lazy creation.- Function
Invoke-VmrunCommandcon 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:
$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 (già esiste).
Aggiungere regole specifiche progetto (PSScriptAnalyzerSettings.psd1 in root):
PSAvoidUsingPlainTextForPassword— rilevante perSetup-WinBuild2025.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 — 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.
Trasformare in composite action Gitea (.gitea/actions/local-ci-build/action.yml)
richiamabile da qualsiasi repo:
- 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.
Attualmente single job. Quando arriverà la VM Linux:
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.
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 (
Setup-WinBuild2025.ps1) — ora è assente per design - L'implementazione deve essere non-breaking: nuovo switch opt-in
-UseGitCloneinInvoke-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
-
Setup-WinBuild2025.ps1 — installare Git for Windows
- Scaricare e installare Git for Windows (installer silenzioso da git-scm.com)
powershell $gitUrl = 'https://github.com/git-for-windows/git/releases/download/v2.47.1.windows.1/Git-2.47.1-64-bit.exe' Start-Process $gitUrl '/VERYSILENT /NORESTART /COMPONENTS=gitlfs' -Wait - Aggiungere
C:\Program Files\Git\cmdal PATH di sistema nella VM - Verificare:
git --versionritorna exit 0 nella VM - Rimuovere il commento "Git is NOT installed" dal docblock di Setup-WinBuild2025.ps1
- Scaricare e installare Git for Windows (installer silenzioso da git-scm.com)
-
Setup-WinBuild2025.ps1 — altri tool utili
- 7-Zip: installer silenzioso — molto più veloce di
Compress-Archive/Expand-Archiveper 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
- 7-Zip: installer silenzioso — molto più veloce di
-
Invoke-CIJob.ps1 — aggiungere switch
-UseGitClone- Quando
-UseGitCloneè attivo:- Saltare Phase 1 (host git clone) e la creazione del
HostSourceDirtemporaneo - 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 come parametro a
Invoke-RemoteBuild.ps1(mai loggato/stampato)
- Saltare Phase 1 (host git clone) e la creazione del
- Comportamento default invariato (
-UseGitClone=$false) — nessuna regressione
- Quando
-
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 - Iniettare PAT come variabile d'ambiente della sessione WinRM (non argv, non log)
- Pulire la variabile d'ambiente dopo il clone:
[System.Environment]::SetEnvironmentVariable('CI_GIT_PAT', $null, 'Process')
- Aggiungere parametri:
-
Test e2e con
-UseGitClone- Aggiornare snapshot
BaseCleancon Git installato - Eseguire
e2e-010con-UseGitClonesunsis-plugin-nsinnounp(ha submoduli) - Confrontare tempo totale con e2e-009 (senza
-UseGitClone) - Verificare che il PAT non appaia nei log di
Invoke-CIJob.ps1
- Aggiornare snapshot
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).
-
Template VM Linux — Provisionare template VM con Ubuntu Server 24.04 LTS
- Scegliere distro: Ubuntu 24.04 LTS (raccomandato) o Debian 12
- Installare toolchain: GCC, Clang, CMake, Python 3.x, build-essential
- Configurare accesso SSH (chiave pubblica da host) in alternativa/integrazione a WinRM
- Prendere snapshot
BaseClean-Linux - Archiviare credenziali SSH in Credential Manager (o key file su host)
-
Invoke-CIJob.ps1 — branch Linux
- 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)
- Aggiungere parametro
-
Workflow Gitea — build matrix
- Definire matrix strategy
[windows-build, linux-build]nel workflow (vedi §6.4) - Aggiungere label
linux-buildal runner (o registrare runner separato se necessario) - Verificare che artifacts da entrambe le piattaforme vengano raccolti correttamente
- Definire matrix strategy
-
Test e2e Linux — eseguire almeno un build end-to-end su VM Linux
- Confermare che
build_plugin.py(o analogo script) funzioni su Linux - Confrontare artifact Linux con quelli Windows
- Confermare che
Suggerimento di sequencing
Sprint progressivi per ridurre rischio / ottenere valore prima:
- Sprint 1 (sicurezza) — §1.1, §1.2, §1.3, §1.4 — superficie di attacco e bug noti.
- Sprint 2 (operatività) — §2.1, §2.2, §2.3, §2.5 — rendere il sistema "fire and forget".
- Sprint 3 (osservabilità) — §4.1, §4.3, §4.4 — visibilità prima di estendere.
- Sprint 4 (perf) — §3.1, §3.2 misurati su un repo reale (baseline §3.6).
- Sprint 5 (qualità) — §5.1, §5.2 — rifattorizzazione con safety net di test.
- 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\WinBuild\CI-WinBuild.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 |