a5719f2ac6
Move pre-warm pool (maintaining 2 avviati clones) from main §3 backlog to Deferred section. Rationale: optimization only valuable if profiling shows New-BuildVM+Wait-VMReady is bottleneck; with 2-min builds ~40% overhead, but ~0% for 10+ min builds. Update summary table: §3 now shows 3 done, 2 open, 1 deferred (instead of 3 open). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
794 lines
44 KiB
Markdown
794 lines
44 KiB
Markdown
# TODO — Local CI/CD System
|
||
|
||
<!-- Last updated: 2026-05-10 — Post Sprint 7: §1.6 threat model + §3.2 7-Zip + test plan 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**:
|
||
>
|
||
> **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 (Deploy + Prepare + Setup-WinBuild2025)
|
||
> - [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
|
||
|
||
---
|
||
## Summary
|
||
|
||
_Last updated: 2026-05-10 (post Sprint 7: §1.6/§3.2 done, test plan created)_
|
||
|
||
**Stato generale**: §1, §2, §4, §5 chiusi (4 sezioni). §3 perf: 3/6 done. Threat model, 7-Zip, test plan, type hints, JSONL logs, disk alert, runbook completati. Security deferred. Prossimi: test plan exec, §6.6 (toolchain), §3.3/3.4.
|
||
|
||
| 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` |
|
||
| [ ] | Gitea Workflow Integration | 4 | 1 | manca solo §P3 generalizzazione workflow |
|
||
| [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) |
|
||
| [ ] | §3 Performance & throughput | 3 | 2 | 3.1/3.2/3.6 done; 3.3/3.5 backlog; 3.4 deferred |
|
||
| [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 |
|
||
| [ ] | §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. **Test Plan** — eseguire `docs/TEST-PLAN-v1.3-to-HEAD.md` (25+ Pester tests, e2e validation)
|
||
2. **§6.6** — Toolchain Tier-1 in template (Git, 7-Zip, PowerShell 7, NSIS, CMake, Node.js, etc.)
|
||
3. **§3.3** — In-VM Git clone (`-UseGitClone` flag, dipende §6.6)
|
||
4. **§3.4** — Pre-warm pool di cloni (P3, solo se profilo dimostra bottleneck)
|
||
5. **Security** — Rifiori se condizioni cambiano; vedi sezione "Deferred (Home Lab)"
|
||
|
||
---
|
||
## Setup & Infrastructure
|
||
|
||
- [x] **Gitea Server** — già in esecuzione su `http://10.10.20.11:3100` (e `https://gitea.emulab.it`)
|
||
- [x] Runner registration token ottenuto e usato
|
||
- [x] Create at least one test repository with `.gitea/workflows/build.yml`
|
||
(`Simone/nsis-plugin-nsinnounp` — testato e2e, workflow in `gitea/workflows/build-nsis.yml`)
|
||
- [x] Gitea Actions abilitato (runner registrato con successo)
|
||
|
||
- [x] **act_runner** — installato e registrato sull'host Windows
|
||
- [x] Binario `gitea-runner v1.0.2` scaricato in `F:\CI\act_runner\act_runner.exe`
|
||
- [x] Registrato con Gitea (`http://10.10.20.11:3100`) — runner ID 1, nome `local-windows-runner`
|
||
- [x] `config.yaml` copiato in `F:\CI\act_runner\config.yaml` con label `windows-build:host`
|
||
- [x] Installato come servizio Windows via NSSM — stato: **Running**, StartType: Automatic
|
||
- [x] Verificare che il runner appaia "Online" nell'UI Gitea Admin → Actions → Runners
|
||
- [x] Confermare riavvio automatico dopo reboot host
|
||
|
||
- [x] **Directory CI** create su `F:\CI\`
|
||
- [x] `F:\CI\BuildVMs\`
|
||
- [x] `F:\CI\Artifacts\`
|
||
- [x] `F:\CI\act_runner\`
|
||
- [x] `F:\CI\Cache\NuGet\`
|
||
- [x] `F:\CI\RunnerWork\`
|
||
- [x] `F:\CI\Templates\WinBuild\`
|
||
- [x] `F:\CI\Logs\` — log per job (retention: 30 giorni)
|
||
- [x] `F:\CI\ISO\` — contiene `26100.1742.240906-0331.ge_release_svc_refresh_SERVER_VOL_x64FRE_en-us.iso` (Windows Server 2025)
|
||
|
||
- [x] **CredentialManager** PowerShell module v2.0 installato (Scope: CurrentUser)
|
||
|
||
- [x] **Rete VM**: VMnet8 (NAT) — internet access per pip/nuget/npm durante i build
|
||
|
||
## Template VM
|
||
|
||
- [x] **Provision template VM** in VMware Workstation — segui questi passi nell'ordine esatto:
|
||
|
||
### Fase A — Crea e installa la VM (NIC: NAT per internet)
|
||
- [x] Crea nuova VM in VMware Workstation con queste impostazioni:
|
||
- 4 vCPU, 6144 MB RAM, disco 80 GB thin
|
||
- VMX path: `F:\CI\Templates\WinBuild\CI-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`
|
||
- [x] Installa Windows Server 2025 dall'ISO
|
||
- [x] 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
|
||
```
|
||
- [x] **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
|
||
- [x] Nota l'IP assegnato dal DHCP di VMnet8 (es. `192.168.79.x`) — `ipconfig` nella VM
|
||
|
||
### Fase B — Provisioning automatico dall'host
|
||
- [x] 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, Setup-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**.
|
||
- [x] Setup completato con successo (VS Build Tools 2026 exit code 0).
|
||
- [x] `Setup-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
|
||
- [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-WinBuild2025.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
|
||
- [x] Archivia credenziali guest sull'host (PowerShell elevato con CredentialManager):
|
||
```powershell
|
||
New-StoredCredential -Target "BuildVMGuest" -UserName "ci_build" `
|
||
-Password "<your-build-password>" -Persist LocalMachine
|
||
```
|
||
- [x] Verifica `GITEA_CI_TEMPLATE_PATH` in `F:\CI\act_runner\config.yaml` — aggiornato a `CI-WinBuild.vmx` (2026-05-08)
|
||
|
||
## Scripts Verification
|
||
|
||
- [x] Test `New-BuildVM.ps1` standalone — clone `Clone_test-002` creato correttamente (2026-05-08)
|
||
- [x] Test `Wait-VMReady.ps1` standalone — exit 0 in ~5s, VM pronta (2026-05-08)
|
||
- [x] Test `Invoke-RemoteBuild.ps1` — dotnet restore + build OK, artifacts.zip creato in VM (2026-05-08)
|
||
- [x] Test `Get-BuildArtifacts.ps1` — artifacts.zip (78 KB) copiato in F:\CI\Artifacts\test-003\ (2026-05-08)
|
||
- [x] Test `Remove-BuildVM.ps1` — VM spenta + directory rimossa correttamente (2026-05-08)
|
||
- [x] Test `Invoke-CIJob.ps1` end-to-end su una soluzione reale (nsis-plugin-nsinnounp)
|
||
- [x] e2e-008: SUCCESS — build OK + artifact raccolto (1632 KB)
|
||
- [x] e2e-009: SUCCESS — cleanup automatico VM + clone confermato (finally block)
|
||
- [x] `scripts/Cleanup-OrphanedBuildVMs.ps1` creato e verificato — `-WhatIf`, soglia `-MaxAgeHours`, hard stop + deleteVM + rimozione dir (2026-05-09)
|
||
- [x] `scripts/Remove-BuildVM.ps1` fix `vmrun deleteVM` exit -1 — poll `vmrun list` + retry 3× backoff 0/3/6s (2026-05-09)
|
||
|
||
## Runner Configuration
|
||
|
||
- [x] `runner/config.yaml` aggiornato con percorsi `F:\CI\`, rete VMnet8 (NAT), label corretti
|
||
- [x] `capacity: 4` configurato (64 GB RAM / ~8 GB per VM)
|
||
- [x] Aggiornare `GITEA_CI_TEMPLATE_PATH` in `config.yaml` dopo creazione template VM
|
||
- [x] Archiviare credenziali guest in Windows Credential Manager (target: `BuildVMGuest`)
|
||
|
||
## Gitea Workflow Integration
|
||
|
||
- [x] Copiare `gitea/workflow-example.yml` in `.gitea/workflows/build.yml` nel repo di test
|
||
(workflow `build-nsis.yml` già presente e funzionante per `nsis-plugin-nsinnounp`)
|
||
- [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)
|
||
- [ ] **[P3] Adattare workflow per altri repository** — generalizzare `BUILD_COMMAND` e `ARTIFACT_SOURCE`.
|
||
Vedi anche §6.2 (composite action riutilizzabile).
|
||
|
||
---
|
||
|
||
## 1. Sicurezza & hardening
|
||
|
||
### 1.1 [P0] [x] Migrare WinRM da HTTP/Basic a HTTPS/5986 — COMPLETATO 2026-05-10
|
||
|
||
**Azioni**:
|
||
- [x] Generare cert self-signed nel template *prima* dello snapshot (già in Deploy post-install.ps1).
|
||
- [x] Sostituire `New-PSSession -ComputerName $ip` con `-UseSSL -Port 5986 -Authentication Basic` in `Invoke-RemoteBuild.ps1`, `Get-BuildArtifacts.ps1`, `Prepare-WinBuild2025.ps1`, `Validate-*.ps1`.
|
||
- [x] Rimuovere `AllowUnencrypted=true` da Deploy post-install.ps1 e Setup-WinBuild2025.ps1 (assertion → false).
|
||
- [x] `-SkipCACheck`/`-SkipCNCheck`/`-SkipRevocationCheck` mantenuti nei `New-PSSessionOption` e `New-WSManSessionOption` (cert lab self-signed — documentato inline).
|
||
- [x] Regola firewall `WinRM-HTTPS` in Deploy ristretta a `RemoteAddress '192.168.79.0/24'`.
|
||
- [x] `Wait-VMReady.ps1` usa `New-WSManSessionOption` + `Test-WSMan -Port 5986 -UseSSL`.
|
||
- [x] `Prepare-WinBuild2025.ps1`: preflight TCP/5986, host non imposta più `AllowUnencrypted`; solo `TrustedHosts` viene salvato/ripristinato.
|
||
- [x] `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](docs/BEST-PRACTICES.md).
|
||
|
||
**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](runner/config.yaml), [scripts/Invoke-CIJob.ps1:244-253](scripts/Invoke-CIJob.ps1).
|
||
|
||
**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](scripts/Cleanup-OrphanedBuildVMs.ps1) — script pronto, scheduling registrato da [scripts/Register-CIScheduledTasks.ps1](scripts/Register-CIScheduledTasks.ps1).
|
||
|
||
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] [x] Retention artifact + log automatica — COMPLETATO 2026-05-10
|
||
File: [scripts/Invoke-RetentionPolicy.ps1](scripts/Invoke-RetentionPolicy.ps1) — script creato; scheduling via [scripts/Register-CIScheduledTasks.ps1](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](scripts/Remove-BuildVM.ps1).
|
||
|
||
`[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).
|
||
|
||
**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](scripts/Backup-CITemplate.ps1).
|
||
|
||
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] [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).
|
||
|
||
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/Set-TemplateSharedFolders.ps1), [scripts/Invoke-RemoteBuild.ps1](scripts/Invoke-RemoteBuild.ps1).
|
||
|
||
`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`.
|
||
|
||
`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](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] [ ] In-VM clone (`-UseGitClone`)
|
||
Implementazione disegnata di seguito (sezione "In-VM Git Clone (Ottimizzazione)").
|
||
Vincoli sicurezza PAT: vedi §1.5. Tool prerequisiti (Git, 7-Zip): vedi §6.6.
|
||
Beneficio reale solo per repo > 200 MB con submoduli grandi; misurare prima.
|
||
|
||
### 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] [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.
|
||
|
||
---
|
||
|
||
## 4. Osservabilità & manutenzione
|
||
|
||
### 4.1 [P1] [x] Log strutturati per parsing — COMPLETATO 2026-05-10
|
||
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.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/_Common.Tests.ps1), [tests/New-BuildVM.Tests.ps1](tests/New-BuildVM.Tests.ps1), [tests/Remove-BuildVM.Tests.ps1](tests/Remove-BuildVM.Tests.ps1), [tests/Wait-VMReady.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](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](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] [ ] 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.
|
||
|
||
### 6.6 [P2] [ ] Toolchain Tier-1 in Setup-WinBuild2025
|
||
File: [template/Setup-WinBuild2025.ps1](template/Setup-WinBuild2025.ps1).
|
||
|
||
**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.
|
||
|
||
Tool da aggiungere come step `Setup-WinBuild2025` (ognuno con `Assert-Step`):
|
||
|
||
| Tool | Versione | Razionale |
|
||
| ------------------- | ----------------------- | -------------------------------------------------------------- |
|
||
| **Git for Windows** | latest LTS | Self-clone in VM (alt a host-zip-transfer), submodule fetch |
|
||
| **7-Zip** | latest | Universale unpack/zip; molti installer e workflow ne dipendono |
|
||
| **PowerShell 7.x** | latest LTS | Più veloce di 5.1, parallel pipelines, operatori moderni |
|
||
| **NSIS** | latest | Test build installer (es. `nsis-plugin-nsinnounp`) |
|
||
| **CMake** | latest | Build system cross-platform per progetti C/C++ nativi |
|
||
| **Node.js LTS** | latest LTS | Frontend/Electron pipelines, JS toolchain (npm) |
|
||
| **WiX Toolset** | v4 stable | MSI building da .NET projects |
|
||
| **gh CLI** | latest | Upload artifact a release Gitea/GitHub, comment PR |
|
||
| **Sysinternals** | sysinternals.com `live` | Diagnostica process/handle quando build flaky |
|
||
| **vcpkg** | latest | 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/Deploy-WinBuild2025.ps1),
|
||
[template/Setup-WinBuild2025.ps1](template/Setup-WinBuild2025.ps1).
|
||
|
||
- [x] Aggiungere `Set-NetFirewallProfile -Enabled False` (tutti i profili) in Deploy post-install.ps1
|
||
- [x] Aggiungere `MaxMemoryPerShellMB=2048`, `IdleTimeOut=7200000`, `MaxProcessesPerShell=25`, `StartupType=Automatic` in Deploy dopo Enable-PSRemoting
|
||
- [x] 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
|
||
- [x] Setup Step 1 (Firewall) → Assert-Step only
|
||
- [x] Setup Step 2 (Defender) → già validation-only (refactor 2026-05-09)
|
||
- [x] Setup Step 3 (WinRM tuning) → Assert-Step only (rimuovi Enable-PSRemoting, winrm set, Set-Item, Set-Service)
|
||
- [x] Setup Step 4b (UAC) → Assert-Step only
|
||
- [x] Setup Step 5b (Explorer LaunchTo) → Assert-Step only
|
||
- [x] Setup Step 5c (Server Manager / DisableCAD / OOBE) → Assert-Step only
|
||
- [x] 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/Deploy-WinBuild2025.ps1),
|
||
[template/Setup-WinBuild2025.ps1](template/Setup-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.
|
||
|
||
- [x] Deploy: rimuovere `sc.exe config wuauserv start= disabled` (e UsoSvc, WaaSMedicSvc)
|
||
- [x] Deploy: aggiungere GPO `DisableWindowsUpdateAccess=1` (era mancante; `NoAutoUpdate=1` già presente)
|
||
- [x] Setup Step 6 Step A: già rimuove `DisableWindowsUpdateAccess` + `NoAutoUpdate` prima del COM API — nessuna modifica necessaria
|
||
- [x] Setup Step 6 Step D: già fa `Set-Service start=Manual` + `Start-Service` — idempotente con servizi già Manual
|
||
- [x] Setup Step 6b: già disabilita wuauserv/UsoSvc + GPO keys — nessuna modifica necessaria
|
||
- [x] E2e validation — completata §7.4 (2026-05-10)
|
||
|
||
### 7.3 [P2] [x] Update header docs di entrambi gli script
|
||
|
||
- [x] [template/Deploy-WinBuild2025.ps1](template/Deploy-WinBuild2025.ps1) `.DESCRIPTION`: aggiornato con tutte le hardening voci (firewall, WinRM tuning, WU GPO strategy B, lock screen, SM, OOBE)
|
||
- [x] [template/Setup-WinBuild2025.ps1](template/Setup-WinBuild2025.ps1) `.DESCRIPTION`: Steps 1/3/4b/5b/5c marcati "validation-only — set by Deploy"; step ordering rationale aggiornato
|
||
- [x] [docs/WINDOWS-TEMPLATE-SETUP.md](docs/WINDOWS-TEMPLATE-SETUP.md): architettura "tre script", VMX path `CI-WinBuild.vmx`, Fase C step list + razionale + tabella validazioni aggiornati
|
||
|
||
### 7.4 [P2] [x] Test e2e refactor — COMPLETATO 2026-05-10
|
||
|
||
- [x] Deploy stand-alone su VM test → `Get-NetFirewallProfile` tutti `Enabled=False`, `Get-Service wuauserv | Select StartType` → `Manual`, `NoAutoUpdate=1` GPO presente
|
||
- [x] Prepare dopo Deploy con `-SkipWindowsUpdate` → tutti `Assert-Step` passano `[OK]` senza eseguire Set (log mostra solo validation output)
|
||
- [x] Prepare senza `-SkipWindowsUpdate` → WU (0 update trovati, ResultCode=0), Step 6b disabilita wuauserv/UsoSvc (`StartType=Disabled`)
|
||
- [x] 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] [ ] Rinomina Setup → Setup-CITools (opzionale, futuro)
|
||
Una volta che Setup fa solo build customization, nome `Setup-WinBuild2025` è impreciso —
|
||
non setup-a la build VM, **estende** un template OS già pronto con toolchain CI.
|
||
Rinominare in `Setup-CITools.ps1` o `Install-CIToolchain.ps1` rifletterebbe meglio la
|
||
responsabilità ridotta. Tracciare in TODO post-7.1/7.2.
|
||
|
||
---
|
||
|
||
## 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 `-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 Setup-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`**
|
||
- [ ] Aggiornare snapshot `BaseClean` con Git installato
|
||
- [ ] Eseguire `e2e-010` con `-UseGitClone` su `nsis-plugin-nsinnounp` (ha submoduli)
|
||
- [ ] Confrontare tempo totale con e2e-009 (senza `-UseGitClone`)
|
||
- [ ] Verificare che il PAT non appaia nei log di `Invoke-CIJob.ps1`
|
||
|
||
---
|
||
|
||
## 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)
|
||
|
||
- [ ] **Workflow Gitea — build matrix**
|
||
- [ ] 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
|
||
|
||
- [ ] **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
|
||
|
||
---
|
||
|
||
## 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](docs/BEST-PRACTICES.md).
|
||
|
||
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/Setup-WinBuild2025.ps1](template/Setup-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).
|
||
|
||
---
|
||
|
||
## 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\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 |
|