Refactor documentation and analysis in final master plan, opus47 analysis, and opus47 review of GPT-5.5

- Updated the final master plan to improve clarity and consistency in the status of various capabilities, including fixes and enhancements made as of 2026-05-12.
- Revised the opus47 analysis to provide a more structured overview of the system's production readiness, including detailed coverage of OWASP Top 10 risks and operational gaps.
- Enhanced the opus47 review of GPT-5.5 by clarifying severity ratings and rationales for various items, while adding new high-severity items that were previously overlooked.
This commit is contained in:
Simone
2026-05-13 00:08:19 +02:00
parent 5d1b47e943
commit 3592dcab78
13 changed files with 350 additions and 343 deletions
+53 -53
View File
@@ -35,41 +35,41 @@ Ogni build gira in una VM **usa e getta** ripristinata dallo snapshot: Windows S
## Requisiti Host ## Requisiti Host
| Componente | Versione / Dettaglio | | Componente | Versione / Dettaglio |
|---|---| | ---------------------- | ----------------------------------------------------------------- |
| OS | Windows 11 | | OS | Windows 11 |
| CPU/RAM | i9-10900X, 64 GB RAM | | CPU/RAM | i9-10900X, 64 GB RAM |
| VMware Workstation Pro | installato, `vmrun.exe` disponibile | | VMware Workstation Pro | installato, `vmrun.exe` disponibile |
| PowerShell | 5.1 | | PowerShell | 5.1 |
| act_runner | v1.0.2 — `F:\CI\act_runner\act_runner.exe` | | act_runner | v1.0.2 — `F:\CI\act_runner\act_runner.exe` |
| Gitea | self-hosted `http://10.10.20.11:3100` / `https://gitea.emulab.it` | | Gitea | self-hosted `http://10.10.20.11:3100` / `https://gitea.emulab.it` |
## Template VM ## Template VM
### Windows (snapshot `BaseClean`) ### Windows (snapshot `BaseClean`)
| Componente | Versione | | Componente | Versione |
|---|---| | -------------- | ------------------------------------------------------------------------------ |
| OS | Windows Server 2025 | | OS | Windows Server 2025 |
| VMX | `F:\CI\Templates\WinBuild2025\WinBuild2025.vmx` (env `GITEA_CI_TEMPLATE_PATH`) | | VMX | `F:\CI\Templates\WinBuild2025\WinBuild2025.vmx` (env `GITEA_CI_TEMPLATE_PATH`) |
| VS Build Tools | 2026 (MSBuild 18.5.4 / toolset v145) | | VS Build Tools | 2026 (MSBuild 18.5.4 / toolset v145) |
| .NET SDK | 10.0.203 | | .NET SDK | 10.0.203 |
| Python | 3.13.3 | | Python | 3.13.3 |
| Rete | VMnet8 NAT — `192.168.79.0/24` | | Rete | VMnet8 NAT — `192.168.79.0/24` |
| WinRM | HTTPS/5986, Basic auth, self-signed cert (SkipCACheck — lab-only) | | WinRM | HTTPS/5986, Basic auth, self-signed cert (SkipCACheck — lab-only) |
Variante **Windows Server 2022**: `*WinBuild2022.ps1` + VMX `F:\CI\Templates\WinBuild2022\WinBuild2022.vmx`. Variante **Windows Server 2022**: `*WinBuild2022.ps1` + VMX `F:\CI\Templates\WinBuild2022\WinBuild2022.vmx`.
### Linux (snapshot `BaseClean-Linux`) ### Linux (snapshot `BaseClean-Linux`)
| Componente | Versione | | Componente | Versione |
|---|---| | ------------ | ---------------------------------------------------------------------------------------- |
| OS | Ubuntu 24.04 LTS (cloud image) | | OS | Ubuntu 24.04 LTS (cloud image) |
| VMX | `F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx` (env `GITEA_CI_LINUX_TEMPLATE_PATH`) | | VMX | `F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx` (env `GITEA_CI_LINUX_TEMPLATE_PATH`) |
| Toolchain | GCC, G++, Clang, CMake, Ninja, Python 3, Git, 7-Zip | | Toolchain | GCC, G++, Clang, CMake, Ninja, Python 3, Git, 7-Zip |
| Rete | VMnet8 NAT — `192.168.79.0/24` | | Rete | VMnet8 NAT — `192.168.79.0/24` |
| SSH | porta 22, utente `ci_build`, chiave `F:\CI\keys\ci_linux` | | SSH | porta 22, utente `ci_build`, chiave `F:\CI\keys\ci_linux` |
| Runner label | `linux-build:host` | | Runner label | `linux-build:host` |
--- ---
@@ -217,14 +217,14 @@ nssm start act_runner
Imposta queste variabili d'ambiente nel servizio (`runner/config.yaml`): Imposta queste variabili d'ambiente nel servizio (`runner/config.yaml`):
| Variabile | Valore | | Variabile | Valore |
|---|---| | ------------------------------ | --------------------------------------------------- |
| `GITEA_CI_TEMPLATE_PATH` | `F:\CI\Templates\WinBuild2025\WinBuild2025.vmx` | | `GITEA_CI_TEMPLATE_PATH` | `F:\CI\Templates\WinBuild2025\WinBuild2025.vmx` |
| `GITEA_CI_LINUX_TEMPLATE_PATH` | `F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx` | | `GITEA_CI_LINUX_TEMPLATE_PATH` | `F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx` |
| `GITEA_CI_CLONE_BASE_DIR` | `F:\CI\BuildVMs` | | `GITEA_CI_CLONE_BASE_DIR` | `F:\CI\BuildVMs` |
| `GITEA_CI_ARTIFACT_DIR` | `F:\CI\Artifacts` | | `GITEA_CI_ARTIFACT_DIR` | `F:\CI\Artifacts` |
| `GITEA_CI_GUEST_CRED_TARGET` | `BuildVMGuest` | | `GITEA_CI_GUEST_CRED_TARGET` | `BuildVMGuest` |
| `GITEA_CI_SSH_KEY_PATH` | `F:\CI\keys\ci_linux` | | `GITEA_CI_SSH_KEY_PATH` | `F:\CI\keys\ci_linux` |
Labels runner: `windows-build:host` (job Windows) e `linux-build:host` (job Linux). Labels runner: `windows-build:host` (job Windows) e `linux-build:host` (job Linux).
@@ -283,14 +283,14 @@ Usa una **strategy matrix** `[windows, linux]` che esegue in parallelo su entram
La composite action [gitea/actions/local-ci-build/action.yml](gitea/actions/local-ci-build/action.yml) La composite action [gitea/actions/local-ci-build/action.yml](gitea/actions/local-ci-build/action.yml)
asconde tutta la logica Invoke-CIJob.ps1 e accetta questi input principali: asconde tutta la logica Invoke-CIJob.ps1 e accetta questi input principali:
| Input | Descrizione | | Input | Descrizione |
|---|---| | ----------------- | ------------------------------------------------ |
| `build-command` | Comando di build da eseguire nel guest | | `build-command` | Comando di build da eseguire nel guest |
| `guest-os` | `Windows` (default) o `Linux` | | `guest-os` | `Windows` (default) o `Linux` |
| `artifact-source` | Path artifacts nel guest | | `artifact-source` | Path artifacts nel guest |
| `skip-artifact` | `true` per job senza output | | `skip-artifact` | `true` per job senza output |
| `repo-url` | URL SSH del repository | | `repo-url` | URL SSH del repository |
| `job-id-suffix` | Suffisso per disambiguare artifact dir in matrix | | `job-id-suffix` | Suffisso per disambiguare artifact dir in matrix |
Per adattare ad altri repository, copia [gitea/workflow-example.yml](gitea/workflow-example.yml) Per adattare ad altri repository, copia [gitea/workflow-example.yml](gitea/workflow-example.yml)
e aggiorna `build-command`, `artifact-source`, `repo-url`. e aggiorna `build-command`, `artifact-source`, `repo-url`.
@@ -299,19 +299,19 @@ e aggiorna `build-command`, `artifact-source`, `repo-url`.
## Documentazione ## Documentazione
| File | Contenuto | | File | Contenuto |
|---|---| | ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | Diagramma componenti e flusso dati | | [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | Diagramma componenti e flusso dati |
| [docs/CI-FLOW.md](docs/CI-FLOW.md) | Descrizione dettagliata di ogni fase del pipeline | | [docs/CI-FLOW.md](docs/CI-FLOW.md) | Descrizione dettagliata di ogni fase del pipeline |
| [docs/HOST-SETUP.md](docs/HOST-SETUP.md) | Bootstrap macchina host (Setup-Host.ps1) | | [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) | | [docs/WINDOWS-TEMPLATE-SETUP.md](docs/WINDOWS-TEMPLATE-SETUP.md) | Provisioning template Windows (Deploy + Prepare + Setup) |
| [docs/LINUX-TEMPLATE-SETUP.md](docs/LINUX-TEMPLATE-SETUP.md) | Template Ubuntu 24.04: Deploy-LinuxBuild2404, Prepare-LinuxBuild2404, snapshot BaseClean-Linux | | [docs/LINUX-TEMPLATE-SETUP.md](docs/LINUX-TEMPLATE-SETUP.md) | Template Ubuntu 24.04: Deploy-LinuxBuild2404, Prepare-LinuxBuild2404, snapshot BaseClean-Linux |
| [docs/OPTIMIZATION.md](docs/OPTIMIZATION.md) | Layout NVMe, snapshot strategy, cache, tuning | | [docs/OPTIMIZATION.md](docs/OPTIMIZATION.md) | Layout NVMe, snapshot strategy, cache, tuning |
| [docs/BEST-PRACTICES.md](docs/BEST-PRACTICES.md) | Sicurezza WinRM, threat model, credenziali | | [docs/BEST-PRACTICES.md](docs/BEST-PRACTICES.md) | Sicurezza WinRM, threat model, credenziali |
| [docs/RUNBOOK.md](docs/RUNBOOK.md) | Triage incident comuni (runner offline, clone fail, ecc.) | | [docs/RUNBOOK.md](docs/RUNBOOK.md) | Triage incident comuni (runner offline, clone fail, ecc.) |
| [docs/TEST-PLAN-v1.3-to-HEAD.md](docs/TEST-PLAN-v1.3-to-HEAD.md) | Test plan completo features post-v1.3 | | [docs/TEST-PLAN-v1.3-to-HEAD.md](docs/TEST-PLAN-v1.3-to-HEAD.md) | Test plan completo features post-v1.3 |
| [docs/Setup-GiteaSSH.md](docs/Setup-GiteaSSH.md) | Configurazione SSH alias `gitea-ci` | | [docs/Setup-GiteaSSH.md](docs/Setup-GiteaSSH.md) | Configurazione SSH alias `gitea-ci` |
| [TODO.md](TODO.md) | Roadmap, audit trail task completati, backlog | | [TODO.md](TODO.md) | Roadmap, audit trail task completati, backlog |
--- ---
+1 -1
View File
@@ -39,7 +39,7 @@ _Last updated: 2026-05-11 (post Sprint 15: §7.5 DONE — Rinomina Setup-* → I
| [x] | §4 Osservabilità & manutenzione | 3 | 0 | 4.1/4.3/4.4 done (4.2 Prometheus, 4.5 Dashboard rimossi) | | [x] | §4 Osservabilità & manutenzione | 3 | 0 | 4.1/4.3/4.4 done (4.2 Prometheus, 4.5 Dashboard rimossi) |
| [x] | §5 Qualità codice & test | 5 | 0 | 5.1/5.2/5.3/5.4/5.5 done | | [x] | §5 Qualità codice & test | 5 | 0 | 5.1/5.2/5.3/5.4/5.5 done |
| [x] | §6 Scalabilità & estensioni | 5 | 0 | 6.1-6.2 done, 6.3 deferred (home lab), 6.4-6.5 done, 6.6 done | | [x] | §6 Scalabilità & estensioni | 5 | 0 | 6.1-6.2 done, 6.3 deferred (home lab), 6.4-6.5 done, 6.6 done |
| [x] | §7 Refactor Deploy ↔ Setup | 5 | 0 | 7.1-7.5 done; Setup-* → Install-CIToolchain-* (2026-05-11) | | [x] | §7 Refactor Deploy ↔ Setup | 5 | 0 | 7.1-7.5 done; Setup-* → Install-CIToolchain-* (2026-05-11) |
| [x] | In-VM Git Clone (§3.3) | 4 | 0 | COMPLETATO 2026-05-10 — e2e PASS: 34s/25.7% vs baseline | | [x] | In-VM Git Clone (§3.3) | 4 | 0 | COMPLETATO 2026-05-10 — e2e PASS: 34s/25.7% vs baseline |
| [x] | Linux Build VM (§6.1) | 5 | 0 | Deploy/Prepare/Setup/Transport + doc + e2e PASS nsis7z.dll 2272 KB | | [x] | Linux Build VM (§6.1) | 5 | 0 | Deploy/Prepare/Setup/Transport + doc + e2e PASS nsis7z.dll 2272 KB |
+12 -12
View File
@@ -60,11 +60,11 @@ $session = New-PSSession -ComputerName $ip -Port 5986 -UseSSL -Authentication Ba
The template VM disables Windows Defender, Windows Firewall, and User Account Control (UAC). The template VM disables Windows Defender, Windows Firewall, and User Account Control (UAC).
This is **intentional** — not a bug, not an oversight. Each has tradeoffs: This is **intentional** — not a bug, not an oversight. Each has tradeoffs:
| Feature | Disabled? | Why | Cost if enabled | | Feature | Disabled? | Why | Cost if enabled |
|---------|-----------|-----|-----------------| | --------------------------------------- | --------- | ------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------- |
| **Windows Defender** | Yes | Real-time AV scanning blocks .NET compilation, Python wheels, and npm installs | 510 min per build overhead; false positives on dev tools | | **Windows Defender** | Yes | Real-time AV scanning blocks .NET compilation, Python wheels, and npm installs | 510 min per build overhead; false positives on dev tools |
| **Windows Firewall** | Yes | Blocks inbound WinRM even with rules; requires Domain/Home profile tuning | Complex rules; fragile across OS updates | | **Windows Firewall** | Yes | Blocks inbound WinRM even with rules; requires Domain/Home profile tuning | Complex rules; fragile across OS updates |
| **UAC (LocalAccountTokenFilterPolicy)** | Yes | Prevents non-elevated WinRM scripts from running builds | Requires built-in Administrator account; WinRM behaves like a user with limited rights | | **UAC (LocalAccountTokenFilterPolicy)** | Yes | Prevents non-elevated WinRM scripts from running builds | Requires built-in Administrator account; WinRM behaves like a user with limited rights |
### When this threat model is acceptable ### When this threat model is acceptable
@@ -368,13 +368,13 @@ cached in the ISO or in `F:\CI\ISO\`).
Priority targets (descending risk): Priority targets (descending risk):
| Installer | Script | Where to pin | | Installer | Script | Where to pin |
|-----------|--------|--------------| | ----------------------- | ----------------------------------------------- | ------------------------------------------------------ |
| Git for Windows `.exe` | `template/Install-CIToolchain-WinBuild2025.ps1` | `-sha256` param or `Get-FileHash` check after download | | Git for Windows `.exe` | `template/Install-CIToolchain-WinBuild2025.ps1` | `-sha256` param or `Get-FileHash` check after download |
| 7-Zip `.msi` / `.exe` | `template/Install-CIToolchain-WinBuild2025.ps1` | same | | 7-Zip `.msi` / `.exe` | `template/Install-CIToolchain-WinBuild2025.ps1` | same |
| Python `.exe` | `template/Install-CIToolchain-WinBuild2025.ps1` | same | | Python `.exe` | `template/Install-CIToolchain-WinBuild2025.ps1` | same |
| .NET SDK install script | `template/Install-CIToolchain-WinBuild2025.ps1` | HTTPS only; hash less critical | | .NET SDK install script | `template/Install-CIToolchain-WinBuild2025.ps1` | HTTPS only; hash less critical |
| Ubuntu cloud VMDK | `template/Deploy-LinuxBuild2404.ps1` | already implemented via `-VmdkSha256` parameter | | Ubuntu cloud VMDK | `template/Deploy-LinuxBuild2404.ps1` | already implemented via `-VmdkSha256` parameter |
**Implementation pattern** (PS 5.1): **Implementation pattern** (PS 5.1):
+10 -10
View File
@@ -8,17 +8,17 @@
Before any CI job runs, the following must be in place: Before any CI job runs, the following must be in place:
| Component | State | | Component | State |
| ------------------ | ----------------------------------------------------------------------- | | ------------------ | ----------------------------------------------------------------------------- |
| Gitea server | Running, accessible on LAN | | Gitea server | Running, accessible on LAN |
| act_runner | Registered, running as Windows service on host | | act_runner | Registered, running as Windows service on host |
| Template VM (Win) | Provisioned, snapshot "BaseClean" taken, VM powered off | | Template VM (Win) | Provisioned, snapshot "BaseClean" taken, VM powered off |
| Template VM (Lin) | Ubuntu 24.04 LTS, snapshot "BaseClean-Linux" taken, VM powered off (optional) | | Template VM (Lin) | Ubuntu 24.04 LTS, snapshot "BaseClean-Linux" taken, VM powered off (optional) |
| WinRM | Enabled on Windows template VM (inherits to all clones) | | WinRM | Enabled on Windows template VM (inherits to all clones) |
| SSH key | `F:\CI\keys\ci_linux` (ed25519) present; public key in Linux template | | SSH key | `F:\CI\keys\ci_linux` (ed25519) present; public key in Linux template |
| vmrun.exe | Present at `C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe` | | vmrun.exe | Present at `C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe` |
| `F:\CI\BuildVMs\` | Directory exists and writable | | `F:\CI\BuildVMs\` | Directory exists and writable |
| `F:\CI\Artifacts\` | Directory exists and writable | | `F:\CI\Artifacts\` | Directory exists and writable |
--- ---
+32 -32
View File
@@ -7,15 +7,15 @@ Eseguire **una volta** prima di qualsiasi provisioning del template VM o esecuzi
## Prerequisiti host ## Prerequisiti host
| Componente | Versione/Note | | Componente | Versione/Note |
| ----------------------- | ----------------------------------------------------------------- | | ------------------ | ----------------------------------------------------------------- |
| OS | Windows 11 (host fisico) o Windows Server 2022+ | | OS | Windows 11 (host fisico) o Windows Server 2022+ |
| VMware Workstation | Pro 17.x — necessario per `vmrun.exe` e supporto linked clone | | VMware Workstation | Pro 17.x — necessario per `vmrun.exe` e supporto linked clone |
| Storage | NVMe dedicato (consigliato `F:\` riservato a CI, ≥ 500 GB libero) | | Storage | NVMe dedicato (consigliato `F:\` riservato a CI, ≥ 500 GB libero) |
| RAM | ≥ 32 GB (4 VM parallele × 6-8 GB) | | RAM | ≥ 32 GB (4 VM parallele × 6-8 GB) |
| Rete | VMnet8 (NAT) configurato in VMware Workstation | | Rete | VMnet8 (NAT) configurato in VMware Workstation |
| PowerShell | 5.1+ (built-in) o 7.x | | PowerShell | 5.1+ (built-in) o 7.x |
| Privilegi | Account amministrativo per Setup-Host.ps1 | | Privilegi | Account amministrativo per Setup-Host.ps1 |
Software opzionali installati on-demand dallo script: Software opzionali installati on-demand dallo script:
- **NSSM** — installazione automatica via Chocolatey se presente; altrimenti install manuale da https://nssm.cc - **NSSM** — installazione automatica via Chocolatey se presente; altrimenti install manuale da https://nssm.cc
@@ -94,20 +94,20 @@ Apri PowerShell **come Administrator**, poi:
## Parametri principali ## Parametri principali
| Parametro | Default | Note | | Parametro | Default | Note |
| ---------------------------- | -------------------------------- | ------------------------------------- | | ------------------------ | ------------------------------------ | ------------------------------------- |
| `-CIRoot` | `F:\CI` | Base directory per tutti i dati CI | | `-CIRoot` | `F:\CI` | Base directory per tutti i dati CI |
| `-GuestCredentialTarget` | `BuildVMGuest` | Target Credential Manager | | `-GuestCredentialTarget` | `BuildVMGuest` | Target Credential Manager |
| `-GuestUsername` | `ci_build` | Account build dentro la VM | | `-GuestUsername` | `ci_build` | Account build dentro la VM |
| `-GuestPassword` | (prompt) | Mai hard-codare | | `-GuestPassword` | (prompt) | Mai hard-codare |
| `-ActRunnerExe` | `<CIRoot>\act_runner\act_runner.exe` | Path binario runner | | `-ActRunnerExe` | `<CIRoot>\act_runner\act_runner.exe` | Path binario runner |
| `-ActRunnerConfigYaml` | `<repo>\runner\config.yaml` | Source del config da copiare | | `-ActRunnerConfigYaml` | `<repo>\runner\config.yaml` | Source del config da copiare |
| `-GiteaUrl` | `http://10.10.20.11:3100` | URL Gitea per registrazione | | `-GiteaUrl` | `http://10.10.20.11:3100` | URL Gitea per registrazione |
| `-GiteaRunnerToken` | (vuoto) | Token registrazione (Admin → Runners) | | `-GiteaRunnerToken` | (vuoto) | Token registrazione (Admin → Runners) |
| `-SkipRunnerInstall` | `$false` | Salta installazione servizio | | `-SkipRunnerInstall` | `$false` | Salta installazione servizio |
| `-SkipSSHConfig` | `$false` | Salta scrittura SSH alias | | `-SkipSSHConfig` | `$false` | Salta scrittura SSH alias |
| `-GiteaSSHHost` | `10.10.20.11` | Hostname SSH Gitea | | `-GiteaSSHHost` | `10.10.20.11` | Hostname SSH Gitea |
| `-GiteaSSHPort` | `2222` | Porta SSH Gitea | | `-GiteaSSHPort` | `2222` | Porta SSH Gitea |
--- ---
@@ -158,7 +158,7 @@ Allo `Setup-Host.ps1` exit 0:
| act_runner config | `F:\CI\act_runner\config.yaml` | | act_runner config | `F:\CI\act_runner\config.yaml` |
| act_runner logs | `F:\CI\act_runner\logs\` (stdout.log, stderr.log) | | act_runner logs | `F:\CI\act_runner\logs\` (stdout.log, stderr.log) |
| Template VMX (Windows) | `F:\CI\Templates\WinBuild2025\WinBuild2025.vmx` | | Template VMX (Windows) | `F:\CI\Templates\WinBuild2025\WinBuild2025.vmx` |
| Template VMX (Linux) | `F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx` | | Template VMX (Linux) | `F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx` |
| Snapshot name (Windows) | `BaseClean` | | Snapshot name (Windows) | `BaseClean` |
| Snapshot name (Linux) | `BaseClean-Linux` | | Snapshot name (Linux) | `BaseClean-Linux` |
| SSH key (Linux VMs) | `F:\CI\keys\ci_linux` (privata), `F:\CI\keys\ci_linux.pub` | | SSH key (Linux VMs) | `F:\CI\keys\ci_linux` (privata), `F:\CI\keys\ci_linux.pub` |
@@ -188,11 +188,11 @@ Task schedulati (vedi `scripts/Register-CIScheduledTasks.ps1` per il bootstrap):
## Troubleshooting ## Troubleshooting
| Sintomo | Diagnosi / Fix | | Sintomo | Diagnosi / Fix |
| --------------------------------------- | -------------------------------------------------------------------- | | ------------------------------- | ---------------------------------------------------------------- |
| `vmrun.exe NOT found` | Installa VMware Workstation Pro, riesegui | | `vmrun.exe NOT found` | Installa VMware Workstation Pro, riesegui |
| `NSSM not available` | Install manuale da https://nssm.cc, aggiungi a PATH, riesegui | | `NSSM not available` | Install manuale da https://nssm.cc, aggiungi a PATH, riesegui |
| Runner registration `exit != 0` | Verifica token Gitea + URL raggiungibile da host | | Runner registration `exit != 0` | Verifica token Gitea + URL raggiungibile da host |
| Service `act_runner` non parte | Check `F:\CI\act_runner\logs\stderr.log` | | Service `act_runner` non parte | Check `F:\CI\act_runner\logs\stderr.log` |
| `New-StoredCredential` fail | Verifica modulo CredentialManager importato + scope corretto | | `New-StoredCredential` fail | Verifica modulo CredentialManager importato + scope corretto |
| Job CI fallisce su `Test-WSMan` | TrustedHosts host non include subnet VM, AllowUnencrypted=$false | | Job CI fallisce su `Test-WSMan` | TrustedHosts host non include subnet VM, AllowUnencrypted=$false |
+7 -7
View File
@@ -7,12 +7,12 @@
## Architettura: tre script + modulo transport ## Architettura: tre script + modulo transport
| Script / Modulo | Dove gira | Ruolo | | Script / Modulo | Dove gira | Ruolo |
| ------------------------------------- | ---------------- | --------------------------------------------------------------------------- | | ------------------------------------------- | ---------------- | --------------------------------------------------------------------------- |
| `template/Deploy-LinuxBuild2404.ps1` | **Host** (PS) | Crea VM da cloud image VMDK, genera seed ISO cloud-init, avvia, aspetta SSH | | `template/Deploy-LinuxBuild2404.ps1` | **Host** (PS) | Crea VM da cloud image VMDK, genera seed ISO cloud-init, avvia, aspetta SSH |
| `template/Prepare-LinuxBuild2404.ps1` | **Host** (PS) | Copia + esegue setup via SSH, valida stato, prende snapshot | | `template/Prepare-LinuxBuild2404.ps1` | **Host** (PS) | Copia + esegue setup via SSH, valida stato, prende snapshot |
| `template/Install-CIToolchain-Linux2404.sh` | **Guest** (Bash) | Installa toolchain CI, dirs, hardening, gate finale | | `template/Install-CIToolchain-Linux2404.sh` | **Guest** (Bash) | Installa toolchain CI, dirs, hardening, gate finale |
| `scripts/_Transport.psm1` | **Host** (PS) | Funzioni SSH-only per il branch Linux (WinRM esistente invariato per ora) | | `scripts/_Transport.psm1` | **Host** (PS) | Funzioni SSH-only per il branch Linux (WinRM esistente invariato per ora) |
Perche tre script separati (non tutto-in-uno): cloud-init copre solo il bootstrap OS Perche tre script separati (non tutto-in-uno): cloud-init copre solo il bootstrap OS
(utente, SSH key, pacchetti base). Il toolchain CI e le validazioni per step sono piu (utente, SSH key, pacchetti base). Il toolchain CI e le validazioni per step sono piu
@@ -26,7 +26,7 @@ Deploy/Setup/Prepare di Windows.
| Parametro | Valore | | Parametro | Valore |
| ------------- | ---------------------------------------------------- | | ------------- | ---------------------------------------------------- |
| OS | Ubuntu 24.04 LTS (cloud image, non ISO installer) | | OS | Ubuntu 24.04 LTS (cloud image, non ISO installer) |
| Immagine base | `noble-server-cloudimg-amd64.vmdk` | | Immagine base | `noble-server-cloudimg-amd64.vmdk` |
| Download | `https://cloud-images.ubuntu.com/noble/current/` | | Download | `https://cloud-images.ubuntu.com/noble/current/` |
| vCPU | 4 | | vCPU | 4 |
| RAM | 4096 MB | | RAM | 4096 MB |
+10 -10
View File
@@ -200,16 +200,16 @@ Estimated time: 2-4 hours including Windows Update.
## Quick Reference ## Quick Reference
| Symptom | First command | | Symptom | First command |
| ------------------------------ | ---------------------------------------------------------------------- | | ------------------- | ------------------------------------------------------------------ |
| Runner offline | `Get-Service act_runner`, then `Restart-Service act_runner` | | Runner offline | `Get-Service act_runner`, then `Restart-Service act_runner` |
| Phase 2 clone fails | `Test-Path F:\CI\Templates\WinBuild2025\WinBuild2025.vmx` | | Phase 2 clone fails | `Test-Path F:\CI\Templates\WinBuild2025\WinBuild2025.vmx` |
| Disk full | `Get-PSDrive F \| Select Free`; run `Invoke-RetentionPolicy.ps1` | | Disk full | `Get-PSDrive F \| Select Free`; run `Invoke-RetentionPolicy.ps1` |
| Stale lock | `Remove-Item F:\CI\State\vm-start.lock` | | Stale lock | `Remove-Item F:\CI\State\vm-start.lock` |
| Slow builds | Check `invoke-ci.jsonl` phase timestamps; check disk I/O | | Slow builds | Check `invoke-ci.jsonl` phase timestamps; check disk I/O |
| Template corrupt | Remove `*.lck` files; if persistent, restore from `F:\CI\Backups\` | | Template corrupt | Remove `*.lck` files; if persistent, restore from `F:\CI\Backups\` |
| Snapshot missing | `vmrun listSnapshots <vmx>`; update `GITEA_CI_SNAPSHOT_NAME` | | Snapshot missing | `vmrun listSnapshots <vmx>`; update `GITEA_CI_SNAPSHOT_NAME` |
| IP collision | `Remove-Item F:\CI\State\ip-leases\*.lease`; lower `capacity` | | IP collision | `Remove-Item F:\CI\State\ip-leases\*.lease`; lower `capacity` |
--- ---
+1 -1
View File
@@ -12,7 +12,7 @@ Organized by sprint area with pre-requisites, test steps, and pass/fail criteria
| **Sprint 2** (Reliability) | 2.1/2.2/2.3/2.5 | Partial | §2.2/§2.3 validated locally 2026-05-10; §2.1/§2.5 need real VMs | | **Sprint 2** (Reliability) | 2.1/2.2/2.3/2.5 | Partial | §2.2/§2.3 validated locally 2026-05-10; §2.1/§2.5 need real VMs |
| **Sprint 3** (Observability) | 4.1/4.3/4.4 | Partial | §4.3/§4.4 validated locally 2026-05-10; §4.1 (JSONL) needs real build job | | **Sprint 3** (Observability) | 4.1/4.3/4.4 | Partial | §4.3/§4.4 validated locally 2026-05-10; §4.1 (JSONL) needs real build job |
| **Sprint 4-6** (Quality/Perf) | 1.4/3.1/3.6/5.2/5.3/5.4 | Partial | §1.4/§5.2/§5.3/§5.4 validated 2026-05-10; §3.1/§3.6 need real VMs | | **Sprint 4-6** (Quality/Perf) | 1.4/3.1/3.6/5.2/5.3/5.4 | Partial | §1.4/§5.2/§5.3/§5.4 validated 2026-05-10; §3.1/§3.6 need real VMs |
| **Sprint 7** (Testing) | 5.1 | [x] Done | 22/22 Pester tests passing in 12.9s (re-validated 2026-05-11) | | **Sprint 7** (Testing) | 5.1 | [x] Done | 22/22 Pester tests passing in 12.9s (re-validated 2026-05-11) |
| **§1.6** (Docs) | Threat model | [x] Done | BEST-PRACTICES.md verified 2026-05-10 | | **§1.6** (Docs) | Threat model | [x] Done | BEST-PRACTICES.md verified 2026-05-10 |
| **§3.2** (Perf) | 7-Zip compression | Partial | Fallback path validated; in-VM 7-Zip speed test needs real VM | | **§3.2** (Perf) | 7-Zip compression | Partial | Fallback path validated; in-VM 7-Zip speed test needs real VM |
| **§5.4** (PSScriptAnalyzer) | 0 errors, 298 warnings | [x] Done | All 6 actionable warnings fixed 2026-05-11; 0 Error severity violations | | **§5.4** (PSScriptAnalyzer) | 0 errors, 298 warnings | [x] Done | All 6 actionable warnings fixed 2026-05-11; 0 Error severity violations |
+19 -19
View File
@@ -11,16 +11,16 @@ credenziali archiviate, ISO Windows Server presente).
## Architettura: tre script ## Architettura: tre script
| Script | Dove gira | Scopo | | Script | Dove gira | Scopo |
| ----------------------------------- | ------------- | -------------------------------------------------------------------- | | ----------------------------------------------- | ------------- | -------------------------------------------------------------------- |
| `template/Deploy-WinBuild2025.ps1` | **Host** | Opzionale: crea VM e installa Windows Server 2025 unattended da ISO | | `template/Deploy-WinBuild2025.ps1` | **Host** | Opzionale: crea VM e installa Windows Server 2025 unattended da ISO |
| `template/Prepare-WinBuild2025.ps1` | **Host** | Orchestratore: copia + esegue Setup nel guest via WinRM (2025) | | `template/Prepare-WinBuild2025.ps1` | **Host** | Orchestratore: copia + esegue Setup nel guest via WinRM (2025) |
| `template/Install-CIToolchain-WinBuild2025.ps1` | **Dentro VM** | CI toolchain (user, .NET, Python, VS) + validazione hardening Deploy | | `template/Install-CIToolchain-WinBuild2025.ps1` | **Dentro VM** | CI toolchain (user, .NET, Python, VS) + validazione hardening Deploy |
| `template/Deploy-WinBuild2022.ps1` | **Host** | Opzionale: crea VM e installa Windows Server 2022 unattended da ISO | | `template/Deploy-WinBuild2022.ps1` | **Host** | Opzionale: crea VM e installa Windows Server 2022 unattended da ISO |
| `template/Prepare-WinBuild2022.ps1` | **Host** | Orchestratore: copia + esegue Setup nel guest via WinRM (2022) | | `template/Prepare-WinBuild2022.ps1` | **Host** | Orchestratore: copia + esegue Setup nel guest via WinRM (2022) |
| `template/Install-CIToolchain-WinBuild2022.ps1` | **Dentro VM** | CI toolchain per Windows Server 2022 (stesso flusso del 2025) | | `template/Install-CIToolchain-WinBuild2022.ps1` | **Dentro VM** | CI toolchain per Windows Server 2022 (stesso flusso del 2025) |
| `template/Validate-DeployState.ps1` | **Host** | Valida stato post-Deploy prima di eseguire Prepare (2025 e 2022) | | `template/Validate-DeployState.ps1` | **Host** | Valida stato post-Deploy prima di eseguire Prepare (2025 e 2022) |
| `template/Validate-SetupState.ps1` | **Host** | Valida stato post-Setup (Deploy + Setup) prima dello snapshot | | `template/Validate-SetupState.ps1` | **Host** | Valida stato post-Setup (Deploy + Setup) prima dello snapshot |
**Confine Deploy / Setup** (refactor §7, 2026-05-10): **Confine Deploy / Setup** (refactor §7, 2026-05-10):
- `Deploy-WinBuild2025.ps1` si occupa dell'**OS hardening** (Firewall, WinRM, UAC, Defender, UX tweaks, autologin Administrator, WU GPO locks). Se usato, Setup valida questi come Assert-Step senza re-applicarli. - `Deploy-WinBuild2025.ps1` si occupa dell'**OS hardening** (Firewall, WinRM, UAC, Defender, UX tweaks, autologin Administrator, WU GPO locks). Se usato, Setup valida questi come Assert-Step senza re-applicarli.
@@ -145,7 +145,7 @@ Ogni step ha validazione `Assert-Step` (throw on failure, `[OK]` su pass):
| `-BuildPassword` | (prompt) | Password per `ci_build` — mai hard-codare | | `-BuildPassword` | (prompt) | Password per `ci_build` — mai hard-codare |
| `-BuildUsername` | ci_build | Account CI dentro la VM | | `-BuildUsername` | ci_build | Account CI dentro la VM |
| `-DotNetSdkVersion` | 10.0 | Channel .NET SDK | | `-DotNetSdkVersion` | 10.0 | Channel .NET SDK |
| `-SkipWindowsUpdate` | (off) | Pass-through a Install-CIToolchain-WinBuild2025.ps1 | | `-SkipWindowsUpdate` | (off) | Pass-through a Install-CIToolchain-WinBuild2025.ps1 |
| `-StoreCredential` | (off) | Registra `BuildUsername`/`BuildPassword` in Windows Credential Manager | | `-StoreCredential` | (off) | Registra `BuildUsername`/`BuildPassword` in Windows Credential Manager |
| `-CredentialTarget` | BuildVMGuest | Target Credential Manager (deve corrispondere a quanto usato da Invoke-CIJob) | | `-CredentialTarget` | BuildVMGuest | Target Credential Manager (deve corrispondere a quanto usato da Invoke-CIJob) |
@@ -292,15 +292,15 @@ toolchain (.NET, VS Build Tools, Python).
## Troubleshooting ## Troubleshooting
| Sintomo | Diagnosi / Fix | | Sintomo | Diagnosi / Fix |
| ---------------------------------------------- | --------------------------------------------------------------------------------------------------------- | | ------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------- |
| `Cannot reach $VMIPAddress via WinRM` | VM non avviata, WinRM non abilitato, IP errato — verifica con ipconfig | | `Cannot reach $VMIPAddress via WinRM` | VM non avviata, WinRM non abilitato, IP errato — verifica con ipconfig |
| `Install-CIToolchain-WinBuild2025.ps1 exited with code 3010` | Reboot richiesto post-WU. Re-run con `-SkipWindowsUpdate` | | `Install-CIToolchain-WinBuild2025.ps1 exited with code 3010` | Reboot richiesto post-WU. Re-run con `-SkipWindowsUpdate` |
| `[Defender] Validation failed: GPO key` | Defender riattivato da Windows Update — disabilita via gpedit + reboot | | `[Defender] Validation failed: GPO key` | Defender riattivato da Windows Update — disabilita via gpedit + reboot |
| `VS Build Tools installation timed out` | Network slow o cache corrotta. Re-run con cache pulita (`C:\ProgramData\Microsoft\VisualStudio\Packages`) | | `VS Build Tools installation timed out` | Network slow o cache corrotta. Re-run con cache pulita (`C:\ProgramData\Microsoft\VisualStudio\Packages`) |
| `Python version match` fail | `$PythonVersion` ≠ versione installata. Aggiorna param o reinstalla | | `Python version match` fail | `$PythonVersion` ≠ versione installata. Aggiorna param o reinstalla |
| Post-setup `MSBuild not found` | VS install fallita silenziosa. Check `C:\CI\vs_log.txt` | | Post-setup `MSBuild not found` | VS install fallita silenziosa. Check `C:\CI\vs_log.txt` |
| Pre-snapshot Final check fail | Stato VM rotto — non prendere snapshot. Re-run o ricomincia da zero | | Pre-snapshot Final check fail | Stato VM rotto — non prendere snapshot. Re-run o ricomincia da zero |
--- ---
+87 -80
View File
@@ -8,23 +8,30 @@
## Table of Contents ## Table of Contents
1. [System Overview](#1-system-overview) - [Workflow Authoring Reference](#workflow-authoring-reference)
2. [Runner Labels](#2-runner-labels) - [Table of Contents](#table-of-contents)
3. [Shell Requirement](#3-shell-requirement) - [1. System Overview](#1-system-overview)
4. [Environment Variables (Injected by Runner)](#4-environment-variables-injected-by-runner) - [2. Runner Labels](#2-runner-labels)
5. [Invoke-CIJob.ps1 Parameter Reference](#5-invoke-cijobps1-parameter-reference) - [3. Shell Requirement](#3-shell-requirement)
6. [URL Conventions](#6-url-conventions) - [4. Environment Variables (Injected by Runner)](#4-environment-variables-injected-by-runner)
7. [Artifact Path Convention](#7-artifact-path-convention) - [5. Invoke-CIJob.ps1 Parameter Reference](#5-invoke-cijobps1-parameter-reference)
8. [Workflow Patterns](#8-workflow-patterns) - [Mandatory parameters](#mandatory-parameters)
- [8.1 Windows build (host-clone mode)](#81-windows-build-host-clone-mode) - [Optional parameters](#optional-parameters)
- [8.2 Linux build (host-clone mode)](#82-linux-build-host-clone-mode) - [6. URL Conventions](#6-url-conventions)
- [8.3 Windows build (UseGitClone mode)](#83-windows-build-usegitclone-mode) - [Host-clone mode (default, no `-UseGitClone`)](#host-clone-mode-default-no--usegitclone)
- [8.4 Linux build (UseGitClone mode)](#84-linux-build-usegitclone-mode) - [UseGitClone mode (`-UseGitClone`)](#usegitclone-mode--usegitclone)
- [8.5 PSScriptAnalyzer lint](#85-psscriptanalyzer-lint) - [Quick reference](#quick-reference)
- [8.6 Matrix build (multiple configs)](#86-matrix-build-multiple-configs) - [7. Artifact Path Convention](#7-artifact-path-convention)
9. [Checkout Step](#9-checkout-step) - [8. Workflow Patterns](#8-workflow-patterns)
10. [Timeouts](#10-timeouts) - [8.1 Windows build (host-clone mode)](#81-windows-build-host-clone-mode)
11. [Common Mistakes](#11-common-mistakes) - [8.2 Linux build (host-clone mode)](#82-linux-build-host-clone-mode)
- [8.3 Windows build (UseGitClone mode)](#83-windows-build-usegitclone-mode)
- [8.4 Linux build (UseGitClone mode)](#84-linux-build-usegitclone-mode)
- [8.5 PSScriptAnalyzer lint](#85-psscriptanalyzer-lint)
- [8.6 Matrix build (multiple configs)](#86-matrix-build-multiple-configs)
- [9. Checkout Step](#9-checkout-step)
- [10. Timeouts](#10-timeouts)
- [11. Common Mistakes](#11-common-mistakes)
--- ---
@@ -50,12 +57,12 @@ Supported guest OS: Windows Server 2025 / 2022 (WinRM transport), Ubuntu 24.04 (
## 2. Runner Labels ## 2. Runner Labels
| Label | Configured as | Use for | | Label | Configured as | Use for |
| ---------------- | ---------------- | ----------------------------------- | | --------------- | -------------------- | ------------------------------------------ |
| `windows-build` | `windows-build:host` | Windows VM builds, Windows-only tools | | `windows-build` | `windows-build:host` | Windows VM builds, Windows-only tools |
| `linux-build` | `linux-build:host` | Linux VM builds (cross-compile, GCC/Clang) | | `linux-build` | `linux-build:host` | Linux VM builds (cross-compile, GCC/Clang) |
| `dotnet` | `dotnet:host` | Alias for windows-build (legacy) | | `dotnet` | `dotnet:host` | Alias for windows-build (legacy) |
| `msbuild` | `msbuild:host` | Alias for windows-build (legacy) | | `msbuild` | `msbuild:host` | Alias for windows-build (legacy) |
Both `windows-build` and `linux-build` run on the same physical host. Only the Both `windows-build` and `linux-build` run on the same physical host. Only the
template VM used differs. Use `windows-build` unless you specifically need a Linux template VM used differs. Use `windows-build` unless you specifically need a Linux
@@ -91,14 +98,14 @@ required runtime and may not be present on the host.
These variables are automatically available in every job step. Do not redeclare them These variables are automatically available in every job step. Do not redeclare them
in the workflow unless you need to override the default. in the workflow unless you need to override the default.
| Variable | Value (default) | Description | | Variable | Value (default) | Description |
| ---------------------------- | ---------------------------------------------------- | --------------------------------------- | | ------------------------------ | --------------------------------------------------- | -------------------------------------- |
| `GITEA_CI_TEMPLATE_PATH` | `F:\CI\Templates\WinBuild2025\WinBuild2025.vmx` | Windows 2025 template VMX path | | `GITEA_CI_TEMPLATE_PATH` | `F:\CI\Templates\WinBuild2025\WinBuild2025.vmx` | Windows 2025 template VMX path |
| `GITEA_CI_LINUX_TEMPLATE_PATH` | `F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx` | Ubuntu 24.04 template VMX path | | `GITEA_CI_LINUX_TEMPLATE_PATH` | `F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx` | Ubuntu 24.04 template VMX path |
| `GITEA_CI_CLONE_BASE_DIR` | `F:\CI\BuildVMs` | Directory for ephemeral VM clones | | `GITEA_CI_CLONE_BASE_DIR` | `F:\CI\BuildVMs` | Directory for ephemeral VM clones |
| `GITEA_CI_ARTIFACT_DIR` | `F:\CI\Artifacts` | Root directory for job artifacts | | `GITEA_CI_ARTIFACT_DIR` | `F:\CI\Artifacts` | Root directory for job artifacts |
| `GITEA_CI_GUEST_CRED_TARGET` | `BuildVMGuest` | Credential Manager target for guest VM | | `GITEA_CI_GUEST_CRED_TARGET` | `BuildVMGuest` | Credential Manager target for guest VM |
| `GITEA_CI_SSH_KEY_PATH` | `F:\CI\keys\ci_linux` | SSH private key for Linux guest access | | `GITEA_CI_SSH_KEY_PATH` | `F:\CI\keys\ci_linux` | SSH private key for Linux guest access |
Invoke-CIJob.ps1 reads `GITEA_CI_TEMPLATE_PATH` and `GITEA_CI_CLONE_BASE_DIR` Invoke-CIJob.ps1 reads `GITEA_CI_TEMPLATE_PATH` and `GITEA_CI_CLONE_BASE_DIR`
automatically if `-TemplatePath` and `-CloneBaseDir` are not passed explicitly. automatically if `-TemplatePath` and `-CloneBaseDir` are not passed explicitly.
@@ -111,33 +118,33 @@ Script location (fixed on host): `N:\Code\Workspace\Local-CI-CD-System\scripts\I
### Mandatory parameters ### Mandatory parameters
| Parameter | Type | Description | | Parameter | Type | Description |
| ----------- | ------ | --------------------------------------------------------------- | | ---------- | ------ | ------------------------------------------------------------------ |
| `-JobId` | string | Unique job ID. Use `${{ github.run_id }}` or `run_id-run_attempt`. | | `-JobId` | string | Unique job ID. Use `${{ github.run_id }}` or `run_id-run_attempt`. |
| `-RepoUrl` | string | Git URL of the repository to clone/build. See Section 6. | | `-RepoUrl` | string | Git URL of the repository to clone/build. See Section 6. |
| `-Branch` | string | Branch to build. Use `${{ github.ref_name }}`. | | `-Branch` | string | Branch to build. Use `${{ github.ref_name }}`. |
### Optional parameters ### Optional parameters
| Parameter | Type | Default | Description | | Parameter | Type | Default | Description |
| ------------------------ | ------ | --------------------------- | -------------------------------------------------------------- | | ------------------------ | ------ | ------------------------------ | ---------------------------------------------------------------- |
| `-Commit` | string | `''` | Specific commit SHA. Use `${{ github.sha }}`. Empty = HEAD. | | `-Commit` | string | `''` | Specific commit SHA. Use `${{ github.sha }}`. Empty = HEAD. |
| `-TemplatePath` | string | `$env:GITEA_CI_TEMPLATE_PATH` | Full path to template VMX. | | `-TemplatePath` | string | `$env:GITEA_CI_TEMPLATE_PATH` | Full path to template VMX. |
| `-SnapshotName` | string | `BaseClean` | Template snapshot name to clone from. | | `-SnapshotName` | string | `BaseClean` | Template snapshot name to clone from. |
| `-GuestOS` | string | `Auto` | `Windows`, `Linux`, or `Auto` (detected from VMX guestOS field). | | `-GuestOS` | string | `Auto` | `Windows`, `Linux`, or `Auto` (detected from VMX guestOS field). |
| `-BuildCommand` | string | `''` | Shell command to run inside VM. Empty = `dotnet build`. | | `-BuildCommand` | string | `''` | Shell command to run inside VM. Empty = `dotnet build`. |
| `-GuestArtifactSource` | string | `dist` | Path inside VM guest from which artifacts are collected. | | `-GuestArtifactSource` | string | `dist` | Path inside VM guest from which artifacts are collected. |
| `-Submodules` | switch | off | Pass to clone with `--recurse-submodules`. | | `-Submodules` | switch | off | Pass to clone with `--recurse-submodules`. |
| `-UseGitClone` | switch | off | Skip host-side clone; let the guest VM clone directly via HTTPS. | | `-UseGitClone` | switch | off | Skip host-side clone; let the guest VM clone directly via HTTPS. |
| `-GiteaCredentialTarget` | string | `GiteaPAT` | Credential Manager target for Gitea PAT (UseGitClone only). | | `-GiteaCredentialTarget` | string | `GiteaPAT` | Credential Manager target for Gitea PAT (UseGitClone only). |
| `-GuestCredentialTarget` | string | `BuildVMGuest` | Credential Manager target for Windows guest VM login. | | `-GuestCredentialTarget` | string | `BuildVMGuest` | Credential Manager target for Windows guest VM login. |
| `-SshKeyPath` | string | `F:\CI\keys\ci_linux` | SSH key for Linux guest (ignored for Windows). | | `-SshKeyPath` | string | `F:\CI\keys\ci_linux` | SSH key for Linux guest (ignored for Windows). |
| `-SshUser` | string | `ci_build` | SSH username for Linux guest (ignored for Windows). | | `-SshUser` | string | `ci_build` | SSH username for Linux guest (ignored for Windows). |
| `-CloneBaseDir` | string | `$env:GITEA_CI_CLONE_BASE_DIR` | Directory for VM clone files. | | `-CloneBaseDir` | string | `$env:GITEA_CI_CLONE_BASE_DIR` | Directory for VM clone files. |
| `-ArtifactBaseDir` | string | `F:\CI\Artifacts` | Root artifact directory on host. | | `-ArtifactBaseDir` | string | `F:\CI\Artifacts` | Root artifact directory on host. |
| `-VMIPAddress` | string | `''` | Override guest IP. Empty = auto-detected via vmrun. | | `-VMIPAddress` | string | `''` | Override guest IP. Empty = auto-detected via vmrun. |
| `-LogDir` | string | `F:\CI\Logs` | Directory for per-job transcripts and JSONL logs. | | `-LogDir` | string | `F:\CI\Logs` | Directory for per-job transcripts and JSONL logs. |
| `-LogRetentionDays` | int | `30` | Days before log directories are purged. `0` = disabled. | | `-LogRetentionDays` | int | `30` | Days before log directories are purged. `0` = disabled. |
Exit codes: `0` = success, `1` = failure (VM is always destroyed regardless). Exit codes: `0` = success, `1` = failure (VM is always destroyed regardless).
@@ -173,11 +180,11 @@ https://gitea.emulab.it/<owner>/<repo>.git
### Quick reference ### Quick reference
| Mode | RepoUrl to use | | Mode | RepoUrl to use |
| ----------------- | ---------------------------------------------------------- | | ----------------- | -------------------------------------------- |
| Default (Windows) | `ssh://gitea-ci/<owner>/<repo>.git` | | Default (Windows) | `ssh://gitea-ci/<owner>/<repo>.git` |
| Default (Linux) | `ssh://gitea-ci/<owner>/<repo>.git` | | Default (Linux) | `ssh://gitea-ci/<owner>/<repo>.git` |
| UseGitClone | `https://gitea.emulab.it/<owner>/<repo>.git` | | UseGitClone | `https://gitea.emulab.it/<owner>/<repo>.git` |
--- ---
@@ -537,13 +544,13 @@ The CI scripts are at a fixed path on the runner host and do not need a checkout
## 10. Timeouts ## 10. Timeouts
| Build type | Recommended `timeout-minutes` | | Build type | Recommended `timeout-minutes` |
| --------------------------- | ----------------------------- | | -------------------------- | ----------------------------- |
| Windows build (typical) | 90 | | Windows build (typical) | 90 |
| Windows build (large/slow) | 120 | | Windows build (large/slow) | 120 |
| Linux build (typical) | 60 | | Linux build (typical) | 60 |
| Lint / static analysis | 10 | | Lint / static analysis | 10 |
| Template provisioning | 180 | | Template provisioning | 180 |
The runner-level timeout is `2h` (from `runner/config.yaml`). Keep job timeouts The runner-level timeout is `2h` (from `runner/config.yaml`). Keep job timeouts
below that value. If a job timeout fires, the VM may not be cleanly destroyed — below that value. If a job timeout fires, the VM may not be cleanly destroyed —
@@ -553,16 +560,16 @@ the cleanup task `Cleanup-OrphanedBuildVMs.ps1` handles these cases.
## 11. Common Mistakes ## 11. Common Mistakes
| Mistake | Correct approach | | Mistake | Correct approach |
| ------- | ---------------- | | ---------------------------------------------------------------- | -------------------------------------------------------------------------- |
| `shell: pwsh` | Use `shell: powershell` (PS 5.1, not Core) | | `shell: pwsh` | Use `shell: powershell` (PS 5.1, not Core) |
| SSH alias URL with `-UseGitClone` | Use `https://gitea.emulab.it/...` for UseGitClone; SSH alias is host-only | | SSH alias URL with `-UseGitClone` | Use `https://gitea.emulab.it/...` for UseGitClone; SSH alias is host-only |
| HTTPS URL without `-UseGitClone` | SSH alias `ssh://gitea-ci/...` for host-clone mode | | HTTPS URL without `-UseGitClone` | SSH alias `ssh://gitea-ci/...` for host-clone mode |
| `$env:GITHUB_WORKSPACE` to find CI scripts | Use hardcoded `N:\Code\Workspace\Local-CI-CD-System\scripts\` | | `$env:GITHUB_WORKSPACE` to find CI scripts | Use hardcoded `N:\Code\Workspace\Local-CI-CD-System\scripts\` |
| `actions/checkout@v4` in build jobs | Omit it; source is handled by Invoke-CIJob.ps1 | | `actions/checkout@v4` in build jobs | Omit it; source is handled by Invoke-CIJob.ps1 |
| `runs-on: ubuntu-latest` or `windows-latest` | Use `windows-build` or `linux-build` — cloud runners are not available | | `runs-on: ubuntu-latest` or `windows-latest` | Use `windows-build` or `linux-build` — cloud runners are not available |
| `&&` in PowerShell run blocks | Not valid in PS 5.1; use `if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }` | | `&&` in PowerShell run blocks | Not valid in PS 5.1; use `if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }` |
| Hardcoded IP in `-VMIPAddress` | Omit it; auto-detected via `vmrun getGuestIPAddress` | | Hardcoded IP in `-VMIPAddress` | Omit it; auto-detected via `vmrun getGuestIPAddress` |
| `-TemplatePath` for Linux without `GITEA_CI_LINUX_TEMPLATE_PATH` | Pass `$env:GITEA_CI_LINUX_TEMPLATE_PATH` or the full path explicitly | | `-TemplatePath` for Linux without `GITEA_CI_LINUX_TEMPLATE_PATH` | Pass `$env:GITEA_CI_LINUX_TEMPLATE_PATH` or the full path explicitly |
| Forgetting `-SnapshotName 'BaseClean-Linux'` for Linux | Linux template uses a different snapshot name than Windows (`BaseClean`) | | Forgetting `-SnapshotName 'BaseClean-Linux'` for Linux | Linux template uses a different snapshot name than Windows (`BaseClean`) |
| Same `-JobId` for matrix jobs | Append matrix key: `${{ github.run_id }}-${{ matrix.config }}` | | Same `-JobId` for matrix jobs | Append matrix key: `${{ github.run_id }}-${{ matrix.config }}` |
+12 -12
View File
@@ -24,19 +24,19 @@ Top 3 risks today, in order: (1) the Linux matrix leg builds against the Windows
The optimistic [TODO.md](../TODO.md) and the conservative [docs/TEST-PLAN-v1.3-to-HEAD.md](../docs/TEST-PLAN-v1.3-to-HEAD.md) disagree. The honest state, reconciled against the source files, is below. The optimistic [TODO.md](../TODO.md) and the conservative [docs/TEST-PLAN-v1.3-to-HEAD.md](../docs/TEST-PLAN-v1.3-to-HEAD.md) disagree. The honest state, reconciled against the source files, is below.
| Area | Genuinely Done | Partially Done | Unvalidated / Broken | | Area | Genuinely Done | Partially Done | Unvalidated / Broken |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| Windows VM lifecycle | Clone, start, IP detect, WinRM HTTPS, build, artifacts, destroy ([scripts/Invoke-CIJob.ps1](../scripts/Invoke-CIJob.ps1), [scripts/New-BuildVM.ps1](../scripts/New-BuildVM.ps1), [scripts/Wait-VMReady.ps1](../scripts/Wait-VMReady.ps1), [scripts/Invoke-RemoteBuild.ps1](../scripts/Invoke-RemoteBuild.ps1), [scripts/Get-BuildArtifacts.ps1](../scripts/Get-BuildArtifacts.ps1), [scripts/Remove-BuildVM.ps1](../scripts/Remove-BuildVM.ps1)) | — | Real 4-way concurrency | | Windows VM lifecycle | Clone, start, IP detect, WinRM HTTPS, build, artifacts, destroy ([scripts/Invoke-CIJob.ps1](../scripts/Invoke-CIJob.ps1), [scripts/New-BuildVM.ps1](../scripts/New-BuildVM.ps1), [scripts/Wait-VMReady.ps1](../scripts/Wait-VMReady.ps1), [scripts/Invoke-RemoteBuild.ps1](../scripts/Invoke-RemoteBuild.ps1), [scripts/Get-BuildArtifacts.ps1](../scripts/Get-BuildArtifacts.ps1), [scripts/Remove-BuildVM.ps1](../scripts/Remove-BuildVM.ps1)) | — | Real 4-way concurrency |
| Linux VM lifecycle | Cloud-init deploy, SSH transport, IP via `guestinfo.ci-ip` ([template/Deploy-LinuxBuild2404.ps1](../template/Deploy-LinuxBuild2404.ps1), [scripts/_Transport.psm1](../scripts/_Transport.psm1)) | Generic validator (Windows-only) ([template/Validate-DeployState.ps1](../template/Validate-DeployState.ps1)) | **FIXED 2026-05-12**: Matrix workflow Linux leg now picks correct template (C1) | | Linux VM lifecycle | Cloud-init deploy, SSH transport, IP via `guestinfo.ci-ip` ([template/Deploy-LinuxBuild2404.ps1](../template/Deploy-LinuxBuild2404.ps1), [scripts/_Transport.psm1](../scripts/_Transport.psm1)) | Generic validator (Windows-only) ([template/Validate-DeployState.ps1](../template/Validate-DeployState.ps1)) | **FIXED 2026-05-12**: Matrix workflow Linux leg now picks correct template (C1) |
| Composite action | Inputs forwarded via env vars, step outputs work, success and failure upload paths ([gitea/actions/local-ci-build/action.yml](../gitea/actions/local-ci-build/action.yml)) | — | **FIXED 2026-05-12**: `outputs:` block corrected (H2); hardcoded `N:\` replaced with env var (H11) | | Composite action | Inputs forwarded via env vars, step outputs work, success and failure upload paths ([gitea/actions/local-ci-build/action.yml](../gitea/actions/local-ci-build/action.yml)) | — | **FIXED 2026-05-12**: `outputs:` block corrected (H2); hardcoded `N:\` replaced with env var (H11) |
| Concurrency | File mutex + lease design ([scripts/Invoke-CIJob.ps1](../scripts/Invoke-CIJob.ps1) ~L303-L460) | **FIXED 2026-05-12**: Stale lock auto-cleanup added (H5) | 4-way burn-in never run | | Concurrency | File mutex + lease design ([scripts/Invoke-CIJob.ps1](../scripts/Invoke-CIJob.ps1) ~L303-L460) | **FIXED 2026-05-12**: Stale lock auto-cleanup added (H5) | 4-way burn-in never run |
| Credential handling | Windows Credential Manager target `BuildVMGuest`; PAT via Credential Manager target `GiteaPAT`; Windows Mode 2 uses `http.extraHeader` | — | **FIXED 2026-05-12**: Linux Mode 2 PAT now uses `http.extraHeader` (H3); `ExtraGuestEnv` logging redacted (C2) | | Credential handling | Windows Credential Manager target `BuildVMGuest`; PAT via Credential Manager target `GiteaPAT`; Windows Mode 2 uses `http.extraHeader` | — | **FIXED 2026-05-12**: Linux Mode 2 PAT now uses `http.extraHeader` (H3); `ExtraGuestEnv` logging redacted (C2) |
| Maintenance | Disk watcher, runner health watcher, retention, orphan cleanup, scheduled tasks ([scripts/Watch-DiskSpace.ps1](../scripts/Watch-DiskSpace.ps1), [scripts/Watch-RunnerHealth.ps1](../scripts/Watch-RunnerHealth.ps1), [scripts/Invoke-RetentionPolicy.ps1](../scripts/Invoke-RetentionPolicy.ps1), [scripts/Cleanup-OrphanedBuildVMs.ps1](../scripts/Cleanup-OrphanedBuildVMs.ps1), [scripts/Register-CIScheduledTasks.ps1](../scripts/Register-CIScheduledTasks.ps1)) | — | — | | Maintenance | Disk watcher, runner health watcher, retention, orphan cleanup, scheduled tasks ([scripts/Watch-DiskSpace.ps1](../scripts/Watch-DiskSpace.ps1), [scripts/Watch-RunnerHealth.ps1](../scripts/Watch-RunnerHealth.ps1), [scripts/Invoke-RetentionPolicy.ps1](../scripts/Invoke-RetentionPolicy.ps1), [scripts/Cleanup-OrphanedBuildVMs.ps1](../scripts/Cleanup-OrphanedBuildVMs.ps1), [scripts/Register-CIScheduledTasks.ps1](../scripts/Register-CIScheduledTasks.ps1)) | — | — |
| Backup | [scripts/Backup-CITemplate.ps1](../scripts/Backup-CITemplate.ps1) functional; **FIXED 2026-05-12**: default `WinBuild2025`, `-AllTemplates` switch added (H7) | — | — | | Backup | [scripts/Backup-CITemplate.ps1](../scripts/Backup-CITemplate.ps1) functional; **FIXED 2026-05-12**: default `WinBuild2025`, `-AllTemplates` switch added (H7) | — | — |
| Host bootstrap | Runner install, NSSM service, credential prompts ([Setup-Host.ps1](../Setup-Host.ps1)); **FIXED 2026-05-12**: directory array updated (H6); `F:\CI\Cache\pip` created on live host | — | act_runner runs as LocalSystem — H8 SSH alias mismatch confirmed, not yet fixed | | Host bootstrap | Runner install, NSSM service, credential prompts ([Setup-Host.ps1](../Setup-Host.ps1)); **FIXED 2026-05-12**: directory array updated (H6); `F:\CI\Cache\pip` created on live host | — | act_runner runs as LocalSystem — H8 SSH alias mismatch confirmed, not yet fixed |
| Observability | JSONL per-job events, Event Log, optional webhook | Phase-duration summary | Cross-job analysis tool | | Observability | JSONL per-job events, Event Log, optional webhook | Phase-duration summary | Cross-job analysis tool |
| Tests | Argument-parsing Pester suite over fake `vmrun.cmd` (4 files in [tests/](../tests/)) | — | Orchestrator state machine, real-VM smoke tests, lock concurrency | | Tests | Argument-parsing Pester suite over fake `vmrun.cmd` (4 files in [tests/](../tests/)) | — | Orchestrator state machine, real-VM smoke tests, lock concurrency |
| Documentation | [docs/ARCHITECTURE.md](../docs/ARCHITECTURE.md), [docs/CI-FLOW.md](../docs/CI-FLOW.md), [docs/RUNBOOK.md](../docs/RUNBOOK.md), [docs/BEST-PRACTICES.md](../docs/BEST-PRACTICES.md), [docs/WORKFLOW-AUTHORING.md](../docs/WORKFLOW-AUTHORING.md) | Drift: README claims production-ready; CI-FLOW claims partial-artifacts-on-failure; test plan uses PS7 syntax and wrong param names | Consolidated template-refresh runbook | | Documentation | [docs/ARCHITECTURE.md](../docs/ARCHITECTURE.md), [docs/CI-FLOW.md](../docs/CI-FLOW.md), [docs/RUNBOOK.md](../docs/RUNBOOK.md), [docs/BEST-PRACTICES.md](../docs/BEST-PRACTICES.md), [docs/WORKFLOW-AUTHORING.md](../docs/WORKFLOW-AUTHORING.md) | Drift: README claims production-ready; CI-FLOW claims partial-artifacts-on-failure; test plan uses PS7 syntax and wrong param names | Consolidated template-refresh runbook |
The README is genuinely ahead of the evidence. The accurate label is *feature-complete homelab CI awaiting stabilization pass*. Everything in this plan exists to close that gap. The README is genuinely ahead of the evidence. The accurate label is *feature-complete homelab CI awaiting stabilization pass*. Everything in this plan exists to close that gap.
+84 -84
View File
@@ -30,32 +30,32 @@ The rest of this document expands on these and 30+ smaller findings.
The system declares itself "production-ready" in `README.md` line 1. Measured against what a reasonable definition of that phrase requires, here is the state: The system declares itself "production-ready" in `README.md` line 1. Measured against what a reasonable definition of that phrase requires, here is the state:
| Capability | Status | Evidence | | Capability | Status | Evidence |
| --- | --- | --- | | ---------------------------------------------- | ------------ | ---------------------------------------------------------------------------------------- |
| Ephemeral VM lifecycle (clone, start, destroy) | Complete | `scripts/New-BuildVM.ps1`, `Remove-BuildVM.ps1`, `Invoke-CIJob.ps1` | | Ephemeral VM lifecycle (clone, start, destroy) | Complete | `scripts/New-BuildVM.ps1`, `Remove-BuildVM.ps1`, `Invoke-CIJob.ps1` |
| Windows guest (WinRM HTTPS) | Complete | `Invoke-RemoteBuild.ps1`, `Get-BuildArtifacts.ps1` Windows branch | | Windows guest (WinRM HTTPS) | Complete | `Invoke-RemoteBuild.ps1`, `Get-BuildArtifacts.ps1` Windows branch |
| Linux guest (SSH) | Complete | `_Transport.psm1`, Linux branches in build/artifact scripts | | Linux guest (SSH) | Complete | `_Transport.psm1`, Linux branches in build/artifact scripts |
| Auto-detect guest OS from VMX | Complete | `Invoke-CIJob.ps1` `guestOS` regex | | Auto-detect guest OS from VMX | Complete | `Invoke-CIJob.ps1` `guestOS` regex |
| Host-clone mode + zip transfer (Mode 1) | Complete | Default path in `Invoke-RemoteBuild.ps1` | | Host-clone mode + zip transfer (Mode 1) | Complete | Default path in `Invoke-RemoteBuild.ps1` |
| In-VM `git clone` (Mode 2) | Complete | `-UseGitClone`, PAT via `http.extraHeader` | | In-VM `git clone` (Mode 2) | Complete | `-UseGitClone`, PAT via `http.extraHeader` |
| Credential storage (CredentialManager) | Complete | `BuildVMGuest`, `GiteaPAT` | | Credential storage (CredentialManager) | Complete | `BuildVMGuest`, `GiteaPAT` |
| Reusable composite action | Complete | `gitea/actions/local-ci-build/action.yml` | | Reusable composite action | Complete | `gitea/actions/local-ci-build/action.yml` |
| Build matrix Windows + Linux | Complete | `gitea/workflows/build-nsInnoUnp.yml` | | Build matrix Windows + Linux | Complete | `gitea/workflows/build-nsInnoUnp.yml` |
| Shared NuGet/pip cache via HGFS | Complete | `Set-TemplateSharedFolders.ps1`, `-UseSharedCache` | | Shared NuGet/pip cache via HGFS | Complete | `Set-TemplateSharedFolders.ps1`, `-UseSharedCache` |
| Structured JSONL logs | Complete | `Write-JobEvent` in `Invoke-CIJob.ps1` | | Structured JSONL logs | Complete | `Write-JobEvent` in `Invoke-CIJob.ps1` |
| Scheduled maintenance | Complete | `Register-CIScheduledTasks.ps1` (4 tasks) | | Scheduled maintenance | Complete | `Register-CIScheduledTasks.ps1` (4 tasks) |
| Disk-space + runner-health watchdogs | Complete | `Watch-DiskSpace.ps1`, `Watch-RunnerHealth.ps1` | | Disk-space + runner-health watchdogs | Complete | `Watch-DiskSpace.ps1`, `Watch-RunnerHealth.ps1` |
| Retention policy with aggressive fallback | Complete | `Invoke-RetentionPolicy.ps1` | | Retention policy with aggressive fallback | Complete | `Invoke-RetentionPolicy.ps1` |
| Orphan cleanup | Complete | `Cleanup-OrphanedBuildVMs.ps1` | | Orphan cleanup | Complete | `Cleanup-OrphanedBuildVMs.ps1` |
| Template backup before refresh | Complete | `Backup-CITemplate.ps1` | | Template backup before refresh | Complete | `Backup-CITemplate.ps1` |
| Benchmark harness | Complete | `Measure-CIBenchmark.ps1` | | Benchmark harness | Complete | `Measure-CIBenchmark.ps1` |
| Secret injection into guest (`ExtraGuestEnv`) | Complete | Forwarded host → action → `Invoke-CIJob``Invoke-RemoteBuild` | | Secret injection into guest (`ExtraGuestEnv`) | Complete | Forwarded host → action → `Invoke-CIJob``Invoke-RemoteBuild` |
| Pester unit tests | Stub-level | `tests/*.Tests.ps1`, all use fake `vmrun.cmd` | | Pester unit tests | Stub-level | `tests/*.Tests.ps1`, all use fake `vmrun.cmd` |
| Automated integration test | **Missing** | No automated harness exercises real VMs | | Automated integration test | **Missing** | No automated harness exercises real VMs |
| Concurrency burn-in | **Missing** | `TODO.md §2.1` admits "race non riprodotta in e2e-008/009" | | Concurrency burn-in | **Missing** | `TODO.md §2.1` admits "race non riprodotta in e2e-008/009" |
| Multi-host federation | Not in scope | `TODO.md §6.3` deferred | | Multi-host federation | Not in scope | `TODO.md §6.3` deferred |
| Template snapshot refresh procedure | Partial | `Backup-CITemplate.ps1` exists; refresh procedure not codified | | Template snapshot refresh procedure | Partial | `Backup-CITemplate.ps1` exists; refresh procedure not codified |
| Setup-Host post-conditions documented | Partial | `Setup-Host.ps1` does the work but `Validate-DeployState.ps1` covers templates, not host | | Setup-Host post-conditions documented | Partial | `Setup-Host.ps1` does the work but `Validate-DeployState.ps1` covers templates, not host |
Overall completion against the original scope: **~85%**. The remaining 15% is concentrated in test coverage and concurrency validation — exactly the parts that justify the "production-ready" label. Overall completion against the original scope: **~85%**. The remaining 15% is concentrated in test coverage and concurrency validation — exactly the parts that justify the "production-ready" label.
@@ -284,18 +284,18 @@ Currently `[string] $GuestPassword = ''`, which triggers a prompt — fine. But
### 5.7 OWASP Top 10 Coverage (in scope) ### 5.7 OWASP Top 10 Coverage (in scope)
| Risk | Status | | Risk | Status |
| --- | --- | | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| A01 Broken Access Control | Local host only. Acceptable. | | A01 Broken Access Control | Local host only. Acceptable. |
| A02 Cryptographic Failures | Self-signed TLS for lab use. Acceptable. PAT base64 in command line is the only real concern (§5.2). | | A02 Cryptographic Failures | Self-signed TLS for lab use. Acceptable. PAT base64 in command line is the only real concern (§5.2). |
| A03 Injection | `BuildCommand` is by-design caller-controlled. JSON env injection parses safely via `ConvertFrom-Json`. SSH commands built from string concatenation in `Invoke-RemoteBuild.ps1` Linux branch — `$GuestLinuxWorkDir`, `$CloneBranch`, etc. are not user-supplied in the trigger path but a workflow author could pass `'$(rm -rf /)'` in `submodules` etc. The `single-quote escape` on `ExtraGuestEnv` values is correct; other interpolated strings are not escaped. **MEDIUM** — see §6.7. | | A03 Injection | `BuildCommand` is by-design caller-controlled. JSON env injection parses safely via `ConvertFrom-Json`. SSH commands built from string concatenation in `Invoke-RemoteBuild.ps1` Linux branch — `$GuestLinuxWorkDir`, `$CloneBranch`, etc. are not user-supplied in the trigger path but a workflow author could pass `'$(rm -rf /)'` in `submodules` etc. The `single-quote escape` on `ExtraGuestEnv` values is correct; other interpolated strings are not escaped. **MEDIUM** — see §6.7. |
| A04 Insecure Design | Acceptable for homelab. | | A04 Insecure Design | Acceptable for homelab. |
| A05 Security Misconfiguration | Defender/Firewall/UAC off, documented in BEST-PRACTICES. Acceptable for isolated lab. | | A05 Security Misconfiguration | Defender/Firewall/UAC off, documented in BEST-PRACTICES. Acceptable for isolated lab. |
| A06 Vulnerable Components | `TODO.md §1.3 SHA256 pinning` was deferred. Toolchain installer downloads (Tier-1/Tier-2) use only placeholders. **MEDIUM** — see §6.8. | | A06 Vulnerable Components | `TODO.md §1.3 SHA256 pinning` was deferred. Toolchain installer downloads (Tier-1/Tier-2) use only placeholders. **MEDIUM** — see §6.8. |
| A07 Auth Failures | Shared `BuildVMGuest` account — see §5.4. | | A07 Auth Failures | Shared `BuildVMGuest` account — see §5.4. |
| A08 Software/Data Integrity | No artifact signing. **NICE-TO-HAVE** for a homelab. | | A08 Software/Data Integrity | No artifact signing. **NICE-TO-HAVE** for a homelab. |
| A09 Logging Failures | Strong (`invoke-ci.jsonl`, Event Log, webhook). Good. | | A09 Logging Failures | Strong (`invoke-ci.jsonl`, Event Log, webhook). Good. |
| A10 SSRF | Not applicable. | | A10 SSRF | Not applicable. |
--- ---
@@ -370,21 +370,21 @@ If a workflow author somehow gets `$GuestLinuxWorkDir` to contain `' && rm -rf /
## 7. Operational Gaps ## 7. Operational Gaps
| Gap | Severity | Notes | | Gap | Severity | Notes |
| --- | --- | --- | | --------------------------------------------------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| No documented template-refresh runbook | HIGH | `Backup-CITemplate.ps1` exists, but the procedure (Win KMS reactivation, snapshot rebuild, validation) is not codified. | | No documented template-refresh runbook | HIGH | `Backup-CITemplate.ps1` exists, but the procedure (Win KMS reactivation, snapshot rebuild, validation) is not codified. |
| No automated end-to-end smoke test | HIGH | The "production-ready" claim rests on `e2e-008`/`e2e-009` manual runs. | | No automated end-to-end smoke test | HIGH | The "production-ready" claim rests on `e2e-008`/`e2e-009` manual runs. |
| `capacity: 4` never validated | HIGH | See §6.1. | | `capacity: 4` never validated | HIGH | See §6.1. |
| No CI for the CI | HIGH | PSScriptAnalyzer lint workflow exists; no Pester run on commit; no integration test on commit. | | No CI for the CI | HIGH | PSScriptAnalyzer lint workflow exists; no Pester run on commit; no integration test on commit. |
| No alerting on stuck jobs | MEDIUM | A job that hangs at 1 h 50 min (just under the 2 h runner timeout) is invisible. Watchdog only checks the runner service, not job duration. | | No alerting on stuck jobs | MEDIUM | A job that hangs at 1 h 50 min (just under the 2 h runner timeout) is invisible. Watchdog only checks the runner service, not job duration. |
| No central log aggregation | MEDIUM | JSONL files are per-job. Cross-job analysis requires manual grep. A `Get-CIJobStats.ps1` summarizer would help. | | No central log aggregation | MEDIUM | JSONL files are per-job. Cross-job analysis requires manual grep. A `Get-CIJobStats.ps1` summarizer would help. |
| No quota/limit on PR builds | MEDIUM | A misbehaving workflow could fork the orchestrator. Concurrency lock prevents IP collisions but not disk fill. `MaxAgeHours 4` provides eventual cleanup. | | No quota/limit on PR builds | MEDIUM | A misbehaving workflow could fork the orchestrator. Concurrency lock prevents IP collisions but not disk fill. `MaxAgeHours 4` provides eventual cleanup. |
| No multi-host fan-out | NICE-TO-HAVE | `§6.3` deferred. Single point of failure is the workstation. Acceptable for homelab. | | No multi-host fan-out | NICE-TO-HAVE | `§6.3` deferred. Single point of failure is the workstation. Acceptable for homelab. |
| No remote-access procedure for debugging a stuck VM | LOW | `Cleanup-OrphanedBuildVMs.ps1` will eventually destroy a stuck VM. Manual inspection between job and cleanup requires knowing the clone path. | | No remote-access procedure for debugging a stuck VM | LOW | `Cleanup-OrphanedBuildVMs.ps1` will eventually destroy a stuck VM. Manual inspection between job and cleanup requires knowing the clone path. |
| No host hardware monitoring | LOW | CPU/RAM/disk-IO not measured. `Measure-CIBenchmark.ps1` is phase-time only. | | No host hardware monitoring | LOW | CPU/RAM/disk-IO not measured. `Measure-CIBenchmark.ps1` is phase-time only. |
| `BaseClean` snapshot age not tracked | LOW | Windows KMS lease is 180 days. After that, builds will silently degrade (activation issues affecting `dotnet`). | | `BaseClean` snapshot age not tracked | LOW | Windows KMS lease is 180 days. After that, builds will silently degrade (activation issues affecting `dotnet`). |
| `runner/Install-Runner.ps1` deprecated but present | LOW | Delete it. | | `runner/Install-Runner.ps1` deprecated but present | LOW | Delete it. |
| `Setup-Host.ps1` password documentation mismatch | LOW | See §4.5. | | `Setup-Host.ps1` password documentation mismatch | LOW | See §4.5. |
--- ---
@@ -436,15 +436,15 @@ Four Pester v5 files exist in `tests/`:
Per `TODO.md §5.1`, they all use a fake `vmrun.cmd` driven by `$env:FAKE_VMRUN_EXIT`. What this means in practice: Per `TODO.md §5.1`, they all use a fake `vmrun.cmd` driven by `$env:FAKE_VMRUN_EXIT`. What this means in practice:
| Tested | Not Tested | | Tested | Not Tested |
| --- | --- | | ------------------------------------------------------ | ------------------------------------------------------------------------- |
| Argument construction for `vmrun clone` | Whether `vmrun clone` actually clones | | Argument construction for `vmrun clone` | Whether `vmrun clone` actually clones |
| `Invoke-Vmrun` return shape | Whether `Invoke-Vmrun` works with real `vmrun.exe` | | `Invoke-Vmrun` return shape | Whether `Invoke-Vmrun` works with real `vmrun.exe` |
| Parameter validation regexes | Whether `Test-NetConnection -Port 5986` works | | Parameter validation regexes | Whether `Test-NetConnection -Port 5986` works |
| Path resolution helpers | Whether `Start-Sleep` polling deadlines fire correctly | | Path resolution helpers | Whether `Start-Sleep` polling deadlines fire correctly |
| Throw-on-error paths via fake exit codes | The actual failure modes (`vmware-vmx.exe` file lock, DHCP timeout, etc.) | | Throw-on-error paths via fake exit codes | The actual failure modes (`vmware-vmx.exe` file lock, DHCP timeout, etc.) |
| WinRM session options object shape | Whether WinRM actually accepts self-signed cert | | WinRM session options object shape | Whether WinRM actually accepts self-signed cert |
| Phase 1 readiness loop (with fake `vmrun list` output) | Whether real VM boot timing fits the deadline | | Phase 1 readiness loop (with fake `vmrun list` output) | Whether real VM boot timing fits the deadline |
This is meaningful coverage — the Pester suite catches regressions in argument shape, parameter validation, return types, and exit-code interpretation. It is NOT integration coverage. Calling this "production-ready" testing is overstating it. This is meaningful coverage — the Pester suite catches regressions in argument shape, parameter validation, return types, and exit-code interpretation. It is NOT integration coverage. Calling this "production-ready" testing is overstating it.
@@ -464,18 +464,18 @@ Estimated test coverage (lines exercised by Pester / lines of production code):
This is the area I am most positive about. The system genuinely has better observability than most paid CI systems give you: This is the area I am most positive about. The system genuinely has better observability than most paid CI systems give you:
| Channel | Purpose | Quality | | Channel | Purpose | Quality |
| --- | --- | --- | | ------------------------------------------------------------- | ------------------------------- | ------- |
| `F:\CI\Logs\$JobId\invoke-ci.log` | Per-job transcript | High | | `F:\CI\Logs\$JobId\invoke-ci.log` | Per-job transcript | High |
| `F:\CI\Logs\$JobId\invoke-ci.jsonl` | Per-job structured phase events | High | | `F:\CI\Logs\$JobId\invoke-ci.jsonl` | Per-job structured phase events | High |
| `F:\CI\Logs\benchmark.jsonl` | Cross-job benchmark trend | High | | `F:\CI\Logs\benchmark.jsonl` | Cross-job benchmark trend | High |
| Windows Event Log `CI-DiskAlert` (EventId 1001) | Disk alert | Medium | | Windows Event Log `CI-DiskAlert` (EventId 1001) | Disk alert | Medium |
| Windows Event Log `CI-RunnerHealth` (EventIds 1002/1003/1004) | Runner state changes | High | | Windows Event Log `CI-RunnerHealth` (EventIds 1002/1003/1004) | Runner state changes | High |
| Webhook (Discord/Gitea-compatible) | Real-time notification | High | | Webhook (Discord/Gitea-compatible) | Real-time notification | High |
| `F:\CI\State\runner-restart-log.json` | Rolling 1-hour restart cooldown | High | | `F:\CI\State\runner-restart-log.json` | Rolling 1-hour restart cooldown | High |
| `F:\CI\State\ip-leases\<ip>.lease` | Active IP allocations | Medium | | `F:\CI\State\ip-leases\<ip>.lease` | Active IP allocations | Medium |
| Task Scheduler history | Scheduled-task health | Medium | | Task Scheduler history | Scheduled-task health | Medium |
| PSScriptAnalyzer lint workflow output | Code health | Medium | | PSScriptAnalyzer lint workflow output | Code health | Medium |
What is missing: What is missing:
@@ -737,17 +737,17 @@ What stops me from agreeing with the `README.md` claim of "production-ready":
Honest grade: Honest grade:
| Dimension | Grade | | Dimension | Grade |
| --- | --- | | ---------------------- | ------------------------------------ |
| Architecture | A- | | Architecture | A- |
| Code Quality | B+ | | Code Quality | B+ |
| Security (in scope) | B | | Security (in scope) | B |
| Reliability (in scope) | B- (would be A- with §6.1 validated) | | Reliability (in scope) | B- (would be A- with §6.1 validated) |
| Test Coverage | C | | Test Coverage | C |
| Observability | A- | | Observability | A- |
| Documentation | B+ | | Documentation | B+ |
| Operational Readiness | B- | | Operational Readiness | B- |
| Overall | **B+** | | Overall | **B+** |
**Production-ready for the homelab use case it was built for**, with the caveats above. **Not production-ready by any commercial standard**, but it was never built to be, and that is fine. **Production-ready for the homelab use case it was built for**, with the caveats above. **Not production-ready by any commercial standard**, but it was never built to be, and that is fine.
+20 -20
View File
@@ -241,26 +241,26 @@ The other GPT-5.5 recommendations respect PS 5.1, VMware Workstation single-host
## 7. Priority Validation ## 7. Priority Validation
| GPT-5.5 Severity | Item | My Verdict | Rationale | | GPT-5.5 Severity | Item | My Verdict | Rationale |
| --- | --- | --- | --- | | ---------------- | ------------------------------------ | --------------------------- | -------------------------------------------------------------------------------------------------------------- |
| CRITICAL | Composite action outputs structure | Should be HIGH | Step-level outputs work today; only caller-facing action interface is broken. Latent, not active. | | CRITICAL | Composite action outputs structure | Should be HIGH | Step-level outputs work today; only caller-facing action interface is broken. Latent, not active. |
| CRITICAL | Linux extra guest env secret logging | CRITICAL (concur) | Active leak path. | | CRITICAL | Linux extra guest env secret logging | CRITICAL (concur) | Active leak path. |
| CRITICAL | Linux Mode 2 PAT in SSH command | HIGH-CRITICAL boundary | PAT visibility limited to host argv + guest /proc. Real but bounded. I would put HIGH; CRITICAL is defensible. | | CRITICAL | Linux Mode 2 PAT in SSH command | HIGH-CRITICAL boundary | PAT visibility limited to host argv + guest /proc. Real but bounded. I would put HIGH; CRITICAL is defensible. |
| HIGH | vmrun unbounded calls | HIGH (concur) | | | HIGH | vmrun unbounded calls | HIGH (concur) | |
| HIGH | Stale vm-start.lock | HIGH (concur) | | | HIGH | Stale vm-start.lock | HIGH (concur) | |
| HIGH | Setup-Host stale dirs | HIGH (concur) | | | HIGH | Setup-Host stale dirs | HIGH (concur) | |
| HIGH | Backup default path | HIGH (concur) | | | HIGH | Backup default path | HIGH (concur) | |
| HIGH | Failure-path diagnostics | Should be MEDIUM | Quality-of-life, not operational-trust. | | HIGH | Failure-path diagnostics | Should be MEDIUM | Quality-of-life, not operational-trust. |
| HIGH | Test plan PS7 / wrong params | Should be MEDIUM | Documentation-only. | | HIGH | Test plan PS7 / wrong params | Should be MEDIUM | Documentation-only. |
| HIGH | Shared cache not wired | Should be MEDIUM | Documented feature missing, performance impact only. | | HIGH | Shared cache not wired | Should be MEDIUM | Documented feature missing, performance impact only. |
| MEDIUM | JobId not sanitized | Should be LOW | Local-only attack surface in single-tenant homelab. | | MEDIUM | JobId not sanitized | Should be LOW | Local-only attack surface in single-tenant homelab. |
| MEDIUM | Wait-VMReady TCP-only check | MEDIUM (concur) | | | MEDIUM | Wait-VMReady TCP-only check | MEDIUM (concur) | |
| MEDIUM | CI-FLOW doc claims partial artifacts | Should be LOW | Pure docs. | | MEDIUM | CI-FLOW doc claims partial artifacts | Should be LOW | Pure docs. |
| MEDIUM | Validate-SetupState PasswordExpires | MEDIUM (concur) | Validation failure mode. | | MEDIUM | Validate-SetupState PasswordExpires | MEDIUM (concur) | Validation failure mode. |
| MEDIUM | Ubuntu VMDK no hash | MEDIUM (concur) | | | MEDIUM | Ubuntu VMDK no hash | MEDIUM (concur) | |
| MEDIUM | Installer hash placeholders | MEDIUM (concur for homelab) | | | MEDIUM | Installer hash placeholders | MEDIUM (concur for homelab) | |
| MEDIUM | Event Log / task name drift | Should be LOW | Tests fail not scripts. | | MEDIUM | Event Log / task name drift | Should be LOW | Tests fail not scripts. |
| MEDIUM | _Transport.psm1 host-key handling | MEDIUM (concur) | | | MEDIUM | _Transport.psm1 host-key handling | MEDIUM (concur) | |
Items I would add at HIGH that GPT-5.5 missed: `act_runner` SYSTEM-vs-user SSH alias mismatch (verifiable, runtime-reachable), `ci-report-ip.service` missing from `Validate-DeployState.ps1` (silent 120 s timeout), `capacity: 4` burn-in not run (concurrency claim unmeasured). Items I would add at HIGH that GPT-5.5 missed: `act_runner` SYSTEM-vs-user SSH alias mismatch (verifiable, runtime-reachable), `ci-report-ip.service` missing from `Validate-DeployState.ps1` (silent 120 s timeout), `capacity: 4` burn-in not run (concurrency claim unmeasured).