3592dcab78
- 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.
292 lines
11 KiB
Markdown
292 lines
11 KiB
Markdown
# CI Pipeline Flow — Step by Step
|
||
|
||
## Trigger to Artifact: Complete Pipeline Walk-Through
|
||
|
||
---
|
||
|
||
### Step 0 — Prerequisites (one-time setup)
|
||
|
||
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 |
|
||
| 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 |
|
||
|
||
---
|
||
|
||
### Step 1 — Developer Pushes Code
|
||
|
||
```
|
||
Developer → git push origin main
|
||
```
|
||
|
||
- Git push lands on Gitea server
|
||
- Gitea evaluates `.gitea/workflows/build.yml` in the repository
|
||
- If the workflow trigger matches (e.g. `on: push` to `main`), Gitea enqueues a new **Actions job**
|
||
- Job is tagged with the label defined in the workflow (`runs-on: windows-build`)
|
||
|
||
---
|
||
|
||
### Step 2 — act_runner Picks Up the Job
|
||
|
||
```
|
||
act_runner (host) ─polling─► Gitea Actions API
|
||
◄─job data─
|
||
```
|
||
|
||
- act_runner polls the Gitea API approximately every 5–10 seconds
|
||
- Detects a pending job matching its labels (`windows-build`)
|
||
- Downloads the workflow YAML and job parameters
|
||
- If `capacity` slots are available, starts job execution immediately
|
||
- If all slots are busy, job waits in Gitea queue until a slot frees
|
||
|
||
---
|
||
|
||
### Step 3 — act_runner Executes Workflow Steps
|
||
|
||
The workflow YAML defines steps that run as PowerShell commands **on the host**.
|
||
The first substantive step calls `Invoke-CIJob.ps1`:
|
||
|
||
```yaml
|
||
- name: Run CI Job
|
||
shell: pwsh
|
||
run: |
|
||
& 'N:\Code\Workspace\Local-CI-CD-System\scripts\Invoke-CIJob.ps1' `
|
||
-JobId '${{ github.run_id }}' `
|
||
-RepoUrl 'ssh://gitea-ci/Simone/<repo>.git' `
|
||
-Branch '${{ github.ref_name }}' `
|
||
-Commit '${{ github.sha }}' `
|
||
-TemplatePath $env:GITEA_CI_TEMPLATE_PATH `
|
||
-Submodules `
|
||
-BuildCommand 'python build_plugin.py --final --dist-dir dist' `
|
||
-GuestArtifactSource 'dist'
|
||
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||
```
|
||
|
||
> Il parametro `-VMIPAddress` **non è più necessario** — l'IP viene rilevato automaticamente
|
||
> tramite `vmrun getGuestIPAddress` dopo l'avvio della VM.
|
||
|
||
---
|
||
|
||
### Step 4 — Invoke-CIJob.ps1: Clone VM
|
||
|
||
```
|
||
New-BuildVM.ps1
|
||
vmrun.exe -T ws clone <template.vmx> <clone.vmx> linked -snapshot "BaseClean"
|
||
```
|
||
|
||
- Generates unique clone name: `Clone_{JobId}_{yyyyMMdd_HHmmss}`
|
||
- Creates clone directory under `F:\CI\BuildVMs\`
|
||
- **Linked clone** creation takes ~5–15 seconds
|
||
- The template snapshot "BaseClean" is **not modified**
|
||
- Returns the full path to the new `.vmx` file
|
||
|
||
---
|
||
|
||
### Step 5 — Start VM
|
||
|
||
```
|
||
vmrun.exe -T ws start <clone.vmx> nogui
|
||
```
|
||
|
||
- Starts the cloned VM in headless (no GUI) mode
|
||
- VM boots from the "BaseClean" state: clean OS, build tools installed, WinRM enabled
|
||
- Boot takes ~20–40 seconds
|
||
|
||
---
|
||
|
||
### Step 6 — Wait for VM Readiness
|
||
|
||
```
|
||
Wait-VMReady.ps1 -VMPath <clone.vmx> -IPAddress <dynamic-NAT-ip> -TimeoutSeconds 300
|
||
```
|
||
|
||
IP is discovered dynamically via `vmrun getGuestIPAddress` (VMnet8 NAT, subnet 192.168.79.0/24).
|
||
No hardcoded IPs — each clone gets a DHCP-assigned address from VMware NAT.
|
||
|
||
Three-phase readiness check (retried every 5 seconds, up to 300s timeout).
|
||
Transport is selected automatically from the VMX `guestOS` field (`-Transport WinRM` for Windows, `-Transport SSH` for Linux):
|
||
|
||
```
|
||
Phase 1: vmrun getState → must return "running"
|
||
|
||
Windows (-Transport WinRM, default):
|
||
Phase 2: Test-Connection (ICMP ping) → must succeed
|
||
Phase 3: Test-WSMan → WinRM listener must respond
|
||
|
||
Linux (-Transport SSH):
|
||
Phase 2: Test-NetConnection -Port 22 → must succeed
|
||
Phase 3: ssh -o ConnectTimeout=5 ... "echo ready" → must return "ready"
|
||
```
|
||
|
||
- Total wait is typically **30–90 seconds** after `vmrun start`
|
||
- If timeout exceeded, VM is destroyed and job fails with a clear error message
|
||
- On success, IP and credentials are ready for PSSession
|
||
|
||
---
|
||
|
||
### Step 7 — Remote Build Execution
|
||
|
||
```
|
||
Invoke-RemoteBuild.ps1
|
||
-IPAddress <dynamic-NAT-ip> # from vmrun getGuestIPAddress
|
||
-GuestOS Windows|Linux # auto-detected from VMX guestOS field
|
||
|
||
# Windows path (default):
|
||
-Credential (from Windows Credential Manager)
|
||
-BuildCommand 'python build_plugin.py --final --dist-dir dist'
|
||
-GuestArtifactSource 'dist'
|
||
|
||
# Linux path (-GuestOS Linux):
|
||
-SshKeyPath F:\CI\keys\ci_linux
|
||
-SshUser ci_build
|
||
-CloneUrl / -CloneBranch # always in-VM git clone for Linux
|
||
-BuildCommand 'make all'
|
||
```
|
||
|
||
Sequence inside the PSSession:
|
||
|
||
```
|
||
1. New-PSSession → open WinRM session to VM
|
||
2a. (default) Compress-Archive (host) → copy zip to C:\CI\build.zip (guest) → Expand-Archive to C:\CI\build\
|
||
(source code è già clonato sull'host in Phase 1 — nessun git clone nella VM)
|
||
2b. (opt-in, `-UseGitClone`, §3.3 DONE 2026-05-10)
|
||
git clone direttamente in VM tramite `ssh://gitea-ci/...` (richiede Git+7-Zip in template, §6.6 Tier-1)
|
||
Vantaggio: skip host-zip-transfer, -25.7% durata pipeline (e2e PASS). Verifica SHA commit post-clone.
|
||
3. Invoke-Expression "$BuildCommand" in C:\CI\build\
|
||
Esempio: python build_plugin.py --final --dist-dir dist
|
||
a. Build 4 configurazioni MSBuild in parallelo (x86-unicode, x64-unicode, cli-x86, cli-x64)
|
||
b. Raccoglie artifact in C:\CI\build\dist\
|
||
c. Cleanup build dir (--final)
|
||
4. Compress-Archive C:\CI\build\$GuestArtifactSource C:\CI\output\artifacts.zip
|
||
5. Cattura exit code; se non-zero il job fallisce con errore chiaro
|
||
6. Remove-PSSession
|
||
```
|
||
|
||
- Output standard e stderr dalla build sono streamati all'host e catturati da act_runner per i log Gitea Actions
|
||
- Se la build fallisce (exit code ≠ 0), il controllo passa al blocco `finally`
|
||
|
||
---
|
||
|
||
### Step 8 — Collect Artifacts
|
||
|
||
```
|
||
Get-BuildArtifacts.ps1
|
||
-IPAddress <dynamic-NAT-ip>
|
||
-GuestOS Windows|Linux # auto-detected from Invoke-CIJob
|
||
|
||
# Windows path (default):
|
||
-Credential (from Windows Credential Manager)
|
||
-GuestArtifactPath C:\CI\output\artifacts.zip
|
||
|
||
# Linux path (-GuestOS Linux):
|
||
-SshKeyPath F:\CI\keys\ci_linux
|
||
-GuestArtifactPath /opt/ci/output
|
||
|
||
-HostArtifactDir F:\CI\Artifacts\{JobId}\
|
||
```
|
||
|
||
- Windows: apre PSSession e copia `C:\CI\output\artifacts.zip` tramite WinRM
|
||
- Linux: `scp -r ci_build@<ip>:/opt/ci/output/. <HostArtifactDir>` tramite `_Transport.psm1`
|
||
- In entrambi i casi valida che almeno un file sia stato trasferito
|
||
|
||
---
|
||
|
||
### Step 9 — Destroy VM
|
||
|
||
```
|
||
Remove-BuildVM.ps1 -VMPath <clone.vmx>
|
||
```
|
||
|
||
Sequence:
|
||
|
||
```
|
||
1. vmrun stop <clone.vmx> soft (graceful shutdown attempt)
|
||
2. Wait 5 seconds
|
||
3. vmrun getState → if still "running":
|
||
vmrun stop <clone.vmx> hard (force off)
|
||
4. vmrun deleteVM <clone.vmx> (removes VMX + VMDK delta files)
|
||
5. Remove-Item <clone dir> -Recurse (removes any leftover files)
|
||
```
|
||
|
||
- VM is gone from disk within ~5–10 seconds
|
||
- No state, no temp files, no credentials remain in the clone
|
||
- Template VM and "BaseClean" snapshot are unaffected
|
||
|
||
> **Note:** This step runs in a `finally` block inside `Invoke-CIJob.ps1`, so it
|
||
> executes even if Steps 6–8 failed. A build VM is **never** left running.
|
||
|
||
---
|
||
|
||
### Step 10 — Report Status & Upload Artifacts
|
||
|
||
```
|
||
act_runner ─► Gitea Actions API (job status: success / failure)
|
||
act_runner ─► Gitea artifact store (uploads F:\CI\Artifacts\{JobId}\*)
|
||
```
|
||
|
||
- act_runner reads the exit code from `Invoke-CIJob.ps1`
|
||
- Reports `success` or `failure` to Gitea
|
||
- Uploads artifacts using `actions/upload-artifact` step in the workflow YAML
|
||
- Build log (stdout from all steps) is stored in Gitea Actions UI
|
||
- Commit/PR status badge is updated
|
||
|
||
---
|
||
|
||
## Parallel Build Flow
|
||
|
||
When multiple pushes happen concurrently (or multiple PRs are open):
|
||
|
||
```
|
||
act_runner (capacity: 4)
|
||
├── Job #1 ──► Clone_Job_001 (192.168.79.x) → build → destroy
|
||
├── Job #2 ──► Clone_Job_002 (192.168.79.x) → build → destroy
|
||
├── Job #3 ──► Clone_Job_003 (192.168.79.x) → build → destroy
|
||
└── Job #4 ──► Clone_Job_004 (192.168.79.x) → build → destroy
|
||
(Job #5 waits in Gitea queue)
|
||
```
|
||
|
||
Note: each clone gets a dynamic IP from VMware NAT DHCP (192.168.79.0/24). IP is discovered
|
||
automatically via `vmrun getGuestIPAddress` — no static assignment required.
|
||
|
||
- Each job creates its own independently named clone
|
||
- Clones share the parent "BaseClean" snapshot (read-only CoW)
|
||
- No filesystem or process overlap between concurrent builds
|
||
- act_runner enforces the `capacity` limit
|
||
|
||
---
|
||
|
||
## Failure Scenarios
|
||
|
||
| Failure Point | Behavior |
|
||
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
|
||
| VM clone fails | `Invoke-CIJob.ps1` throws; no VM to destroy; job fails immediately |
|
||
| VM never reaches ready state (timeout) | `Wait-VMReady.ps1` throws; `finally` destroys the (running) VM |
|
||
| Build fails inside VM | `Invoke-RemoteBuild.ps1` throws; `finally` collects partial artifacts (if any), destroys VM |
|
||
| Artifact collection fails | Job marked failed; VM is still destroyed in `finally` |
|
||
| Host machine loses power mid-job | `act_runner` resumes on reboot, marks in-flight job as failed; orphan VMs must be cleaned up manually (see TODO.md) |
|
||
|
||
---
|
||
|
||
## Timing Summary (typical build)
|
||
|
||
| Phase | Typical Duration |
|
||
| ---------------------------- | -------------------- |
|
||
| Gitea → act_runner poll | 5–10 s |
|
||
| Linked clone creation | 5–15 s |
|
||
| VM boot | 20–40 s |
|
||
| WinRM readiness | 10–30 s (after boot) |
|
||
| git clone (from local Gitea) | 2–10 s |
|
||
| dotnet restore + build | project-dependent |
|
||
| Artifact collection | 2–10 s |
|
||
| VM destruction | 5–10 s |
|
||
| **Overhead total** | **~60–120 s** |
|