Files
local-ci-cd-system/docs/LINUX-TEMPLATE-SETUP.md
T
Simone 3592dcab78 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.
2026-05-13 00:08:19 +02:00

18 KiB

Linux Template VM Setup Piano di implementazione

Status: implementato (2026-05-11) — Fasi A-E complete. Fase F (test e2e) richiede provisioning fisico VM. Vedi TODO.md §6.1 (P2). Distro scelta: Ubuntu 24.04 LTS (cloud image, cloud-init). Approccio simmetrico a Windows.


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)

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 leggibili e manutenibili in un secondo script dedicato identico alla divisione Deploy/Setup/Prepare di Windows.


Specifiche VM

Parametro Valore
OS Ubuntu 24.04 LTS (cloud image, non ISO installer)
Immagine base noble-server-cloudimg-amd64.vmdk
Download https://cloud-images.ubuntu.com/noble/current/
vCPU 4
RAM 4096 MB
Disco 40 GB thin (resize del cloud VMDK)
NIC VMnet8 (NAT) vmxnet3 diretto (driver nativo kernel)
VMX path F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx
Snapshot name BaseClean-Linux

Differenza chiave da Windows: l'immagine di partenza e gia installata (cloud VMDK, ~600 MB). Nessuna fase di installazione OS cloud-init provvede al bootstrap al primo boot in 30-60 secondi. La NIC non richiede lo swap e1000e vmxnet3 perche il kernel Linux ha il driver vmxnet3 nativo.


Prerequisiti host

  • SSH key CI dedicata generare una volta sola (no passphrase):
    New-Item -ItemType Directory -Force F:\CI\keys | Out-Null
    ssh-keygen -t ed25519 -f F:\CI\keys\ci_linux -N '""' -C 'ci-linux-runner'
    # Risultato: F:\CI\keys\ci_linux (privata) + F:\CI\keys\ci_linux.pub (pubblica)
    
  • OpenSSH client verificato presente sull'host (default su Windows 11):
    Get-WindowsCapability -Online -Name OpenSSH.Client* | Select-Object State
    # Atteso: State = Installed
    
  • F:\CI\Templates\LinuxBuild2404\ creata (Setup-Host.ps1 o manuale)
  • F:\CI\ISO\ creata (il VMDK viene scaricato automaticamente da Deploy se mancante)

Fase A Deploy-LinuxBuild2404.ps1

Script host-side. Produce una VM pronta con cloud-init completato e SSH raggiungibile. Non richiede installazione OS parte dal cloud VMDK pre-built.

  • Step 1 Validate prerequisites

    • Parametro -VMwareWorkstationDir (default C:\Program Files (x86)\VMware\VMware Workstation) — stesso pattern di Deploy-WinBuild2025.ps1
    • vmrun.exe presente in $VMwareWorkstationDir
    • vmware-vdiskmanager.exe presente in $VMwareWorkstationDir ($vdiskMgr = Join-Path $VMwareWorkstationDir 'vmware-vdiskmanager.exe')
    • SSH key F:\CI\keys\ci_linux.pub presente
    • Cartella destinazione VMX non gia occupata (o -Force per sovrascrivere)
    • (il VMDK sorgente viene gestito in Step 1b — nessun prerequisito manuale)
  • Step 1b Download cloud VMDK se assente (F:\CI\ISO\ come cache locale)

    $VmdkUrl  = 'https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.vmdk'
    $VmdkPath = 'F:\CI\ISO\noble-server-cloudimg-amd64.vmdk'
    if (-not (Test-Path $VmdkPath)) {
        Write-Host "[Deploy] VMDK non trovato, avvio download..."
        New-Item -ItemType Directory -Force F:\CI\ISO | Out-Null
        $tmp = "$VmdkPath.part"
        try {
            Invoke-WebRequest -Uri $VmdkUrl -OutFile $tmp -UseBasicParsing
            Move-Item $tmp $VmdkPath
            Write-Host "[Deploy] Download completato: $VmdkPath"
        } catch {
            Remove-Item $tmp -ErrorAction SilentlyContinue
            throw "[Deploy] Download VMDK fallito: $_"
        }
    } else {
        Write-Host "[Deploy] VMDK trovato in cache: $VmdkPath"
    }
    
    • Usa Invoke-WebRequest (nativo PowerShell, no dipendenze esterne)
    • Scrittura atomica: file .part durante download, rinomina solo a completamento
    • In caso di errore: il file .part viene rimosso, l'eccezione termina lo script
    • Parametro opzionale -VmdkUrl per sovrascrivere l'URL (es. mirror locale)
  • Step 2 Genera cloud-init user-data + meta-data (inline, no template esterno)

    • meta-data: instance-id: linuxbuild-001, local-hostname: ci-linux-template
    • user-data (YAML):
      • hostname: ci-linux-template
      • users: utente ci_build, shell /bin/bash, sudo: ALL=(ALL) NOPASSWD:ALL, ssh_authorized_keys con contenuto di ci_linux.pub
      • Nessun packages, nessun package_update, nessun runcmd: tutto il provisioning (apt, toolchain, SSH hardening, swap) e' delegato a Prepare-LinuxBuild2404.ps1 via Install-CIToolchain-Linux2404.sh
      • Nessun power_state: il reboot non e' necessario, cloud-init completa tutto al primo boot
  • Step 3 Costruisce seed ISO nocloud via IMAPI2FS COM

    • Due file: user-data + meta-data (volume label: cidata)
    • Stesso codice COM gia usato in Deploy-WinBuild2025.ps1 Step 3
    • Output: F:\CI\Templates\LinuxBuild2404\cloud-init-seed.iso
  • Step 4 Converti e ridimensiona cloud VMDK

    • Il cloud VMDK e' in formato streamOptimized (distribuzione), non direttamente resizeable.
    • Converti a monolithicSparse (tipo 0) contestualmente alla copia: & $vdiskMgr -r noble-server-cloudimg-amd64.vmdk -t 0 LinuxBuild2404.vmdk
    • Ridimensiona a 40 GB: & $vdiskMgr -x 40GB LinuxBuild2404.vmdk (stessa variabile $vdiskMgr di Deploy-WinBuild2025.ps1, valorizzata in Step 1)
    • Il resize avviene PRIMA del primo boot: l'immagine Ubuntu 24.04 ha i moduli cloud-init growpart + resizefs abilitati di default — espandono automaticamente la partizione root e il filesystem durante il primo avvio, senza runcmd aggiuntivi
  • Step 5 Genera .vmx

    • guestOS = "ubuntu-64", firmware = "efi" (Ubuntu 24.04 cloud image usa GPT con partizione EFI; il boot sotto BIOS legacy fallirebbe)
    • NIC: vmxnet3, VMnet8
    • Disco: LinuxBuild2404.vmdk (scsi0:0)
    • CD-ROM secondario: cloud-init-seed.iso (connesso)
    • Nessun USB controller, nessuna sound card
    • memsize = 4096, numvcpus = 4
  • Step 6 Power on (vmrun start nogui)

  • Step 7 Polling SSH port 22 fino a ready

    • Test-NetConnection -ComputerName $IP -Port 22 ogni 10 secondi
    • Timeout: 5 minuti (cloud-init + reboot finale)
    • IP rilevato via vmrun getGuestIPAddress

    open-vm-tools e pre-installato nell'Ubuntu 24.04 cloud image. vmrun getGuestIPAddress funziona senza installazione aggiuntiva.

  • Step 8 Verifica cloud-init completato

    ssh -i F:\CI\keys\ci_linux -o StrictHostKeyChecking=accept-new `
        -o ConnectTimeout=5 ci_build@$IP `
        "test -f /var/lib/cloud/instance/boot-finished && echo OK"
    # Atteso: OK
    
  • Step 9 Rimuove seed ISO dal VMX

    • Setta ide1:0.present = "FALSE" nel VMX
    • Evita che linked clone ricevano il seed ISO e ri-eseguano cloud-init
  • Step 10 Print summary (VMX path, IP, SSH fingerprint)


Fase B Prepare-LinuxBuild2404.ps1

Script host-side. Copia il setup script, lo esegue via SSH, valida stato, prende snapshot. Equivalente di Prepare-WinBuild2025.ps1 con SSH al posto di WinRM.

  • Step 1 Pre-flight

    • VMX presente; se VM spenta, avvia con vmrun start nogui
    • SSH key F:\CI\keys\ci_linux presente
    • ssh.exe e scp.exe nel PATH host
    • TCP/22 raggiungibile (Test-NetConnection)
  • Step 2 Auto-detect IP via vmrun getGuestIPAddress $VMXPath

    • Se -VMIPAddress e fornito esplicitamente, salta il rilevamento automatico
  • Step 3 Aggiungi host key a known_hosts

    ssh -i F:\CI\keys\ci_linux -o StrictHostKeyChecking=accept-new `
        ci_build@$IP "echo connected" | Out-Null
    

    Solo al primo run; idempotente se gia presente.

  • Step 4 Copia Install-CIToolchain-Linux2404.sh in VM

    scp -i F:\CI\keys\ci_linux `
        "$PSScriptRoot\Install-CIToolchain-Linux2404.sh" `
        "ci_build@${IP}:/tmp/Install-CIToolchain-Linux2404.sh"
    

    Valida: confronta size locale vs remota via ssh ... stat -c %s /tmp/...

  • Step 5 Esegui setup script nel guest

    ssh -i F:\CI\keys\ci_linux ci_build@$IP `
        "chmod +x /tmp/Install-CIToolchain-Linux2404.sh && sudo /tmp/Install-CIToolchain-Linux2404.sh"
    # Cattura exit code; != 0 => abort con errore leggibile
    

    Flag opzionali passabili: --skip-update, --dotnet, --mingw

  • Step 6 Post-setup remote validation (batch via singola sessione SSH)

    • systemctl is-active ssh = active
    • id ci_build contiene sudo
    • sudo -n true exit 0 (passwordless sudo)
    • which gcc g++ clang cmake python3 git 7z tutti trovati
    • test -d /opt/ci/build -a -d /opt/ci/output -a -d /opt/ci/scripts exit 0
    • swapon --show output vuoto (swap disabilitato)
    • grep -q "^PasswordAuthentication no" /etc/ssh/sshd_config
  • Step 7 Shutdown VM

    & $vmrun stop $VMXPath soft
    # Polling vmrun list fino a VM non piu presente
    
  • Step 8 Snapshot BaseClean-Linux

    & $vmrun snapshot $VMXPath 'BaseClean-Linux'
    
  • Final Print summary (VMX, snapshot name, toolchain versions rilevate)


Fase C Install-CIToolchain-Linux2404.sh

Script guest-side (Bash). Installazione toolchain CI e hardening. Eseguito da Prepare via SSH come ci_build con sudo.

Header: #!/usr/bin/env bash + set -euo pipefail Helper assert_step(): stampa [OK] [Step N] desc su successo, exit 1 su fallimento.

  • Step 1 apt update + upgrade (saltabile con --skip-update)

    sudo DEBIAN_FRONTEND=noninteractive apt-get update -qq
    sudo DEBIAN_FRONTEND=noninteractive apt-get upgrade -y -qq
    
  • Step 2 Toolchain build essentials

    sudo apt-get install -y -qq \
        build-essential gcc g++ clang \
        make cmake ninja-build \
        pkg-config autoconf automake libtool
    
    • assert: command -v gcc, command -v clang, command -v cmake
  • Step 3 Python

    sudo apt-get install -y -qq python3 python3-pip python3-venv
    sudo ln -sf /usr/bin/python3 /usr/local/bin/python
    
    • assert: python3 --version, pip3 --version
  • Step 4 Tier-1 Toolchain (speculare a §6.6 Windows: Git + 7-Zip)

    sudo apt-get install -y -qq git p7zip-full curl wget ca-certificates
    
    • assert: command -v git, command -v 7z
  • Step 4b .NET SDK (opzionale, flag --dotnet)

    curl -fsSL https://dotnet.microsoft.com/download/dotnet/scripts/v1/dotnet-install.sh \
        | sudo bash -s -- --channel 10.0 --install-dir /usr/local/dotnet
    sudo ln -sf /usr/local/dotnet/dotnet /usr/local/bin/dotnet
    
    • assert: dotnet --version
  • Step 4c mingw-w64 (opzionale, flag --mingw cross-compile per Windows)

    sudo apt-get install -y -qq mingw-w64
    
    • assert: command -v x86_64-w64-mingw32-gcc
  • Step 5 CI directories

    sudo mkdir -p /opt/ci/{build,output,scripts,cache}
    sudo chown -R ci_build:ci_build /opt/ci
    
    • assert: test -d /opt/ci/build, test -d /opt/ci/output, test -d /opt/ci/scripts
  • Step 6 SSH hardening (PasswordAuth off gia impostato da cloud-init, ri-validato)

    sudo sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
    sudo sed -i 's/^#*PubkeyAuthentication.*/PubkeyAuthentication yes/' /etc/ssh/sshd_config
    sudo systemctl restart sshd
    
    • assert: grep -q "^PasswordAuthentication no" /etc/ssh/sshd_config
  • Step 7 Disabilita swap permanente

    sudo swapoff -a
    sudo sed -i '/ swap / s/^/#/' /etc/fstab
    
    • assert: swapon --show output vuoto
  • Step 8 Disabilita apt auto-update (no lock durante build)

    sudo systemctl mask apt-daily.service apt-daily-upgrade.service \
        apt-daily.timer apt-daily-upgrade.timer
    sudo apt-get remove -y unattended-upgrades 2>/dev/null || true
    
  • Step 9 Cleanup pre-snapshot

    sudo apt-get clean
    sudo rm -rf /var/lib/apt/lists/*
    sudo journalctl --vacuum-time=1d
    sudo rm -rf /tmp/* /var/tmp/*
    history -c
    cat /dev/null > ~/.bash_history
    
  • Final Gate pre-snapshot (exit 1 se qualcosa manca)

    • Ogni tool richiesto raggiungibile con command -v
    • /opt/ci/{build,output,scripts} esistenti con owner ci_build
    • swapon --show vuoto
    • sshd attivo
    • PasswordAuthentication no in sshd_config
    • Root filesystem >= 38 GB (verifica che cloud-init growpart abbia funzionato):
      df -BG / | awk 'NR==2{gsub("G","",$2); if ($2+0 < 38) {print "FAIL: root fs too small"; exit 1}}'
      
    • Nessun installer residuo in /tmp

Fase D Adattamento script CI

  • scripts/_Transport.psm1 nuovo modulo SSH-only per il branch Linux. Gli script Windows esistenti NON vengono modificati ora; il refactoring WinRM e' rinviato.

    function Invoke-SshCommand { param($IP, $User, $KeyPath, $Command, ...) }
    function Copy-SshItem      { param($Source, $Dest, $IP, $User, $KeyPath, [ValidateSet('ToGuest','FromGuest')] $Direction, ...) }
    function Test-SshReady     { param($IP, $User, $KeyPath, $TimeoutSec, ...) }
    

    Gli script CI (Invoke-CIJob, Invoke-RemoteBuild, Get-BuildArtifacts) chiameranno queste funzioni nel branch Linux senza toccare il branch WinRM esistente.

  • scripts/Invoke-CIJob.ps1 aggiungere parametro -GuestOS Windows|Linux

    • Auto-detect da VMX guestOS field se non fornito
    • Branch su transport (WinRM vs SSH) in ogni fase
  • scripts/Wait-VMReady.ps1 aggiungere -Transport SSH

    • Probe: Test-NetConnection -Port 22 + ssh -o ConnectTimeout=5 ... "echo ok"
  • scripts/Invoke-RemoteBuild.ps1 branch SSH+scp per Linux

    • Transfer: scp invece di Copy-Item -ToSession
    • Build: ssh ... "cd /opt/ci/build && $BuildCommand"
  • scripts/Get-BuildArtifacts.ps1 branch scp per Linux

    • scp -r ci_build@$IP:/opt/ci/output/* $LocalArtifactDir\
  • scripts/New-BuildVM.ps1 gia OS-agnostic (vmrun clone)

    • Verificare che -SnapshotName BaseClean-Linux funzioni correttamente
  • scripts/Remove-BuildVM.ps1 gia OS-agnostic, nessuna modifica prevista


Fase E Runner e workflow Gitea

  • Label linux-build aggiunta al runner in runner/config.yaml:

    labels:
      - 'windows-build:host'
      - 'linux-build:host'
    
  • Variabile d'ambiente GITEA_CI_LINUX_TEMPLATE_PATH nel servizio act_runner: F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx

  • Workflow matrix di esempio (gitea/workflow-example.yml aggiornato):

    strategy:
      matrix:
        target: [windows, linux]
    runs-on: ${{ matrix.target }}-build
    

Fase F Test e2e

  • Smoke test linked clone + SSH ready:

    .\scripts\New-BuildVM.ps1 -JobId 'linux-smoke-001' `
        -TemplatePath 'F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx' `
        -SnapshotName 'BaseClean-Linux'
    
  • Build test comando reale nella VM:

    .\scripts\Invoke-CIJob.ps1 -JobId 'linux-e2e-001' -GuestOS Linux `
        -RepoUrl 'ssh://gitea-ci/Simone/<repo>.git' -Branch 'main' `
        -TemplatePath 'F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx' `
        -BuildCommand 'make -C /opt/ci/build all' `
        -GuestArtifactSource '/opt/ci/output'
    
  • Cleanup linked clone rimosso dopo build (Remove-BuildVM.ps1)

  • Matrix build run parallela Windows + Linux sullo stesso push


Aspetto Windows Linux
Immagine di partenza ISO installer (Deploy ~60-90 min unattended) Cloud VMDK pre-built (boot + cloud-init ~60 s)
Provisioning unattended autounattend.xml (Windows Setup) cloud-init user-data (seed ISO nocloud)
Transport host VM WinRM HTTPS/5986 + PSSession ssh.exe + scp.exe (built-in Windows 11)
NIC strategia e1000e install vmxnet3 swap post-Tools vmxnet3 diretto (driver nativo kernel)
Setup script .ps1 (PowerShell, via WinRM) .sh (Bash, via SSH)
Rilevamento IP vmrun getGuestIPAddress (VMware Tools) vmrun getGuestIPAddress (open-vm-tools)
Wait completamento polling flag file via vmrun copyFileFromGuestToHost polling SSH + boot-finished cloud-init
CI dirs C:\CI\{build,output,scripts} /opt/ci/{build,output,scripts,cache}
Snapshot name BaseClean BaseClean-Linux

Riferimenti