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
+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).
This is **intentional** — not a bug, not an oversight. Each has tradeoffs:
| 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 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 |
| 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 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 |
### When this threat model is acceptable
@@ -368,13 +368,13 @@ cached in the ISO or in `F:\CI\ISO\`).
Priority targets (descending risk):
| Installer | Script | Where to pin |
|-----------|--------|--------------|
| 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 |
| Python `.exe` | `template/Install-CIToolchain-WinBuild2025.ps1` | same |
| .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 |
| Installer | Script | Where to pin |
| ----------------------- | ----------------------------------------------- | ------------------------------------------------------ |
| 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 |
| Python `.exe` | `template/Install-CIToolchain-WinBuild2025.ps1` | same |
| .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 |
**Implementation pattern** (PS 5.1):
+10 -10
View File
@@ -8,17 +8,17 @@
Before any CI job runs, the following must be in place:
| Component | State |
| ------------------ | ----------------------------------------------------------------------- |
| Gitea server | Running, accessible on LAN |
| act_runner | Registered, running as Windows service on host |
| Template VM (Win) | Provisioned, snapshot "BaseClean" taken, VM powered off |
| Component | State |
| ------------------ | ----------------------------------------------------------------------------- |
| Gitea server | Running, accessible on LAN |
| act_runner | Registered, running as Windows service on host |
| 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) |
| WinRM | Enabled on Windows template VM (inherits to all clones) |
| 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` |
| `F:\CI\BuildVMs\` | Directory exists and writable |
| `F:\CI\Artifacts\` | Directory exists and writable |
| WinRM | Enabled on Windows template VM (inherits to all clones) |
| 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` |
| `F:\CI\BuildVMs\` | 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
| Componente | Versione/Note |
| ----------------------- | ----------------------------------------------------------------- |
| OS | Windows 11 (host fisico) o Windows Server 2022+ |
| VMware Workstation | Pro 17.x — necessario per `vmrun.exe` e supporto linked clone |
| Storage | NVMe dedicato (consigliato `F:\` riservato a CI, ≥ 500 GB libero) |
| RAM | ≥ 32 GB (4 VM parallele × 6-8 GB) |
| Rete | VMnet8 (NAT) configurato in VMware Workstation |
| PowerShell | 5.1+ (built-in) o 7.x |
| Privilegi | Account amministrativo per Setup-Host.ps1 |
| Componente | Versione/Note |
| ------------------ | ----------------------------------------------------------------- |
| OS | Windows 11 (host fisico) o Windows Server 2022+ |
| VMware Workstation | Pro 17.x — necessario per `vmrun.exe` e supporto linked clone |
| Storage | NVMe dedicato (consigliato `F:\` riservato a CI, ≥ 500 GB libero) |
| RAM | ≥ 32 GB (4 VM parallele × 6-8 GB) |
| Rete | VMnet8 (NAT) configurato in VMware Workstation |
| PowerShell | 5.1+ (built-in) o 7.x |
| Privilegi | Account amministrativo per Setup-Host.ps1 |
Software opzionali installati on-demand dallo script:
- **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
| Parametro | Default | Note |
| ---------------------------- | -------------------------------- | ------------------------------------- |
| `-CIRoot` | `F:\CI` | Base directory per tutti i dati CI |
| `-GuestCredentialTarget` | `BuildVMGuest` | Target Credential Manager |
| `-GuestUsername` | `ci_build` | Account build dentro la VM |
| `-GuestPassword` | (prompt) | Mai hard-codare |
| `-ActRunnerExe` | `<CIRoot>\act_runner\act_runner.exe` | Path binario runner |
| `-ActRunnerConfigYaml` | `<repo>\runner\config.yaml` | Source del config da copiare |
| `-GiteaUrl` | `http://10.10.20.11:3100` | URL Gitea per registrazione |
| `-GiteaRunnerToken` | (vuoto) | Token registrazione (Admin → Runners) |
| `-SkipRunnerInstall` | `$false` | Salta installazione servizio |
| `-SkipSSHConfig` | `$false` | Salta scrittura SSH alias |
| `-GiteaSSHHost` | `10.10.20.11` | Hostname SSH Gitea |
| `-GiteaSSHPort` | `2222` | Porta SSH Gitea |
| Parametro | Default | Note |
| ------------------------ | ------------------------------------ | ------------------------------------- |
| `-CIRoot` | `F:\CI` | Base directory per tutti i dati CI |
| `-GuestCredentialTarget` | `BuildVMGuest` | Target Credential Manager |
| `-GuestUsername` | `ci_build` | Account build dentro la VM |
| `-GuestPassword` | (prompt) | Mai hard-codare |
| `-ActRunnerExe` | `<CIRoot>\act_runner\act_runner.exe` | Path binario runner |
| `-ActRunnerConfigYaml` | `<repo>\runner\config.yaml` | Source del config da copiare |
| `-GiteaUrl` | `http://10.10.20.11:3100` | URL Gitea per registrazione |
| `-GiteaRunnerToken` | (vuoto) | Token registrazione (Admin → Runners) |
| `-SkipRunnerInstall` | `$false` | Salta installazione servizio |
| `-SkipSSHConfig` | `$false` | Salta scrittura SSH alias |
| `-GiteaSSHHost` | `10.10.20.11` | Hostname 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 logs | `F:\CI\act_runner\logs\` (stdout.log, stderr.log) |
| 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 (Linux) | `BaseClean-Linux` |
| 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
| Sintomo | Diagnosi / Fix |
| --------------------------------------- | -------------------------------------------------------------------- |
| `vmrun.exe NOT found` | Installa VMware Workstation Pro, 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 |
| Service `act_runner` non parte | Check `F:\CI\act_runner\logs\stderr.log` |
| `New-StoredCredential` fail | Verifica modulo CredentialManager importato + scope corretto |
| Job CI fallisce su `Test-WSMan` | TrustedHosts host non include subnet VM, AllowUnencrypted=$false |
| Sintomo | Diagnosi / Fix |
| ------------------------------- | ---------------------------------------------------------------- |
| `vmrun.exe NOT found` | Installa VMware Workstation Pro, 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 |
| Service `act_runner` non parte | Check `F:\CI\act_runner\logs\stderr.log` |
| `New-StoredCredential` fail | Verifica modulo CredentialManager importato + scope corretto |
| Job CI fallisce su `Test-WSMan` | TrustedHosts host non include subnet VM, AllowUnencrypted=$false |
+8 -8
View File
@@ -7,12 +7,12 @@
## Architettura: tre script + modulo transport
| 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/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 |
| `scripts/_Transport.psm1` | **Host** (PS) | Funzioni SSH-only per il branch Linux (WinRM esistente invariato per ora) |
| 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/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 |
| `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
(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 |
| ------------- | ---------------------------------------------------- |
| 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/` |
| vCPU | 4 |
| RAM | 4096 MB |
@@ -424,4 +424,4 @@ Helper `assert_step()`: stampa `[OK] [Step N] desc` su successo, `exit 1` su fal
- [CI-FLOW.md](CI-FLOW.md) flusso pipeline (aggiornare Step 0 prerequisites)
- [HOST-SETUP.md](HOST-SETUP.md) Setup-Host.ps1 (aggiungere step generazione SSH key)
- [TODO.md §6.1](../TODO.md) tracking implementazione
+10 -10
View File
@@ -200,16 +200,16 @@ Estimated time: 2-4 hours including Windows Update.
## Quick Reference
| Symptom | First command |
| ------------------------------ | ---------------------------------------------------------------------- |
| Runner offline | `Get-Service act_runner`, then `Restart-Service act_runner` |
| 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` |
| Symptom | First command |
| ------------------- | ------------------------------------------------------------------ |
| Runner offline | `Get-Service act_runner`, then `Restart-Service act_runner` |
| 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 -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 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 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 |
| **§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 |
+20 -20
View File
@@ -11,16 +11,16 @@ credenziali archiviate, ISO Windows Server presente).
## Architettura: tre script
| Script | Dove gira | Scopo |
| ----------------------------------- | ------------- | -------------------------------------------------------------------- |
| `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/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/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/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 |
| Script | Dove gira | Scopo |
| ----------------------------------------------- | ------------- | -------------------------------------------------------------------- |
| `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/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/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/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 |
**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.
@@ -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 |
| `-BuildUsername` | ci_build | Account CI dentro la VM |
| `-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 |
| `-CredentialTarget` | BuildVMGuest | Target Credential Manager (deve corrispondere a quanto usato da Invoke-CIJob) |
@@ -292,15 +292,15 @@ toolchain (.NET, VS Build Tools, Python).
## Troubleshooting
| Sintomo | Diagnosi / Fix |
| ---------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `Cannot reach $VMIPAddress via WinRM` | VM non avviata, WinRM non abilitato, IP errato — verifica con ipconfig |
| Sintomo | Diagnosi / Fix |
| ------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------- |
| `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` |
| `[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`) |
| `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` |
| Pre-snapshot Final check fail | Stato VM rotto — non prendere snapshot. Re-run o ricomincia da zero |
| `[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`) |
| `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` |
| Pre-snapshot Final check fail | Stato VM rotto — non prendere snapshot. Re-run o ricomincia da zero |
---
@@ -312,4 +312,4 @@ toolchain (.NET, VS Build Tools, Python).
- **§2.5 [P1]** Snapshot versionato `BaseClean_<yyyyMMdd>` (rollback in caso di refresh rotto)
- **§2.6 [P2]** Backup automatico VMDK template pre-snapshot
- **In-VM Git Clone** — installare Git for Windows + 7-Zip nel template per ottimizzare flusso
+87 -80
View File
@@ -8,23 +8,30 @@
## Table of Contents
1. [System Overview](#1-system-overview)
2. [Runner Labels](#2-runner-labels)
3. [Shell Requirement](#3-shell-requirement)
4. [Environment Variables (Injected by Runner)](#4-environment-variables-injected-by-runner)
5. [Invoke-CIJob.ps1 Parameter Reference](#5-invoke-cijobps1-parameter-reference)
6. [URL Conventions](#6-url-conventions)
7. [Artifact Path Convention](#7-artifact-path-convention)
8. [Workflow Patterns](#8-workflow-patterns)
- [8.1 Windows build (host-clone mode)](#81-windows-build-host-clone-mode)
- [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)
- [Workflow Authoring Reference](#workflow-authoring-reference)
- [Table of Contents](#table-of-contents)
- [1. System Overview](#1-system-overview)
- [2. Runner Labels](#2-runner-labels)
- [3. Shell Requirement](#3-shell-requirement)
- [4. Environment Variables (Injected by Runner)](#4-environment-variables-injected-by-runner)
- [5. Invoke-CIJob.ps1 Parameter Reference](#5-invoke-cijobps1-parameter-reference)
- [Mandatory parameters](#mandatory-parameters)
- [Optional parameters](#optional-parameters)
- [6. URL Conventions](#6-url-conventions)
- [Host-clone mode (default, no `-UseGitClone`)](#host-clone-mode-default-no--usegitclone)
- [UseGitClone mode (`-UseGitClone`)](#usegitclone-mode--usegitclone)
- [Quick reference](#quick-reference)
- [7. Artifact Path Convention](#7-artifact-path-convention)
- [8. Workflow Patterns](#8-workflow-patterns)
- [8.1 Windows build (host-clone mode)](#81-windows-build-host-clone-mode)
- [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
| Label | Configured as | Use for |
| ---------------- | ---------------- | ----------------------------------- |
| `windows-build` | `windows-build:host` | Windows VM builds, Windows-only tools |
| `linux-build` | `linux-build:host` | Linux VM builds (cross-compile, GCC/Clang) |
| `dotnet` | `dotnet:host` | Alias for windows-build (legacy) |
| `msbuild` | `msbuild:host` | Alias for windows-build (legacy) |
| Label | Configured as | Use for |
| --------------- | -------------------- | ------------------------------------------ |
| `windows-build` | `windows-build:host` | Windows VM builds, Windows-only tools |
| `linux-build` | `linux-build:host` | Linux VM builds (cross-compile, GCC/Clang) |
| `dotnet` | `dotnet: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
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
in the workflow unless you need to override the default.
| Variable | Value (default) | Description |
| ---------------------------- | ---------------------------------------------------- | --------------------------------------- |
| `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_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_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 |
| Variable | Value (default) | Description |
| ------------------------------ | --------------------------------------------------- | -------------------------------------- |
| `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_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_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 |
Invoke-CIJob.ps1 reads `GITEA_CI_TEMPLATE_PATH` and `GITEA_CI_CLONE_BASE_DIR`
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
| Parameter | Type | Description |
| ----------- | ------ | --------------------------------------------------------------- |
| `-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. |
| `-Branch` | string | Branch to build. Use `${{ github.ref_name }}`. |
| Parameter | Type | Description |
| ---------- | ------ | ------------------------------------------------------------------ |
| `-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. |
| `-Branch` | string | Branch to build. Use `${{ github.ref_name }}`. |
### Optional parameters
| Parameter | Type | Default | Description |
| ------------------------ | ------ | --------------------------- | -------------------------------------------------------------- |
| `-Commit` | string | `''` | Specific commit SHA. Use `${{ github.sha }}`. Empty = HEAD. |
| `-TemplatePath` | string | `$env:GITEA_CI_TEMPLATE_PATH` | Full path to template VMX. |
| `-SnapshotName` | string | `BaseClean` | Template snapshot name to clone from. |
| `-GuestOS` | string | `Auto` | `Windows`, `Linux`, or `Auto` (detected from VMX guestOS field). |
| `-BuildCommand` | string | `''` | Shell command to run inside VM. Empty = `dotnet build`. |
| `-GuestArtifactSource` | string | `dist` | Path inside VM guest from which artifacts are collected. |
| `-Submodules` | switch | off | Pass to clone with `--recurse-submodules`. |
| `-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). |
| `-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). |
| `-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. |
| `-ArtifactBaseDir` | string | `F:\CI\Artifacts` | Root artifact directory on host. |
| `-VMIPAddress` | string | `''` | Override guest IP. Empty = auto-detected via vmrun. |
| `-LogDir` | string | `F:\CI\Logs` | Directory for per-job transcripts and JSONL logs. |
| `-LogRetentionDays` | int | `30` | Days before log directories are purged. `0` = disabled. |
| Parameter | Type | Default | Description |
| ------------------------ | ------ | ------------------------------ | ---------------------------------------------------------------- |
| `-Commit` | string | `''` | Specific commit SHA. Use `${{ github.sha }}`. Empty = HEAD. |
| `-TemplatePath` | string | `$env:GITEA_CI_TEMPLATE_PATH` | Full path to template VMX. |
| `-SnapshotName` | string | `BaseClean` | Template snapshot name to clone from. |
| `-GuestOS` | string | `Auto` | `Windows`, `Linux`, or `Auto` (detected from VMX guestOS field). |
| `-BuildCommand` | string | `''` | Shell command to run inside VM. Empty = `dotnet build`. |
| `-GuestArtifactSource` | string | `dist` | Path inside VM guest from which artifacts are collected. |
| `-Submodules` | switch | off | Pass to clone with `--recurse-submodules`. |
| `-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). |
| `-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). |
| `-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. |
| `-ArtifactBaseDir` | string | `F:\CI\Artifacts` | Root artifact directory on host. |
| `-VMIPAddress` | string | `''` | Override guest IP. Empty = auto-detected via vmrun. |
| `-LogDir` | string | `F:\CI\Logs` | Directory for per-job transcripts and JSONL logs. |
| `-LogRetentionDays` | int | `30` | Days before log directories are purged. `0` = disabled. |
Exit codes: `0` = success, `1` = failure (VM is always destroyed regardless).
@@ -173,11 +180,11 @@ https://gitea.emulab.it/<owner>/<repo>.git
### Quick reference
| Mode | RepoUrl to use |
| ----------------- | ---------------------------------------------------------- |
| Default (Windows) | `ssh://gitea-ci/<owner>/<repo>.git` |
| Default (Linux) | `ssh://gitea-ci/<owner>/<repo>.git` |
| UseGitClone | `https://gitea.emulab.it/<owner>/<repo>.git` |
| Mode | RepoUrl to use |
| ----------------- | -------------------------------------------- |
| Default (Windows) | `ssh://gitea-ci/<owner>/<repo>.git` |
| Default (Linux) | `ssh://gitea-ci/<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
| Build type | Recommended `timeout-minutes` |
| --------------------------- | ----------------------------- |
| Windows build (typical) | 90 |
| Windows build (large/slow) | 120 |
| Linux build (typical) | 60 |
| Lint / static analysis | 10 |
| Template provisioning | 180 |
| Build type | Recommended `timeout-minutes` |
| -------------------------- | ----------------------------- |
| Windows build (typical) | 90 |
| Windows build (large/slow) | 120 |
| Linux build (typical) | 60 |
| Lint / static analysis | 10 |
| Template provisioning | 180 |
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 —
@@ -553,16 +560,16 @@ the cleanup task `Cleanup-OrphanedBuildVMs.ps1` handles these cases.
## 11. Common Mistakes
| Mistake | Correct approach |
| ------- | ---------------- |
| `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 |
| 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\` |
| `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 |
| `&&` 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` |
| `-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`) |
| Same `-JobId` for matrix jobs | Append matrix key: `${{ github.run_id }}-${{ matrix.config }}` |
| Mistake | Correct approach |
| ---------------------------------------------------------------- | -------------------------------------------------------------------------- |
| `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 |
| 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\` |
| `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 |
| `&&` 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` |
| `-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`) |
| Same `-JobId` for matrix jobs | Append matrix key: `${{ github.run_id }}-${{ matrix.config }}` |