feat(sprint4-6): quality, reliability, perf baseline

Sprint 4 — qualità codice:
- scripts/_Common.psm1: New-CISessionOption, Resolve-VmrunPath, Invoke-Vmrun
- PSScriptAnalyzerSettings.psd1: project-wide PSSA rules (security + formatting)
- Remove-BuildVM.ps1: SupportsShouldProcess (-WhatIf support)
- Invoke-RemoteBuild.ps1, Get-BuildArtifacts.ps1: use New-CISessionOption from module
- New-BuildVM.ps1: use Resolve-VmrunPath + Invoke-Vmrun from module

Sprint 5 — affidabilità:
- Backup-CITemplate.ps1: stop runner, timestamped VMDK backup, prune old, restart
- Watch-RunnerHealth.ps1: auto-restart act_runner, cooldown 3/h, EventLog + webhook
- Register-CIScheduledTasks.ps1: add CI-RunnerHealth task (every 15 min)

Sprint 6 — perf baseline:
- Set-TemplateSharedFolders.ps1: idempotent VMX editor for NuGet/pip shared folders
- Invoke-RemoteBuild.ps1: -UseSharedCache injects NUGET_PACKAGES + PIP_CACHE_DIR in guest
- Measure-CIBenchmark.ps1: times clone/start/IP/WinRM/destroy, appends to benchmark.jsonl

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Simone
2026-05-10 20:08:19 +02:00
parent 1962c977ba
commit 552eb628b7
12 changed files with 966 additions and 98 deletions
+62 -66
View File
@@ -1,6 +1,6 @@
# TODO — Local CI/CD System
<!-- Last updated: 2026-05-10 — line refs e wording allineati al refactor 2026-05-09 -->
<!-- Last updated: 2026-05-10 — Sprint 6 (perf): §3.1, §3.6 completati -->
> 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**:
@@ -18,9 +18,9 @@
---
## Summary
_Last updated: 2026-05-10 (post Sprint 3 osservabilità)_
_Last updated: 2026-05-10 (post Sprint 6 perf: §3.1/§3.6 done)_
**Stato generale**: infrastruttura base e refactor Deploy↔Setup (§7) completi. Sicurezza sprint 1 in corso (HTTPS/5986 done, IP regex done, hash pinning struttura done — valori da riempire). Backlog operatività/perf/qualità intatto.
**Stato generale**: §2 affidabilità interamente chiuso. §3.1 cache e §3.6 benchmark done. §3.2 (7-Zip) dipende da §6.6. Sicurezza P1/P2 e Pester rimangono backlog principale.
| Area | Done | Open | Note |
| ------------------------------- | ---: | ---: | ----------------------------------------------------------------- |
@@ -30,19 +30,20 @@ _Last updated: 2026-05-10 (post Sprint 3 osservabilità)_
| Runner Configuration | all | 0 | `config.yaml`, capacity 4, `BuildVMGuest` |
| Gitea Workflow Integration | 4 | 1 | manca solo §P3 generalizzazione workflow |
| §1 Sicurezza & hardening | 2 | 6 | 1.1, 1.4 done; 1.2/1.3 parzialmente; 1.5/1.6/1.7/1.8 da fare |
| §2 Affidabilità & resilienza | 4 | 3 | 2.1/2.2/2.3/2.5 done; 2.4/2.6/2.7 backlog |
| §3 Performance & throughput | 0 | 6 | nessuna ottimizzazione applicata; baseline §3.6 prerequisito |
| §2 Affidabilità & resilienza | 7 | 0 | tutto done |
| §3 Performance & throughput | 2 | 4 | 3.1/3.6 done; 3.2 (7-Zip, dipende §6.6), 3.3/3.4/3.5 backlog |
| §4 Osservabilità & manutenzione | 3 | 2 | 4.1/4.3/4.4 done; 4.2/4.5 backlog |
| §5 Qualità codice & test | 0 | 5 | Pester, modulo `_Common.psm1`, regole PSScriptAnalyzer custom |
| §5 Qualità codice & test | 3 | 2 | 5.2/5.3/5.4 done; 5.1 (Pester) e 5.5 (type hints) backlog |
| §6 Scalabilità & estensioni | 0 | 6 | Linux VM, composite action, toolchain Tier-1 |
| §7 Refactor Deploy ↔ Setup | 4 | 1 | 7.1/7.2/7.3/7.4 done; 7.5 (rinomina) opzionale |
| In-VM Git Clone (§3.3) | 0 | 4 | dipende da §6.6 (Git+7-Zip nel template) |
| Linux Build VM (§6.1) | 0 | 4 | bozza in `docs/LINUX-TEMPLATE-SETUP.md` |
**Prossimi passi consigliati** (vedi anche "Suggerimento di sequencing" in fondo):
1. Chiudere §1.3 — riempire hash SHA256 in `Setup-WinBuild2025.ps1` prima del prossimo refresh snapshot.
2. Audit §1.2 (TrustedHosts `*` su host), poi §1.7 (rotazione password guest).
3. Sprint 2 operatività — §2.2 (cleanup schedulato), §2.3 (retention), §2.5 (snapshot versionato).
1. §5.1 — Pester smoke tests (safety net prima di refactor più profondi).
2. §1.2 — Audit TrustedHosts (1 comando, manuale).
3. §1.6 — Threat model doc in BEST-PRACTICES.md.
4. §1.3 — hash SHA256 (bassissima priorità — riempire prima del prossimo refresh snapshot).
---
## Setup & Infrastructure
@@ -309,11 +310,10 @@ 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`
### 2.4 [P1] [x] `Remove-BuildVM.ps1` — supportare `-WhatIf` — COMPLETATO 2026-05-10
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.
`[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](docs/BEST-PRACTICES.md), [scripts/Invoke-CIJob.ps1:100](scripts/Invoke-CIJob.ps1).
@@ -331,45 +331,42 @@ e non c'è rollback.
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.
### 2.6 [P2] [x] Backup automatico VMDK template — COMPLETATO 2026-05-10
File: [scripts/Backup-CITemplate.ps1](scripts/Backup-CITemplate.ps1).
Pre-snapshot: copia atomica del `parent` VMDK in `F:\CI\Backups\Template_<date>\`. Su errore
di refresh (es. installer rotto), rollback in 1 minuto.
Copia atomica `F:\CI\Templates\WinBuild` → `F:\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] [ ] Health check del runner + monitoraggio Event Log
File: [docs/BEST-PRACTICES.md:101-115](docs/BEST-PRACTICES.md) — script presente in doc, non operativo.
### 2.7 [P2] [x] Health check del runner + monitoraggio Event Log — COMPLETATO 2026-05-10
File: [scripts/Watch-RunnerHealth.ps1](scripts/Watch-RunnerHealth.ps1); task registrato da [scripts/Register-CIScheduledTasks.ps1](scripts/Register-CIScheduledTasks.ps1) come `CI-RunnerHealth` (ogni 15 min).
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).
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] [ ] 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).
### 3.1 [P1] [x] NuGet/pip cache su shared folder — COMPLETATO 2026-05-10
File: [scripts/Set-TemplateSharedFolders.ps1](scripts/Set-TemplateSharedFolders.ps1), [scripts/Invoke-RemoteBuild.ps1](scripts/Invoke-RemoteBuild.ps1).
**Motivazione**: `F:\CI\Cache\NuGet` esiste come dir, non viene mai usata.
`Set-TemplateSharedFolders.ps1`: edita il VMX template aggiungendo due shared folder
(`nuget-cache` → `F:\CI\Cache\NuGet`, `pip-cache` → `F:\CI\Cache\pip`), idempotente,
`.bak` del VMX originale mantenuto, `SupportsShouldProcess`.
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.
`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] [ ] Sostituire `Compress-Archive` con 7-Zip o robocopy
File: [scripts/Invoke-RemoteBuild.ps1:112,148,185](scripts/Invoke-RemoteBuild.ps1) (3 chiamate `Compress-Archive`).
@@ -414,8 +411,14 @@ 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).
### 3.6 [P2] [x] Benchmark baseline — COMPLETATO 2026-05-10
File: [scripts/Measure-CIBenchmark.ps1](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.
---
@@ -495,33 +498,26 @@ Pester può coprire:
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`.
### 5.2 [P2] [x] Modulo PowerShell condiviso `scripts/_Common.psm1` — COMPLETATO 2026-05-10
File: [scripts/_Common.psm1](scripts/_Common.psm1).
Risultato: meno LoC, fix in un punto solo, più facile da testare.
Esporta: `New-CISessionOption` (WinRM self-signed TLS), `Resolve-VmrunPath` (valida vmrun.exe),
`Invoke-Vmrun` (wrapper uniforme `-T ws`, ritorna `{ExitCode, Output}`, supporta `-ThrowOnError`).
### 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.
Importato da: `Invoke-RemoteBuild.ps1`, `Get-BuildArtifacts.ps1`, `New-BuildVM.ps1`.
### 5.4 [P2] [ ] PSScriptAnalyzer rules custom
File: [gitea/workflows/lint.yml](gitea/workflows/lint.yml) (già esiste).
### 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`.
Aggiungere regole specifiche progetto (`PSScriptAnalyzerSettings.psd1` in root):
- `PSAvoidUsingPlainTextForPassword` — rilevante per [Setup-WinBuild2025.ps1:123](template/Setup-WinBuild2025.ps1:123) (`[string] $BuildPassword``ConvertTo-SecureString -AsPlainText` riga 253).
- `PSAvoidUsingInvokeExpression`.
- `PSUseShouldProcessForStateChangingFunctions`.
- Regole custom: vietare hardcoded `F:\CI\` fuori da config (forzare param/env).
### 5.4 [P2] [x] PSScriptAnalyzer rules custom — COMPLETATO 2026-05-10
File: [PSScriptAnalyzerSettings.psd1](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] [ ] Type hints nei param block
Già parzialmente fatto. Estendere a tutti gli script per migliorare IntelliSense e