Files
local-ci-cd-system/AGENTS.md
T
Simone 451a61c6a1
Lint / python (push) Failing after 22s
Lint / pssa (push) Successful in 25s
test: bump coverage gate from 80%% to 90%%
Update --cov-fail-under in lint workflow + docs (AGENTS, README, ARCHITECTURE). Note: A5 closeout reported 80.10%% so this run will likely fail until additional tests are added.
2026-05-14 23:04:56 +02:00

13 KiB

AGENTS.md — Environment Reference

Questo file descrive l'ambiente su cui e' costruito il progetto. Leggerlo prima di generare o modificare qualsiasi script.

Istruzione per gli agenti: questo file va tenuto aggiornato. Se durante il lavoro si scopre un errore nuovo, un vincolo non documentato, un pattern che ha causato problemi o una best-practice utile, aggiungerla nella sezione "Errori frequenti da evitare" o in una sezione apposita. Non aggiungere dettagli ovvi o gia' coperti; solo informazioni che impedirebbero errori concreti in sessioni future.


Host

Parametro Valore
OS Windows 11
Hardware i9-10900X, 64 GB RAM, NVMe SSD
PowerShell 5.1 (Windows PowerShell — NON Core/7)
VMware Workstation Pro, vmrun.exe in C:\Program Files (x86)\VMware\VMware Workstation\
SSH client ssh.exe / scp.exe built-in Windows 11 (PATH)
act_runner v1.0.2 — F:\CI\act_runner\act_runner.exe
Gitea http://10.10.20.11:3100 / https://gitea.emulab.it

PowerShell 5.1 — Vincoli critici

Tutti gli script devono girare su Windows PowerShell 5.1. Le seguenti sintassi sono disponibili solo in PS 7+ e NON vanno usate:

Costrutto PS 7+ Alternativa PS 5.1 corretta
$x ??= 'default' if ($null -eq $x) { $x = 'default' }
$a ?? $b if ($null -ne $a) { $a } else { $b }
cmd1 && cmd2 cmd1; if ($LASTEXITCODE -eq 0) { cmd2 }
cmd1 || cmd2 cmd1; if ($LASTEXITCODE -ne 0) { cmd2 }
$x is [int] $x -is [int]
Ternary $a ? $b : $c if ($a) { $b } else { $c }
foreach-object con && pipeline classico con -ErrorAction Stop

Ogni script deve avere in testa:

#Requires -Version 5.1
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

Python development

L'orchestratore CI vive in src/ci_orchestrator/ (package ci-orchestrator, entry point python -m ci_orchestrator). Tutta la logica applicativa nuova va scritta in Python, non in PowerShell. Gli script PS in scripts/ sono ridotti a shim a 3 righe verso la CLI Python e sono mantenuti solo per compatibilita' con Task Scheduler e caller esterni.

Parametro Valore
Python 3.11+ richiesto (requires-python in pyproject.toml)
Venv produzione F:\CI\python\venv\ (interprete F:\CI\python\venv\Scripts\python.exe)
Venv dev locale .venv\ (NON committare; gitignored)
Install editable python -m pip install -e .[dev]
Test python -m pytest tests\python -q --cov=ci_orchestrator --cov-fail-under=90
Lint python -m ruff check src tests\python
Type-check python -m mypy --strict src

Convenzioni Python (enforced da ruff + mypy --strict):

  • Type hints obbligatori su funzioni pubbliche e helper esportati. Evitare Any se esiste un tipo concreto/Protocol; Any solo per fixture pytest e mock.
  • Niente variabili globali. Lo state vive in oggetti passati esplicitamente (factory backends.load_backend(config), Config dataclass).
  • Niente print(): usare click.echo (rispetta il flag -q di click e il redirect err=True per stderr).
  • Niente subprocess.run(..., shell=True). Niente shell-out per cose che esistono come libreria Python (paramiko per SSH, pypsrp per WinRM, keyring per credenziali).
  • Encoding stdio sempre UTF-8: i moduli Python lo assumono e runner/config.yaml esporta PYTHONIOENCODING=utf-8 ad act_runner.

Mappatura script PowerShell → sotto-comando Python (Fase A2/A3/A4):

PowerShell legacy (shim) Python sub-command
Wait-VMReady.ps1 python -m ci_orchestrator wait-ready
New-BuildVM.ps1 python -m ci_orchestrator vm new
Remove-BuildVM.ps1 python -m ci_orchestrator vm remove
Cleanup-OrphanedBuildVMs.ps1 python -m ci_orchestrator vm cleanup
Invoke-RemoteBuild.ps1 python -m ci_orchestrator build run
Get-BuildArtifacts.ps1 python -m ci_orchestrator artifacts collect
Watch-DiskSpace.ps1 python -m ci_orchestrator monitor disk
Watch-RunnerHealth.ps1 python -m ci_orchestrator monitor runner
Get-CIJobSummary.ps1 python -m ci_orchestrator report job
Invoke-CIJob.ps1 python -m ci_orchestrator job

Restano in PowerShell (girano sull'host fuori dal flusso CI o nel guest): Setup-Host.ps1, Register-CIScheduledTasks.ps1, Backup-CITemplate.ps1, Invoke-RetentionPolicy.ps1, Measure-CIBenchmark.ps1, Test-CapacityBurnIn.ps1, tutti i template/Deploy-*.ps1, template/Prepare-*.ps1, template/Install-CIToolchain-*.ps1 e i tests/Test-*.ps1 di smoke locale.

Test gate: coverage totale ≥90% (alzato in A5, poi a 90%). Nuovi moduli devono includere unit test con mock; gli errori frequenti di questa stessa sezione sono coperti da tests/python/test_agents_errors.py come regression test — non rimuoverli senza aggiornare la voce in "Errori frequenti da evitare" e motivare la rimozione.

Closeout fasi A: vedi plans/A1-closeout.md, plans/A2-closeout.md, plans/A3-closeout.md, plans/A4-closeout.md, plans/A5-closeout.md per stato per-fase, decisioni prese e voci pendenti a carico utente.


Struttura directory host (fissa)

F:\CI\
  act_runner\          — binario e stato act_runner
  Templates\
    WinBuild2025\      — template Windows Server 2025
    WinBuild2022\      — template Windows Server 2022
    LinuxBuild2404\    — template Ubuntu 24.04
  BuildVMs\            — clone efimeri (creati/distrutti per ogni job)
  Artifacts\           — artifact raccolti (per job-id)
  ISO\                 — ISO/VMDK di bootstrap (cache download)
  keys\
    ci_linux           — chiave SSH privata per guest Linux (no passphrase)
    ci_linux.pub       — chiave pubblica corrispondente

VM Template

Windows (WinBuild2025 — primario)

Parametro Valore
OS Windows Server 2025
VMX F:\CI\Templates\WinBuild2025\WinBuild2025.vmx
Snapshot clone BaseClean
Transport WinRM HTTPS porta 5986, cert self-signed (lab-only)
Credenziali Windows Credential Manager target BuildVMGuest
Rete VMnet8 NAT — 192.168.79.0/24
Toolchain VS Build Tools 2026 (MSBuild 18.5 / v145), .NET SDK 10, Python 3.13, Git, 7-Zip

Variante WinBuild2022: path F:\CI\Templates\WinBuild2022\WinBuild2022.vmx, stesso snapshot BaseClean.

Linux (LinuxBuild2404)

Parametro Valore
OS Ubuntu 24.04 LTS (cloud image)
VMX F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx
Snapshot clone BaseClean-Linux
Transport SSH porta 22, utente ci_build, chiave F:\CI\keys\ci_linux
Rete VMnet8 NAT — 192.168.79.0/24
Toolchain GCC, G++, Clang, CMake, Ninja, Python 3, Git, 7-Zip
CI dirs /opt/ci/{build,output,scripts,cache} — owner ci_build

Transport layer

  • Windows guest: WinRM (New-PSSession con New-CISessionOption da _Common.psm1). Usare Invoke-Command -Session, Copy-Item -ToSession / -FromSession.
  • Linux guest: SSH/SCP via ssh.exe / scp.exe. Usare le funzioni di scripts/_Transport.psm1: Invoke-SshCommand, Copy-SshItem, Test-SshReady.
  • vmrun.exe: sempre invocato tramite Invoke-Vmrun da _Common.psm1 (wrapper uniforme che gestisce $LASTEXITCODE e output).

NON modificare il branch WinRM esistente quando si lavora sul branch Linux e viceversa.


act_runner / Gitea Actions

  • Labels runner: windows-build:host, linux-build:host
  • Env vars iniettate in ogni job (da runner/config.yaml):
    • GITEA_CI_TEMPLATE_PATH — VMX Windows template
    • GITEA_CI_LINUX_TEMPLATE_PATH — VMX Linux template
    • GITEA_CI_CLONE_BASE_DIRF:\CI\BuildVMs
    • GITEA_CI_ARTIFACT_DIRF:\CI\Artifacts
    • GITEA_CI_GUEST_CRED_TARGETBuildVMGuest
    • GITEA_CI_SSH_KEY_PATHF:\CI\keys\ci_linux
    • CI_PYTHON_LAUNCHER — absolute path al Python di sistema usato per bootstrap del venv produzione (F:\CI\python\venv). act_runner gira come SYSTEM con PATH sanitizzato (no python/py.exe risolvibili), quindi i workflow Python leggono questo env come single source of truth. Aggiornare solo quando si fa upgrade dell'interprete.

Regole di stile (PSScriptAnalyzer)

Configurazione in PSScriptAnalyzerSettings.psd1. Regole principali:

  • Indentazione: 4 spazi (no tab)
  • Write-Host e' permesso (output catturato da act_runner; Write-Output interferisce con i return value)
  • Invoke-Expression vietato
  • Funzioni state-changing devono supportare -WhatIf / ShouldProcess
  • Credenziali solo come [PSCredential], mai plain-text string
  • Nessuna variabile globale ($global:)

Errori frequenti da evitare

  1. Sintassi PS 7+ in script PS 5.1 — vedi tabella sopra.
  2. $LASTEXITCODE non controllato dopo vmrun, ssh, scp — controllare sempre e fare throw se non zero.
  3. Percorsi hardcoded senza parametro — ogni path critico deve avere un parametro con default documentato.
  4. Modificare entrambi i branch (WinRM e SSH) nello stesso script — mantenerli separati con if ($GuestOS -eq 'Linux').
  5. Usare New-PSSession / WinRM verso host Linux — Linux usa solo SSH tramite _Transport.psm1.
  6. Non rimuovere il seed ISO dal VMX dopo il primo boot Linux — ide1:0.present = "FALSE" deve essere settato dopo cloud-init.
  7. [ordered]@{} non disponibile in PS 2 — non e' un problema qui (PS 5.1), ma ricordare che [ordered] e' PS 3+.
  8. ForEach-Object -Parallel — disponibile solo in PS 7+; usare foreach classico o Start-Job.
  9. Snapshot template catturato con VM accesa — produce file *.vmem / *.vmsn con memoria; vmrun clone ... linked -snapshot=<name> rifiuta con Error: The virtual machine should not be powered on. It is already running. anche se vmrun list mostra 0 VM. Catturare snapshot SOLO da stato fully powered-off (verificare assenza di .vmem nella dir template).
  10. vmrun getGuestIPAddress per check "VM running" — richiede VMware Tools attivi nel guest; in headless Tools puo' impiegare 30-60s a rispondere e il check appare bloccato. Usare vmrun list e cercare il path del VMX nell'output.
  11. Machine-id identico tra clone Linux — le cloud image Ubuntu hanno un /etc/machine-id fisso. VMware DHCP assegna l'IP tramite DHCP client-id derivato da machine-id: se tutti i clone hanno lo stesso machine-id ottengono lo stesso IP e si bloccano per "IP collision". Fix nel template (prima di prendere lo snapshot): sudo truncate -s 0 /etc/machine-id && sudo rm -f /var/lib/dbus/machine-id && sudo shutdown -h now, poi ricreare lo snapshot BaseClean-Linux da stato powered-off.
  12. & nativecmd 2>$null NON sopprime stderr in PS 5.1 con $ErrorActionPreference='Stop' — la stderr del processo nativo viene convertita in ErrorRecord nel pipeline di PowerShell; sotto 'Stop' questo diventa un errore terminante PRIMA che 2>$null possa scartarlo. Esempio: ssh-keygen -R <ip> -f <file> stampa "Host X not found in file" su stderr → eccezione terminante. Fix: usare $ErrorActionPreference = 'SilentlyContinue' attorno alla chiamata oppure 2>&1 | Out-Null. Per i job CI su VM ephemere locali, usare direttamente StrictHostKeyChecking=no UserKnownHostsFile=NUL (default in _Transport.psm1 con KnownHostsFile='') — nessun ssh-keygen necessario.