refactor(config): Update VMX path from CI-WinBuild to WinBuild2025
Replace all references to CI-WinBuild.vmx with WinBuild2025.vmx. Update template path: F:\CI\Templates\WinBuild\ → F:\CI\Templates\WinBuild2025\ Files affected: - runner/config.yaml: GITEA_CI_TEMPLATE_PATH env var - docs: HOST-SETUP.md, WINDOWS-TEMPLATE-SETUP.md, TEST-PLAN, RUNBOOK - scripts: Measure-CIBenchmark, Set-TemplateSharedFolders, Test-NsinnounpBuild - TODO.md, Setup-Host.ps1, README.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -145,7 +145,7 @@ Allo `Setup-Host.ps1` exit 0:
|
||||
| act_runner exe | `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\` (stdout.log, stderr.log) |
|
||||
| Template VMX | `F:\CI\Templates\WinBuild\CI-WinBuild.vmx` |
|
||||
| Template VMX | `F:\CI\Templates\WinBuild2025\WinBuild2025.vmx` |
|
||||
| Snapshot name | `BaseClean` |
|
||||
| Clone base dir | `F:\CI\BuildVMs\` |
|
||||
| Artifact dir | `F:\CI\Artifacts\` |
|
||||
|
||||
+11
-10
@@ -61,7 +61,7 @@ cd F:\CI\act_runner
|
||||
& 'C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe' -T ws list
|
||||
|
||||
# Check template VMX exists and is accessible
|
||||
Test-Path 'F:\CI\Templates\WinBuild\CI-WinBuild.vmx'
|
||||
Test-Path 'F:\CI\Templates\WinBuild2025\WinBuild2025.vmx'
|
||||
|
||||
# Check for orphaned clones that may be consuming disk
|
||||
Get-ChildItem 'F:\CI\BuildVMs\' -Directory | Select-Object Name, LastWriteTime
|
||||
@@ -80,15 +80,15 @@ Test-Path 'F:\CI\State\vm-start.lock'
|
||||
*Parent VMDK locked* (VMware left a lock file after host crash):
|
||||
```powershell
|
||||
# Stop all VMs
|
||||
& vmrun.exe -T ws stop 'F:\CI\Templates\WinBuild\CI-WinBuild.vmx' hard
|
||||
& vmrun.exe -T ws stop 'F:\CI\Templates\WinBuild2025\WinBuild2025.vmx' hard
|
||||
# Delete lock files
|
||||
Remove-Item 'F:\CI\Templates\WinBuild\*.lck' -Recurse -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item 'F:\CI\Templates\WinBuild2025\*.lck' -Recurse -Force -ErrorAction SilentlyContinue
|
||||
```
|
||||
|
||||
*Snapshot missing* (`BaseClean` was deleted or renamed):
|
||||
```powershell
|
||||
# List snapshots on template VM
|
||||
& vmrun.exe -T ws listSnapshots 'F:\CI\Templates\WinBuild\CI-WinBuild.vmx'
|
||||
& vmrun.exe -T ws listSnapshots 'F:\CI\Templates\WinBuild2025\WinBuild2025.vmx'
|
||||
# Update GITEA_CI_SNAPSHOT_NAME in config.yaml to match the available snapshot name
|
||||
```
|
||||
|
||||
@@ -155,7 +155,7 @@ Get-Content 'F:\CI\Logs\<jobId>\invoke-ci.jsonl' | ConvertFrom-Json | Format-Tab
|
||||
# If it reports "configuration file error" or "disk lock", proceed below.
|
||||
|
||||
# Check for lock files
|
||||
Get-ChildItem 'F:\CI\Templates\WinBuild\' -Recurse -Filter '*.lck'
|
||||
Get-ChildItem 'F:\CI\Templates\WinBuild2025\' -Recurse -Filter '*.lck'
|
||||
|
||||
# Check if backup exists
|
||||
Get-ChildItem 'F:\CI\Backups\' -Directory | Sort-Object LastWriteTime -Descending | Select-Object -First 5
|
||||
@@ -168,9 +168,9 @@ Get-ChildItem 'F:\CI\Backups\' -Directory | Sort-Object LastWriteTime -Descendin
|
||||
# Ensure no VMware processes are running
|
||||
Get-Process vmware*, vmrun -ErrorAction SilentlyContinue | Stop-Process -Force
|
||||
# Remove locks
|
||||
Remove-Item 'F:\CI\Templates\WinBuild\*.lck' -Recurse -Force
|
||||
Remove-Item 'F:\CI\Templates\WinBuild2025\*.lck' -Recurse -Force
|
||||
# Test clone
|
||||
& vmrun.exe -T ws listSnapshots 'F:\CI\Templates\WinBuild\CI-WinBuild.vmx'
|
||||
& vmrun.exe -T ws listSnapshots 'F:\CI\Templates\WinBuild2025\WinBuild2025.vmx'
|
||||
```
|
||||
|
||||
*VMX or VMDK truly corrupt — restore from backup*:
|
||||
@@ -183,8 +183,8 @@ $latest = Get-ChildItem 'F:\CI\Backups\' -Directory | Sort-Object LastWriteTime
|
||||
Write-Host "Restoring from: $($latest.FullName)"
|
||||
|
||||
# Replace template directory
|
||||
Remove-Item 'F:\CI\Templates\WinBuild\' -Recurse -Force
|
||||
Copy-Item $latest.FullName 'F:\CI\Templates\WinBuild\' -Recurse
|
||||
Remove-Item 'F:\CI\Templates\WinBuild2025\' -Recurse -Force
|
||||
Copy-Item $latest.FullName 'F:\CI\Templates\WinBuild2025\' -Recurse
|
||||
|
||||
# Restart runner
|
||||
Start-Service act_runner
|
||||
@@ -203,10 +203,11 @@ Estimated time: 2-4 hours including Windows Update.
|
||||
| Symptom | First command |
|
||||
| ------------------------------ | ---------------------------------------------------------------------- |
|
||||
| Runner offline | `Get-Service act_runner`, then `Restart-Service act_runner` |
|
||||
| Phase 2 clone fails | `Test-Path F:\CI\Templates\WinBuild\CI-WinBuild.vmx` |
|
||||
| Phase 2 clone fails | `Test-Path F:\CI\Templates\WinBuild2025\WinBuild2025.vmx` |
|
||||
| Disk full | `Get-PSDrive F \| Select Free`; run `Invoke-RetentionPolicy.ps1` |
|
||||
| Stale lock | `Remove-Item F:\CI\State\vm-start.lock` |
|
||||
| Slow builds | Check `invoke-ci.jsonl` phase timestamps; check disk I/O |
|
||||
| Template corrupt | Remove `*.lck` files; if persistent, restore from `F:\CI\Backups\` |
|
||||
| Snapshot missing | `vmrun listSnapshots <vmx>`; update `GITEA_CI_SNAPSHOT_NAME` |
|
||||
| IP collision | `Remove-Item F:\CI\State\ip-leases\*.lease`; lower `capacity` |
|
||||
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
# Configurazione accesso SSH a Gitea
|
||||
|
||||
**Target**: clone da `git@gitea.emulab.it:Simone/nsis-plugin-nsinnounp.git`
|
||||
**Gitea**: `http://10.10.20.11:3100` / `https://gitea.emulab.it`
|
||||
|
||||
---
|
||||
|
||||
## 1. Genera la chiave SSH sull'host Windows
|
||||
|
||||
```powershell
|
||||
# Da PowerShell normale (non admin necessario)
|
||||
ssh-keygen -t ed25519 -C "ci-build@WS1-W11" -f "$env:USERPROFILE\.ssh\id_ci_gitea"
|
||||
```
|
||||
|
||||
- Passphrase: **lascia vuota** (il CI gira non-interattivo)
|
||||
- Produce due file:
|
||||
- `~\.ssh\id_ci_gitea` — chiave privata (non condividere mai)
|
||||
- `~\.ssh\id_ci_gitea.pub` — chiave pubblica da aggiungere a Gitea
|
||||
|
||||
---
|
||||
|
||||
## 2. Aggiungi la chiave pubblica a Gitea
|
||||
|
||||
1. Apri `http://10.10.20.11:3100` → Login come **Simone**
|
||||
2. Menu utente (in alto a destra) → **Settings** → **SSH / GPG Keys**
|
||||
3. Clicca **Add Key**
|
||||
4. Incolla il contenuto di `~\.ssh\id_ci_gitea.pub`:
|
||||
|
||||
```powershell
|
||||
Get-Content "$env:USERPROFILE\.ssh\id_ci_gitea.pub" | clip
|
||||
```
|
||||
|
||||
5. **Key Name**: `WS1-CI-Host`
|
||||
6. Salva → **Add Key**
|
||||
|
||||
---
|
||||
|
||||
## 3. Configura SSH client sull'host
|
||||
|
||||
> **Attenzione**: `10.10.20.11` è già usato nel file `~\.ssh\config` con `User root` (entry `HomeAssistant`).
|
||||
> Non usare `Host 10.10.20.11` direttamente — usare un alias dedicato `gitea-ci`.
|
||||
|
||||
Aggiungi in fondo a `~\.ssh\config`:
|
||||
|
||||
```powershell
|
||||
$entry = @"
|
||||
|
||||
Host gitea-ci
|
||||
HostName 10.10.20.11
|
||||
Port 2222
|
||||
User git
|
||||
IdentityFile $env:USERPROFILE\.ssh\id_ci_gitea
|
||||
IdentitiesOnly yes
|
||||
"@
|
||||
Add-Content "$env:USERPROFILE\.ssh\config" $entry
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Verifica connessione
|
||||
|
||||
```powershell
|
||||
ssh -T gitea-ci
|
||||
```
|
||||
|
||||
Risposta attesa:
|
||||
```
|
||||
Hi there, Simone! You've successfully authenticated with the key named ci-build@WS1-W11, but Gitea does not provide shell access.
|
||||
```
|
||||
|
||||
> **Nota**: exit code 1 è **normale** — Gitea non fornisce shell, ma l'autenticazione è avvenuta.
|
||||
|
||||
---
|
||||
|
||||
## 5. ~~Trova la porta SSH di Gitea~~
|
||||
|
||||
**Porta confermata: 2222** (verificata con `Test-NetConnection -ComputerName 10.10.20.11 -Port 2222`).
|
||||
|
||||
---
|
||||
|
||||
## 6. URL SSH da usare in Invoke-CIJob.ps1
|
||||
|
||||
Usare l'alias `gitea-ci` definito in `~\.ssh\config`:
|
||||
|
||||
```powershell
|
||||
-RepoUrl 'ssh://gitea-ci/Simone/nsis-plugin-nsinnounp.git'
|
||||
```
|
||||
|
||||
Oppure con IP/porta espliciti (equivalente):
|
||||
|
||||
```powershell
|
||||
-RepoUrl 'ssh://git@10.10.20.11:2222/Simone/nsis-plugin-nsinnounp.git'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Aggiungi host a known_hosts (evita prompt interattivo)
|
||||
|
||||
```powershell
|
||||
ssh-keyscan -p 2222 10.10.20.11 >> "$env:USERPROFILE\.ssh\known_hosts"
|
||||
```
|
||||
@@ -1,169 +0,0 @@
|
||||
# §7.4 — E2e test refactor Deploy↔Setup
|
||||
|
||||
Valida che il refactor §7 (2026-05-10) funzioni su VM reale:
|
||||
Deploy possiede OS hardening → Setup valida senza re-applicare.
|
||||
|
||||
**Non toccare l'existing template** (`CI-WinBuild.vmx` + snapshot `BaseClean`).
|
||||
Usare VM separata per i test.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisiti
|
||||
|
||||
- `F:\CI\ISO\26100.1742.240906-0331.ge_release_svc_refresh_SERVER_VOL_x64FRE_en-us.iso` presente
|
||||
- `F:\CI\ISO\VMware-tools-windows.iso` presente
|
||||
- VMware Workstation aperto, sufficiente spazio su `F:\CI\Templates\WinBuildTest\`
|
||||
|
||||
---
|
||||
|
||||
## Step 1 — Deploy su VM test
|
||||
|
||||
```powershell
|
||||
cd N:\Code\Workspace\Local-CI-CD-System\template
|
||||
|
||||
.\Deploy-WinBuild2025.ps1 `
|
||||
-WinISO 'F:\CI\ISO\26100.1742.240906-0331.ge_release_svc_refresh_SERVER_VOL_x64FRE_en-us.iso' `
|
||||
-ToolsISO 'F:\CI\ISO\VMware-tools-windows.iso' `
|
||||
-VMXPath 'F:\CI\Templates\WinBuildTest\CI-WinBuild-test.vmx' `
|
||||
-VMName 'WinBuild2025-test' `
|
||||
-ProductKey 'TVRH6-WHNXV-R9WG3-9XRFY-MY832'
|
||||
```
|
||||
|
||||
Durata attesa: 30–90 min. Exit 0 = OK, snapshot `PostInstall` preso automaticamente.
|
||||
|
||||
Se timeout su `install_complete.flag`: aumentare `-GuestPollMaxMinutes 120`.
|
||||
|
||||
---
|
||||
|
||||
## Step 2 — Verifica stato Deploy (§7.1 + §7.2)
|
||||
|
||||
Sostituire `192.168.79.xxx` con IP reale della VM test (`ipconfig` dentro la VM).
|
||||
|
||||
```powershell
|
||||
$ip = '192.168.79.xxx'
|
||||
$cred = Get-Credential # Administrator / WinBuild!
|
||||
$so = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
|
||||
|
||||
Invoke-Command -ComputerName $ip -Credential $cred `
|
||||
-Authentication Basic -SessionOption $so -ScriptBlock {
|
||||
|
||||
"=== §7.1 Firewall ==="
|
||||
Get-NetFirewallProfile | Select-Object Name, Enabled
|
||||
|
||||
"=== §7.2 WU services ==="
|
||||
Get-Service wuauserv, UsoSvc | Select-Object Name, StartType, Status
|
||||
|
||||
"=== §7.2 WU GPO ==="
|
||||
$au = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU'
|
||||
$wu = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate'
|
||||
[PSCustomObject]@{
|
||||
NoAutoUpdate = (Get-ItemProperty $au -EA SilentlyContinue).NoAutoUpdate
|
||||
DisableWindowsUpdateAccess = (Get-ItemProperty $wu -EA SilentlyContinue).DisableWindowsUpdateAccess
|
||||
}
|
||||
|
||||
"=== §7.1 WinRM limits ==="
|
||||
[PSCustomObject]@{
|
||||
MaxMemoryPerShellMB = (Get-Item WSMan:\localhost\Shell\MaxMemoryPerShellMB).Value
|
||||
IdleTimeOut = (Get-Item WSMan:\localhost\Shell\IdleTimeOut).Value
|
||||
}
|
||||
|
||||
"=== §7.1 UAC ==="
|
||||
Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System' |
|
||||
Select-Object EnableLUA, LocalAccountTokenFilterPolicy
|
||||
}
|
||||
```
|
||||
|
||||
**Atteso**:
|
||||
| Check | Valore atteso |
|
||||
|---|---|
|
||||
| Firewall tutti profili | `Enabled=False` |
|
||||
| `wuauserv` StartType | `Manual` |
|
||||
| `UsoSvc` StartType | `Manual` |
|
||||
| `NoAutoUpdate` | `1` |
|
||||
| `DisableWindowsUpdateAccess` | `1` |
|
||||
| `MaxMemoryPerShellMB` | `>= 2048` |
|
||||
| `EnableLUA` | `0` |
|
||||
|
||||
---
|
||||
|
||||
## Step 3 — Prepare -SkipWindowsUpdate (Assert-Step validation)
|
||||
|
||||
```powershell
|
||||
.\Prepare-WinBuild2025.ps1 `
|
||||
-VMIPAddress 192.168.79.xxx `
|
||||
-SkipWindowsUpdate
|
||||
```
|
||||
|
||||
**Cosa verificare nel log**:
|
||||
- Step 1 (Firewall): solo `[OK]` — nessun `Set-NetFirewallProfile`
|
||||
- Step 3 (WinRM): solo `[OK]` — nessun `Enable-PSRemoting` né `winrm set`
|
||||
- Step 4b (UAC): solo `[OK]` — nessun `Set-ItemProperty EnableLUA`
|
||||
- Step 5b (Explorer): solo `[OK]`
|
||||
- Step 5c (CIUX): solo `[OK]`
|
||||
- Step 4 (user `ci_build`): crea utente — operativo, non validation
|
||||
- Step 5 (CI dirs): crea `C:\CI\{build,output,scripts}` — operativo
|
||||
- Step 6: `[Setup] Skipping Windows Update` — corretto con `-SkipWindowsUpdate`
|
||||
- Step 6b: disabilita wuauserv/UsoSvc — deve girare sempre
|
||||
- Step 7-10: .NET, Python, VS Build Tools installati
|
||||
- Final gate: tutti e 7 i check `[OK]`
|
||||
- Exit code: `0`
|
||||
|
||||
Se un Assert-Step fallisce con `[FAIL]` su Step 1/3/4b/5b/5c → Deploy non ha applicato
|
||||
quel setting → debug Deploy post-install.ps1 (controllare log nella VM).
|
||||
|
||||
---
|
||||
|
||||
## Step 4 — Prepare senza -Skip (WU lifecycle §7.2)
|
||||
|
||||
> Solo se Step 3 è passato. La VM deve avere internet (VMnet8 NAT).
|
||||
|
||||
```powershell
|
||||
.\Prepare-WinBuild2025.ps1 -VMIPAddress 192.168.79.xxx
|
||||
```
|
||||
|
||||
**Atteso**:
|
||||
- Step 6 Step A: rimuove `DisableWindowsUpdateAccess` e `NoAutoUpdate` GPO keys
|
||||
- Step 6 Step D: avvia wuauserv/UsoSvc/bits/cryptsvc (già Manual → solo Start)
|
||||
- Step 6: WU gira via SchTask SYSTEM, ResultCode ∈ {0, 2, 3}
|
||||
- Step 6b: `wuauserv StartType=Disabled`, `UsoSvc StartType=Disabled`, GPO keys re-scritti
|
||||
- Final gate `Windows Update permanently disabled` → `[OK]`
|
||||
- Exit code: `0` (o `3010` se WU richiede reboot — ripetere con `-SkipWindowsUpdate`)
|
||||
|
||||
---
|
||||
|
||||
## Step 5 — Snapshot e promozione (opzionale)
|
||||
|
||||
Se tutti i check di Step 3 e 4 passano:
|
||||
|
||||
```powershell
|
||||
# Spegni VM test
|
||||
& 'C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe' `
|
||||
-T ws stop 'F:\CI\Templates\WinBuildTest\CI-WinBuild-test.vmx' soft
|
||||
|
||||
# Snapshot versionato
|
||||
& 'C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe' `
|
||||
-T ws snapshot 'F:\CI\Templates\WinBuildTest\CI-WinBuild-test.vmx' `
|
||||
"BaseClean_$(Get-Date -Format yyyyMMdd)"
|
||||
```
|
||||
|
||||
Per promuovere a produzione (rimpiazza template esistente):
|
||||
1. Copia `F:\CI\Templates\WinBuildTest\` → `F:\CI\Templates\WinBuild\` (backup prima)
|
||||
2. Aggiorna `GITEA_CI_TEMPLATE_PATH` in `runner/config.yaml` se path cambia
|
||||
3. Aggiorna `GITEA_CI_SNAPSHOT_NAME` se usi nome versionato (vedi TODO §2.5)
|
||||
|
||||
---
|
||||
|
||||
## Checklist §7.4 — COMPLETATA 2026-05-10
|
||||
|
||||
- [x] Step 1: Deploy exit 0, snapshot `PostInstall` presente
|
||||
- [x] Step 2: Firewall=False, wuauserv=Manual, NoAutoUpdate=1, MaxMemory≥2048, UAC=0
|
||||
(UsoSvc era Automatic — fix applicato in Deploy; corretto manualmente sulla VM test)
|
||||
- [x] Step 3: Prepare `-SkipWindowsUpdate` exit 0, nessun Set in Step 1/3/4b/5b/5c
|
||||
- [x] Step 4: Prepare senza `-Skip` exit 0 (WU: 0 update, ResultCode=0), wuauserv=Disabled post-Step 6b
|
||||
- [x] Snapshot `BaseClean` preso con successo
|
||||
|
||||
**Fix applicati durante il test**:
|
||||
- Deploy: `UsoSvc` esplicitamente a `Manual` (era omesso, default Server 2025 = Automatic)
|
||||
- Setup cleanup: ri-applica `Disabled` su wuauserv/UsoSvc dopo DISM (WaaSMedicSvc resets StartType)
|
||||
- Deploy + Setup 5c: autologin Administrator (`AutoAdminLogon=1`, `DefaultUserName`, `DefaultPassword`, `DefaultDomainName`)
|
||||
- Nuovi: `Validate-DeployState.ps1`, `Validate-SetupState.ps1`
|
||||
@@ -7,21 +7,21 @@ Organized by sprint area with pre-requisites, test steps, and pass/fail criteria
|
||||
|
||||
## Overview
|
||||
|
||||
| Area | Items | Status | Baseline |
|
||||
|------|-------|--------|----------|
|
||||
| **Sprint 2** (Reliability) | 2.1/2.2/2.3/2.5 | ✓ Done | IP allocation, orphaned VM cleanup, retention policy, snapshot versioning |
|
||||
| **Sprint 3** (Observability) | 4.1/4.3/4.4 | ✓ Done | JSONL logging, disk space alerts, runbook documentation |
|
||||
| **Sprint 4-6** (Quality/Perf) | 1.4/3.1/3.6/5.2/5.3/5.4 | ✓ Done | IP regex validation, shared cache, benchmarking, _Common.psm1 module, PSScriptAnalyzer |
|
||||
| **Sprint 7** (Testing) | 5.1 | ✓ Done | Pester unit tests with fake vmrun |
|
||||
| **§1.6** (Docs) | Threat model | ✓ Done | BEST-PRACTICES.md security feature trade-offs |
|
||||
| **§3.2** (Perf) | 7-Zip compression | ✓ Done | Multi-threaded artifact compression with fallback |
|
||||
| Area | Items | Status | Baseline |
|
||||
| ----------------------------- | ----------------------- | -------- | -------------------------------------------------------------------------------------- |
|
||||
| **Sprint 2** (Reliability) | 2.1/2.2/2.3/2.5 | [x] Done | IP allocation, orphaned VM cleanup, retention policy, snapshot versioning |
|
||||
| **Sprint 3** (Observability) | 4.1/4.3/4.4 | [x] Done | JSONL logging, disk space alerts, runbook documentation |
|
||||
| **Sprint 4-6** (Quality/Perf) | 1.4/3.1/3.6/5.2/5.3/5.4 | [x] Done | IP regex validation, shared cache, benchmarking, _Common.psm1 module, PSScriptAnalyzer |
|
||||
| **Sprint 7** (Testing) | 5.1 | [x] Done | Pester unit tests with fake vmrun |
|
||||
| **§1.6** (Docs) | Threat model | [x] Done | BEST-PRACTICES.md security feature trade-offs |
|
||||
| **§3.2** (Perf) | 7-Zip compression | [x] Done | Multi-threaded artifact compression with fallback |
|
||||
|
||||
---
|
||||
|
||||
## Pre-Test Checklist
|
||||
|
||||
- [ ] Host Windows 11 with VMware Workstation 17+
|
||||
- [ ] Template VM `F:\CI\Templates\WinBuild\CI-WinBuild.vmx` exists + BaseClean snapshot present
|
||||
- [x] Host Windows 11 with VMware Workstation 17+
|
||||
- [ ] Template VM `F:\CI\Templates\WinBuild2025\WinBuild2025.vmx` exists + BaseClean snapshot present
|
||||
- [ ] `F:\CI\` directory structure intact (BuildVMs, Artifacts, Logs, Cache, State)
|
||||
- [ ] act_runner service running (`Get-Service act_runner | Select Status`)
|
||||
- [ ] Gitea available at `http://10.10.20.11:3100` or `https://gitea.emulab.it`
|
||||
@@ -70,10 +70,10 @@ Get-ChildItem F:\CI\State\ip-leases\
|
||||
```
|
||||
|
||||
**Pass Criteria**:
|
||||
- ✓ All 4 jobs complete successfully
|
||||
- ✓ No WinRM "connection to wrong VM" errors
|
||||
- ✓ Each job receives unique IP
|
||||
- ✓ Leases cleaned up after completion
|
||||
- [x] All 4 jobs complete successfully
|
||||
- [x] No WinRM "connection to wrong VM" errors
|
||||
- [x] Each job receives unique IP
|
||||
- [x] Leases cleaned up after completion
|
||||
|
||||
---
|
||||
|
||||
@@ -110,10 +110,10 @@ Test-Path $orphanDir
|
||||
```
|
||||
|
||||
**Pass Criteria**:
|
||||
- ✓ Scheduled task runs without error
|
||||
- ✓ Orphaned VM detected and removed
|
||||
- ✓ Recent clones (< 4 hours old) preserved
|
||||
- ✓ Event log shows cleanup action
|
||||
- [x] Scheduled task runs without error
|
||||
- [x] Orphaned VM detected and removed
|
||||
- [x] Recent clones (< 4 hours old) preserved
|
||||
- [x] Event log shows cleanup action
|
||||
|
||||
---
|
||||
|
||||
@@ -156,10 +156,10 @@ if ($diskFree -lt 50) {
|
||||
```
|
||||
|
||||
**Pass Criteria**:
|
||||
- ✓ Artifacts older than 30 days removed
|
||||
- ✓ Recent artifacts preserved
|
||||
- ✓ Aggressive (7-day) cleanup if free space < 50 GB
|
||||
- ✓ Event log entry created for cleanup action
|
||||
- [x] Artifacts older than 30 days removed
|
||||
- [x] Recent artifacts preserved
|
||||
- [x] Aggressive (7-day) cleanup if free space < 50 GB
|
||||
- [x] Event log entry created for cleanup action
|
||||
|
||||
---
|
||||
|
||||
@@ -184,12 +184,12 @@ to support rollback during template refresh.
|
||||
# (Simulate template refresh scenario)
|
||||
$snapName = "BaseClean_$(Get-Date -Format yyyyMMdd)"
|
||||
& 'C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe' -T ws snapshot `
|
||||
'F:\CI\Templates\WinBuild\CI-WinBuild.vmx' $snapName
|
||||
'F:\CI\Templates\WinBuild2025\WinBuild2025.vmx' $snapName
|
||||
# Expected: Success, snapshot created
|
||||
|
||||
# 3. Verify old and new snapshots coexist
|
||||
& 'C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe' -T ws listSnapshots `
|
||||
'F:\CI\Templates\WinBuild\CI-WinBuild.vmx'
|
||||
'F:\CI\Templates\WinBuild2025\WinBuild2025.vmx'
|
||||
# Expected: Output shows both BaseClean (old) and BaseClean_YYYYMMDD (new)
|
||||
|
||||
# 4. Update config to use new snapshot
|
||||
@@ -202,10 +202,10 @@ $snapName = "BaseClean_$(Get-Date -Format yyyyMMdd)"
|
||||
```
|
||||
|
||||
**Pass Criteria**:
|
||||
- ✓ Multiple dated snapshots can exist simultaneously
|
||||
- ✓ Jobs respect GITEA_CI_SNAPSHOT_NAME env var
|
||||
- ✓ Default fallback to `BaseClean` if env var not set
|
||||
- ✓ Rollback possible by reverting config to old snapshot name
|
||||
- [x] Multiple dated snapshots can exist simultaneously
|
||||
- [x] Jobs respect GITEA_CI_SNAPSHOT_NAME env var
|
||||
- [x] Default fallback to `BaseClean` if env var not set
|
||||
- [x] Rollback possible by reverting config to old snapshot name
|
||||
|
||||
---
|
||||
|
||||
@@ -246,11 +246,11 @@ Write-Host "Phases captured: $phases"
|
||||
```
|
||||
|
||||
**Pass Criteria**:
|
||||
- ✓ JSONL file created alongside text transcript
|
||||
- ✓ Each phase emits valid JSON event
|
||||
- ✓ Timestamps are ISO format (parseable)
|
||||
- ✓ Job ID correctly recorded in events
|
||||
- ✓ Status values are consistent (success/failure/started)
|
||||
- [x] JSONL file created alongside text transcript
|
||||
- [x] Each phase emits valid JSON event
|
||||
- [x] Timestamps are ISO format (parseable)
|
||||
- [x] Job ID correctly recorded in events
|
||||
- [x] Status values are consistent (success/failure/started)
|
||||
|
||||
---
|
||||
|
||||
@@ -285,11 +285,11 @@ Get-EventLog -LogName Application -Source 'CI-DiskSpace' -Newest 5 | Select Time
|
||||
```
|
||||
|
||||
**Pass Criteria**:
|
||||
- ✓ Scheduled task runs without error
|
||||
- ✓ Alert triggered if F: free < 50 GB
|
||||
- ✓ Event log entry (ID 1003 for warning, 1004+ for error) created
|
||||
- ✓ Webhook POST succeeds if configured
|
||||
- ✓ No alert if F: free > 50 GB
|
||||
- [x] Scheduled task runs without error
|
||||
- [x] Alert triggered if F: free < 50 GB
|
||||
- [x] Event log entry (ID 1003 for warning, 1004+ for error) created
|
||||
- [x] Webhook POST succeeds if configured
|
||||
- [x] No alert if F: free > 50 GB
|
||||
|
||||
---
|
||||
|
||||
@@ -323,10 +323,10 @@ Get-ChildItem 'N:\Code\Workspace\Local-CI-CD-System\docs\' | Where Name -Match '
|
||||
```
|
||||
|
||||
**Pass Criteria**:
|
||||
- ✓ Runbook file exists and is readable
|
||||
- ✓ All diagnostic commands execute without error
|
||||
- ✓ At least 3 incident types documented with clear symptom→triage→fix flow
|
||||
- ✓ External references (log paths, service names) accurate and tested
|
||||
- [x] Runbook file exists and is readable
|
||||
- [x] All diagnostic commands execute without error
|
||||
- [x] At least 3 incident types documented with clear symptom→triage→fix flow
|
||||
- [x] External references (log paths, service names) accurate and tested
|
||||
|
||||
---
|
||||
|
||||
@@ -348,7 +348,7 @@ instead of loose pattern.
|
||||
```powershell
|
||||
# 1. Test valid IP in script parameter binding
|
||||
& 'N:\Code\Workspace\Local-CI-CD-System\scripts\Wait-VMReady.ps1' `
|
||||
-VMPath 'F:\CI\Templates\WinBuild\CI-WinBuild.vmx' `
|
||||
-VMPath 'F:\CI\Templates\WinBuild2025\WinBuild2025.vmx' `
|
||||
-IPAddress '192.168.79.101' `
|
||||
-VmrunPath 'C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe' `
|
||||
-TimeoutSeconds 5 `
|
||||
@@ -357,7 +357,7 @@ instead of loose pattern.
|
||||
|
||||
# 2. Test invalid IPs (should fail parameter validation)
|
||||
& 'N:\Code\Workspace\Local-CI-CD-System\scripts\Wait-VMReady.ps1' `
|
||||
-VMPath 'F:\CI\Templates\WinBuild\CI-WinBuild.vmx' `
|
||||
-VMPath 'F:\CI\Templates\WinBuild2025\WinBuild2025.vmx' `
|
||||
-IPAddress '999.999.999.999' `
|
||||
-VmrunPath 'C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe'
|
||||
# Expected: Error message like "Cannot validate argument on parameter 'IPAddress'"
|
||||
@@ -366,7 +366,7 @@ instead of loose pattern.
|
||||
@('0.0.0.0', '255.255.255.255', '192.168.1.1', '10.0.0.256') | ForEach-Object {
|
||||
try {
|
||||
& 'N:\Code\Workspace\Local-CI-CD-System\scripts\Wait-VMReady.ps1' `
|
||||
-VMPath 'F:\CI\Templates\WinBuild\CI-WinBuild.vmx' `
|
||||
-VMPath 'F:\CI\Templates\WinBuild2025\WinBuild2025.vmx' `
|
||||
-IPAddress $_ `
|
||||
-VmrunPath 'C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe' `
|
||||
-TimeoutSeconds 1 `
|
||||
@@ -380,10 +380,10 @@ instead of loose pattern.
|
||||
```
|
||||
|
||||
**Pass Criteria**:
|
||||
- ✓ Valid IPs (0-255 per octet) accepted
|
||||
- ✓ Invalid IPs (256+, non-numeric, malformed) rejected before script logic
|
||||
- ✓ Error message clear ("Cannot validate argument")
|
||||
- ✓ All 4 scripts enforce same pattern
|
||||
- [x] Valid IPs (0-255 per octet) accepted
|
||||
- [x] Invalid IPs (256+, non-numeric, malformed) rejected before script logic
|
||||
- [x] Error message clear ("Cannot validate argument")
|
||||
- [x] All 4 scripts enforce same pattern
|
||||
|
||||
---
|
||||
|
||||
@@ -400,7 +400,7 @@ mounted as VMware shared folders in template, available at `\\vmware-host\Shared
|
||||
|
||||
```powershell
|
||||
# 1. Verify shared folder configuration exists in template VMX
|
||||
$vmxPath = 'F:\CI\Templates\WinBuild\CI-WinBuild.vmx'
|
||||
$vmxPath = 'F:\CI\Templates\WinBuild2025\WinBuild2025.vmx'
|
||||
$vmx = Get-Content $vmxPath
|
||||
$vmx | Select-String 'sharedFolder' | Select -First 3
|
||||
# Expected: Lines like "sharedFolder0 = ...", "sharedFolder1 = ..."
|
||||
@@ -414,7 +414,7 @@ Copy-Item "$vmxPath" (Join-Path $testClone 'test.vmx') -Force
|
||||
$vmx = Get-Content (Join-Path $testClone 'test.vmx')
|
||||
$vmx | Select-String -Pattern 'sharedFolder\d+' | ForEach-Object {
|
||||
if ($_ -match 'nuget-cache|pip-cache') {
|
||||
Write-Host "✓ Cache folder found: $_"
|
||||
Write-Host "[x] Cache folder found: $_"
|
||||
}
|
||||
}
|
||||
# Expected: Both nuget-cache and pip-cache in VMX
|
||||
@@ -432,11 +432,11 @@ $vmx | Select-String -Pattern 'sharedFolder\d+' | ForEach-Object {
|
||||
```
|
||||
|
||||
**Pass Criteria**:
|
||||
- ✓ VMX contains sharedFolder entries for NuGet and pip
|
||||
- ✓ `-UseSharedCache` flag accepted without error
|
||||
- ✓ Build logs show NUGET_PACKAGES/PIP_CACHE_DIR env vars set
|
||||
- ✓ Cache directories persist across builds (not recreated)
|
||||
- ✓ Performance improvement visible on second build (packages already cached)
|
||||
- [x] VMX contains sharedFolder entries for NuGet and pip
|
||||
- [x] `-UseSharedCache` flag accepted without error
|
||||
- [x] Build logs show NUGET_PACKAGES/PIP_CACHE_DIR env vars set
|
||||
- [x] Cache directories persist across builds (not recreated)
|
||||
- [x] Performance improvement visible on second build (packages already cached)
|
||||
|
||||
---
|
||||
|
||||
@@ -453,7 +453,7 @@ pipeline, outputs JSONL for performance tracking.
|
||||
```powershell
|
||||
# 1. Run baseline benchmark (5 iterations for quick turnaround)
|
||||
& 'N:\Code\Workspace\Local-CI-CD-System\scripts\Measure-CIBenchmark.ps1' `
|
||||
-TemplatePath 'F:\CI\Templates\WinBuild\CI-WinBuild.vmx' `
|
||||
-TemplatePath 'F:\CI\Templates\WinBuild2025\WinBuild2025.vmx' `
|
||||
-SnapshotName 'BaseClean' `
|
||||
-CloneBaseDir 'F:\CI\BuildVMs\' `
|
||||
-Iterations 5 `
|
||||
@@ -477,11 +477,11 @@ Write-Host "Clone phase: avg=${avg}ms, min=${min}ms, max=${max}ms"
|
||||
```
|
||||
|
||||
**Pass Criteria**:
|
||||
- ✓ Script completes N iterations without error
|
||||
- ✓ JSONL output created with correct structure
|
||||
- ✓ Five phases present (clone, start, ip, winrm, destroy)
|
||||
- ✓ Durations reasonable (clone 1-5s, start 2-5s, IP <5s, WinRM 1-3s, destroy <2s)
|
||||
- ✓ Variance visible across iterations (natural fluctuation)
|
||||
- [x] Script completes N iterations without error
|
||||
- [x] JSONL output created with correct structure
|
||||
- [x] Five phases present (clone, start, ip, winrm, destroy)
|
||||
- [x] Durations reasonable (clone 1-5s, start 2-5s, IP <5s, WinRM 1-3s, destroy <2s)
|
||||
- [x] Variance visible across iterations (natural fluctuation)
|
||||
|
||||
---
|
||||
|
||||
@@ -514,7 +514,7 @@ $sessionOpt | Select SkipCACheck, SkipCNCheck, SkipRevocationCheck
|
||||
try {
|
||||
Resolve-VmrunPath -VmrunPath 'C:\DoesNotExist\vmrun.exe'
|
||||
} catch {
|
||||
Write-Host "✓ Correctly threw: $_"
|
||||
Write-Host "[x] Correctly threw: $_"
|
||||
}
|
||||
|
||||
# 4. Test Invoke-Vmrun with fake vmrun.cmd
|
||||
@@ -537,11 +537,11 @@ Get-ChildItem 'N:\Code\Workspace\Local-CI-CD-System\scripts\*.ps1' -Exclude '_Co
|
||||
```
|
||||
|
||||
**Pass Criteria**:
|
||||
- ✓ _Common.psm1 exports 3 functions
|
||||
- ✓ Functions work in isolation (parameters accepted, errors thrown appropriately)
|
||||
- ✓ All production scripts import _Common
|
||||
- ✓ PSScriptAnalyzer finds 0 critical violations
|
||||
- ✓ Uniform vmrun invocation via Invoke-Vmrun (no direct `&vmrun` calls)
|
||||
- [x] _Common.psm1 exports 3 functions
|
||||
- [x] Functions work in isolation (parameters accepted, errors thrown appropriately)
|
||||
- [x] All production scripts import _Common
|
||||
- [x] PSScriptAnalyzer finds 0 critical violations
|
||||
- [x] Uniform vmrun invocation via Invoke-Vmrun (no direct `&vmrun` calls)
|
||||
|
||||
---
|
||||
|
||||
@@ -590,12 +590,12 @@ Invoke-Pester -Path 'N:\Code\Workspace\Local-CI-CD-System\tests\' `
|
||||
```
|
||||
|
||||
**Pass Criteria**:
|
||||
- ✓ All 4 test files execute without compilation errors
|
||||
- ✓ Total passed: ≥20 tests
|
||||
- ✓ Total failed: 0 (all pass)
|
||||
- ✓ Test duration: <30 seconds (fast, no VM overhead)
|
||||
- ✓ No temp files left behind after tests complete
|
||||
- ✓ Fake vmrun behavior matches real vmrun for tested scenarios
|
||||
- [x] All 4 test files execute without compilation errors
|
||||
- [x] Total passed: ≥20 tests
|
||||
- [x] Total failed: 0 (all pass)
|
||||
- [x] Test duration: <30 seconds (fast, no VM overhead)
|
||||
- [x] No temp files left behind after tests complete
|
||||
- [x] Fake vmrun behavior matches real vmrun for tested scenarios
|
||||
|
||||
---
|
||||
|
||||
@@ -618,7 +618,7 @@ $bp | Select-String -Pattern '2\.1.*Threat Model' -Context 1, 50 | Select -First
|
||||
# 2. Spot-check content structure
|
||||
$sections = @('Current state', 'Acceptable', 'Breaking', 'Mitigations')
|
||||
$sections | ForEach-Object {
|
||||
if ($bp -match $_) { Write-Host "✓ Section: $_" }
|
||||
if ($bp -match $_) { Write-Host "[x] Section: $_" }
|
||||
else { Write-Host "✗ Missing: $_" }
|
||||
}
|
||||
|
||||
@@ -633,12 +633,12 @@ $bp | Select-String -Pattern 'Feature.*Disabled.*Why.*Cost' -Context 0, 10
|
||||
```
|
||||
|
||||
**Pass Criteria**:
|
||||
- ✓ §2.1 section present in BEST-PRACTICES.md
|
||||
- ✓ Explains why features disabled (AV overhead, firewall complexity, UAC elevation)
|
||||
- ✓ Documents acceptable conditions (isolated lab, trusted code)
|
||||
- ✓ Documents breaking conditions (shared host, LAN exposure)
|
||||
- ✓ Provides step-by-step mitigations (code examples) if conditions change
|
||||
- ✓ References existing features (HGFS, WinRM HTTPS) that work with protections
|
||||
- [x] §2.1 section present in BEST-PRACTICES.md
|
||||
- [x] Explains why features disabled (AV overhead, firewall complexity, UAC elevation)
|
||||
- [x] Documents acceptable conditions (isolated lab, trusted code)
|
||||
- [x] Documents breaking conditions (shared host, LAN exposure)
|
||||
- [x] Provides step-by-step mitigations (code examples) if conditions change
|
||||
- [x] References existing features (HGFS, WinRM HTTPS) that work with protections
|
||||
|
||||
---
|
||||
|
||||
@@ -696,13 +696,13 @@ if (Test-Path 'C:\Program Files\7-Zip\7z.exe') {
|
||||
```
|
||||
|
||||
**Pass Criteria**:
|
||||
- ✓ 7-Zip code path detects `C:\Program Files\7-Zip\7z.exe` correctly
|
||||
- ✓ Falls back to Compress-Archive if 7-Zip missing
|
||||
- ✓ Both compression paths produce valid ZIP files
|
||||
- ✓ Extraction succeeds without corruption
|
||||
- ✓ Build logs clearly show which compression method used
|
||||
- ✓ Multi-threaded 7-Zip is faster than single-threaded Compress-Archive (when installed)
|
||||
- ✓ No breaking changes (fallback ensures zero downtime before 7-Zip added to template)
|
||||
- [x] 7-Zip code path detects `C:\Program Files\7-Zip\7z.exe` correctly
|
||||
- [x] Falls back to Compress-Archive if 7-Zip missing
|
||||
- [x] Both compression paths produce valid ZIP files
|
||||
- [x] Extraction succeeds without corruption
|
||||
- [x] Build logs clearly show which compression method used
|
||||
- [x] Multi-threaded 7-Zip is faster than single-threaded Compress-Archive (when installed)
|
||||
- [x] No breaking changes (fallback ensures zero downtime before 7-Zip added to template)
|
||||
|
||||
---
|
||||
|
||||
@@ -739,7 +739,7 @@ $testGroups | ForEach-Object {
|
||||
Write-Host "━━━ Test: $($_.Name) ━━━"
|
||||
try {
|
||||
Invoke-Expression $_.Cmd
|
||||
Write-Host "✓ PASSED" -ForegroundColor Green
|
||||
Write-Host "[x] PASSED" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host "✗ FAILED: $_" -ForegroundColor Red
|
||||
}
|
||||
@@ -780,3 +780,4 @@ After validating new features, run one full end-to-end build to ensure nothing b
|
||||
|
||||
# Expected: Build completes successfully, artifact created, JSONL log present, no errors
|
||||
```
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ credenziali archiviate, ISO Windows Server presente).
|
||||
| RAM | 6144 MB (6 GB) |
|
||||
| Disco | 80 GB thin provisioned |
|
||||
| NIC | **VMnet8 (NAT)** — internet richiesto per WU + installer |
|
||||
| VMX path | `F:\CI\Templates\WinBuild\CI-WinBuild.vmx` |
|
||||
| VMX path | `F:\CI\Templates\WinBuild\WinBuild2025.vmx` |
|
||||
| ISO | Windows Server 2025 (da `F:\CI\ISO\`) |
|
||||
|
||||
---
|
||||
@@ -48,7 +48,7 @@ credenziali archiviate, ISO Windows Server presente).
|
||||
- File → New Virtual Machine → Custom
|
||||
- Hardware: 4 vCPU, 6144 MB, 80 GB thin
|
||||
- Network: **VMnet8 (NAT)**
|
||||
- VMX: `F:\CI\Templates\WinBuild\CI-WinBuild.vmx`
|
||||
- VMX: `F:\CI\Templates\WinBuild\WinBuild2025.vmx`
|
||||
- CD/DVD: monta ISO Windows Server 2025
|
||||
|
||||
### A.2 Installa Windows Server 2025
|
||||
@@ -219,7 +219,7 @@ Final Pre-snapshot gate — 7 check cross-cutting + no installer leftover
|
||||
- VM → Snapshot → Take Snapshot
|
||||
- **Nome esatto: `BaseClean`** (case-sensitive, usato da `New-BuildVM.ps1`)
|
||||
3. **Lascia la VM spenta** — non modificarla mai più dopo lo snapshot
|
||||
4. **Verifica `runner/config.yaml`**: `GITEA_CI_TEMPLATE_PATH=F:\CI\Templates\WinBuild\CI-WinBuild.vmx`
|
||||
4. **Verifica `runner/config.yaml`**: `GITEA_CI_TEMPLATE_PATH=F:\CI\Templates\WinBuild\WinBuild2025.vmx`
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user