feat(workflow): rinomina build-nsis.yml -> build-nsInnoUnp.yml, aggiunge job release
- Rinominato gitea/workflows/build-nsis.yml in build-nsInnoUnp.yml - Aggiunto job release: scarica artifact Windows+Linux, crea release Gitea via API REST, comprime e uploada gli asset come zip (richiede secret GITEA_TOKEN) - Aggiornati tutti i riferimenti in README.md, TODO.md, plans/*.md
This commit is contained in:
@@ -120,7 +120,7 @@ Variante **Windows Server 2022**: `*WinBuild2022.ps1` + VMX `F:\CI\Templates\Win
|
||||
│ ├── actions/
|
||||
│ │ └── local-ci-build/action.yml # Composite action riusabile (wrap Invoke-CIJob.ps1)
|
||||
│ ├── workflows/
|
||||
│ │ ├── build-nsis.yml # Workflow matrix Windows+Linux per nsis-plugin-nsinnounp
|
||||
│ │ ├── build-nsInnoUnp.yml # Workflow matrix Windows+Linux per nsis-plugin-nsinnounp
|
||||
│ │ └── lint.yml # PSScriptAnalyzer su push/PR (§5.4)
|
||||
│ └── workflow-example.yml # Template generico adattabile
|
||||
│
|
||||
@@ -276,7 +276,7 @@ Aggiungi `-SkipArtifact` per job che non producono output (es. lint, test puri).
|
||||
|
||||
## Workflow Gitea
|
||||
|
||||
Il file [gitea/workflows/build-nsis.yml](gitea/workflows/build-nsis.yml) è il workflow
|
||||
Il file [gitea/workflows/build-nsInnoUnp.yml](gitea/workflows/build-nsInnoUnp.yml) è il workflow
|
||||
attivo per `Simone/nsis-plugin-nsinnounp`. Si attiva su push di tag `v*` o manualmente.
|
||||
Usa una **strategy matrix** `[windows, linux]` che esegue in parallelo su entrambi i runner.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# TODO — Local CI/CD System
|
||||
|
||||
<!-- Last updated: 2026-05-11 — Sprint 15: §7.5 DONE (Rinomina Setup-* → Install-CIToolchain-*: WinBuild2025/2022/Linux2404; tutti i riferimenti aggiornati in Prepare/Deploy/docs/README/TODO/action.yml) -->
|
||||
<!-- Sprint 14: §6.4+§6.5 DONE (build-nsis.yml matrix windows+linux via composite action; ExtraGuestEnv chain Invoke-CIJob→Invoke-RemoteBuild, Windows session inject + Linux export prefix) -->
|
||||
<!-- Sprint 14: §6.4+§6.5 DONE (build-nsInnoUnp.yml matrix windows+linux via composite action; ExtraGuestEnv chain Invoke-CIJob→Invoke-RemoteBuild, Windows session inject + Linux export prefix) -->
|
||||
<!-- Sprint 13: §6.2 Composite Action DONE (gitea/actions/local-ci-build/action.yml — inputs: build-command/artifact-source/submodules/guest-os/use-git-clone) -->
|
||||
<!-- Sprint 12: §6.1 Linux Build VM DONE (Deploy/Prepare/Setup/Transport/e2e 4xPASS — nsis7z.dll 2272 KB parity Windows) -->
|
||||
<!-- Sprint 11: §6.6 Tier-2 Toolchain DONE (Pwsh7/NSIS/CMake/Node.js/WiX/gh CLI/Sysinternals/vcpkg — Step 12 in Install-CIToolchain-WinBuild2025) -->
|
||||
@@ -56,7 +56,7 @@ _Last updated: 2026-05-11 (post Sprint 15: §7.5 DONE — Rinomina Setup-* → I
|
||||
- [x] **Gitea Server** — già in esecuzione su `http://10.10.20.11:3100` (e `https://gitea.emulab.it`)
|
||||
- [x] Runner registration token ottenuto e usato
|
||||
- [x] Create at least one test repository with `.gitea/workflows/build.yml`
|
||||
(`Simone/nsis-plugin-nsinnounp` — testato e2e, workflow in `gitea/workflows/build-nsis.yml`)
|
||||
(`Simone/nsis-plugin-nsinnounp` — testato e2e, workflow in `gitea/workflows/build-nsInnoUnp.yml`)
|
||||
- [x] Gitea Actions abilitato (runner registrato con successo)
|
||||
|
||||
- [x] **act_runner** — installato e registrato sull'host Windows
|
||||
@@ -171,7 +171,7 @@ _Last updated: 2026-05-11 (post Sprint 15: §7.5 DONE — Rinomina Setup-* → I
|
||||
## Gitea Workflow Integration
|
||||
|
||||
- [x] Copiare `gitea/workflow-example.yml` in `.gitea/workflows/build.yml` nel repo di test
|
||||
(workflow `build-nsis.yml` già presente e funzionante per `nsis-plugin-nsinnounp`)
|
||||
(workflow `build-nsInnoUnp.yml` già presente e funzionante per `nsis-plugin-nsinnounp`)
|
||||
- [x] Push commit e verificare job in Gitea Actions UI
|
||||
- [x] Verificare artifact scaricabile da Gitea dopo build riuscita
|
||||
- [x] `gitea/workflows/lint.yml` creato — PSScriptAnalyzer su push/PR che toccano `.ps1` (2026-05-09)
|
||||
@@ -506,9 +506,9 @@ Già supportato lato Gitea, basta replicare il setup.
|
||||
**Deferred**: in un home lab single-host questa funzionalità non serve. Non pianificare.
|
||||
|
||||
### 6.4 [P3] [x] Build matrix nel workflow
|
||||
File: [gitea/workflows/build-nsis.yml](gitea/workflows/build-nsis.yml).
|
||||
File: [gitea/workflows/build-nsInnoUnp.yml](gitea/workflows/build-nsInnoUnp.yml).
|
||||
|
||||
**Status**: COMPLETATO 2026-05-11 — `build-nsis.yml` riscritto con matrix strategy.
|
||||
**Status**: COMPLETATO 2026-05-11 — `build-nsInnoUnp.yml` riscritto con matrix strategy.
|
||||
|
||||
Matrix `target: [windows, linux]`, `runs-on: ${{ matrix.target }}-build`,
|
||||
`fail-fast: false`. Usa la composite action con `job-id-suffix: ${{ matrix.target }}`
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
# Build (Local CI) — pipeline per nsis-plugin-nsinnounp
|
||||
#
|
||||
# Cross-platform matrix build: runs in parallel on both windows-build (WinRM)
|
||||
# and linux-build (SSH) runners using the reusable composite action.
|
||||
# Uses: Simone/local-ci-system/.gitea/actions/local-ci-build@main
|
||||
#
|
||||
# Trigger: push su tag v*, oppure run manuale
|
||||
|
||||
name: Build (Local CI)
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
target: [windows, linux]
|
||||
fail-fast: false
|
||||
|
||||
# Runner label must match config.yaml labels: windows-build or linux-build
|
||||
runs-on: ${{ matrix.target }}-build
|
||||
|
||||
steps:
|
||||
- uses: Simone/local-ci-system/.gitea/actions/local-ci-build@main
|
||||
with:
|
||||
build-command: 'python build_plugin.py --final --dist-dir dist'
|
||||
artifact-source: 'dist'
|
||||
submodules: 'true'
|
||||
guest-os: ${{ matrix.target == 'linux' && 'Linux' || 'Windows' }}
|
||||
# SSH URL alias configured in host ~/.ssh/config — same for both runners
|
||||
repo-url: 'ssh://gitea-ci/Simone/nsis-plugin-nsinnounp.git'
|
||||
# Suffix disambiguates artifact dirs: F:\CI\Artifacts\{run_id}-{attempt}-windows
|
||||
job-id-suffix: '${{ matrix.target }}'
|
||||
artifact-name: 'nsis-plugin-nsinnounp-${{ matrix.target }}-${{ github.ref_name }}'
|
||||
|
||||
# ── Publish Gitea release with build artifacts ────────────────────────────
|
||||
# Runs only on tag pushes, after both matrix legs succeed.
|
||||
# Requires a GITEA_TOKEN secret with repo write permissions.
|
||||
release:
|
||||
needs: build
|
||||
if: github.ref_type == 'tag'
|
||||
runs-on: windows-build
|
||||
|
||||
steps:
|
||||
- name: Download Windows artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: nsis-plugin-nsinnounp-windows-${{ github.ref_name }}
|
||||
path: artifacts/windows
|
||||
|
||||
- name: Download Linux artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: nsis-plugin-nsinnounp-linux-${{ github.ref_name }}
|
||||
path: artifacts/linux
|
||||
|
||||
- name: Create Gitea release and upload assets
|
||||
shell: powershell
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
GITEA_URL: ${{ github.server_url }}
|
||||
REPO: ${{ github.repository }}
|
||||
TAG: ${{ github.ref_name }}
|
||||
run: |
|
||||
#Requires -Version 5.1
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$authHeader = @{ Authorization = "token $env:GITEA_TOKEN" }
|
||||
$apiBase = "$env:GITEA_URL/api/v1/repos/$env:REPO"
|
||||
|
||||
# Create the release (non-draft, non-prerelease)
|
||||
$releaseBody = @{
|
||||
tag_name = $env:TAG
|
||||
name = $env:TAG
|
||||
draft = $false
|
||||
prerelease = $false
|
||||
} | ConvertTo-Json
|
||||
$jsonHeaders = $authHeader + @{ 'Content-Type' = 'application/json' }
|
||||
$release = Invoke-RestMethod -Method Post -Uri "$apiBase/releases" `
|
||||
-Headers $jsonHeaders -Body $releaseBody
|
||||
$releaseId = $release.id
|
||||
Write-Host "Release created: id=$releaseId name=$($release.name)"
|
||||
|
||||
# Compress each artifact directory and upload as a release asset
|
||||
foreach ($target in @('windows', 'linux')) {
|
||||
$srcDir = "artifacts\$target"
|
||||
$zipName = "nsis-plugin-nsinnounp-$target-$env:TAG.zip"
|
||||
Compress-Archive -Path "$srcDir\*" -DestinationPath $zipName -Force
|
||||
|
||||
$uploadUrl = "$apiBase/releases/$releaseId/assets?name=$zipName"
|
||||
$uploadHeaders = $authHeader + @{ 'Content-Type' = 'application/zip' }
|
||||
$zipBytes = [System.IO.File]::ReadAllBytes(
|
||||
(Resolve-Path $zipName).ProviderPath)
|
||||
Invoke-RestMethod -Method Post -Uri $uploadUrl `
|
||||
-Headers $uploadHeaders -Body $zipBytes | Out-Null
|
||||
Write-Host "Uploaded asset: $zipName"
|
||||
}
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
# Build (Local CI) — pipeline per nsis-plugin-nsinnounp
|
||||
#
|
||||
# Cross-platform matrix build: runs in parallel on both windows-build (WinRM)
|
||||
# and linux-build (SSH) runners using the reusable composite action.
|
||||
# Uses: Simone/local-ci-system/.gitea/actions/local-ci-build@main
|
||||
#
|
||||
# Trigger: push su tag v*, oppure run manuale
|
||||
|
||||
name: Build (Local CI)
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
target: [windows, linux]
|
||||
fail-fast: false
|
||||
|
||||
# Runner label must match config.yaml labels: windows-build or linux-build
|
||||
runs-on: ${{ matrix.target }}-build
|
||||
|
||||
steps:
|
||||
- uses: Simone/local-ci-system/.gitea/actions/local-ci-build@main
|
||||
with:
|
||||
build-command: 'python build_plugin.py --final --dist-dir dist'
|
||||
artifact-source: 'dist'
|
||||
submodules: 'true'
|
||||
guest-os: ${{ matrix.target == 'linux' && 'Linux' || 'Windows' }}
|
||||
# SSH URL alias configured in host ~/.ssh/config — same for both runners
|
||||
repo-url: 'ssh://gitea-ci/Simone/nsis-plugin-nsinnounp.git'
|
||||
# Suffix disambiguates artifact dirs: F:\CI\Artifacts\{run_id}-{attempt}-windows
|
||||
job-id-suffix: '${{ matrix.target }}'
|
||||
artifact-name: 'nsis-plugin-nsinnounp-${{ matrix.target }}-${{ github.ref_name }}'
|
||||
|
||||
+12
-12
@@ -1,4 +1,4 @@
|
||||
# Final Master Plan — Local CI/CD System
|
||||
# Final Master Plan — Local CI/CD System
|
||||
|
||||
Date: 2026-05-11
|
||||
Last updated: 2026-05-12
|
||||
@@ -12,7 +12,7 @@ This is the single authoritative document for finishing v1.0 of the system. When
|
||||
|
||||
The Local CI/CD System is a well-engineered, single-host homelab CI built on Gitea Actions, act_runner v1.0.2, VMware Workstation linked clones, Windows PowerShell 5.1, WinRM HTTPS for Windows guests and SSH for Linux guests. The architecture is the right shape for the constraint set: a thin orchestrator on the host, ephemeral linked clones for isolation, two transports for two guest families, and file-based state for everything else. Both reviewers independently graded the architecture A- and operational maturity B-/C+. That matches what the source shows.
|
||||
|
||||
The system is *feature-complete* and *operator-usable*, not yet *unattended-daily-trustworthy*. The gap is small in code volume but real in operational consequence. Five concrete defects can break a live build today: the Linux matrix leg of [gitea/workflows/build-nsis.yml](../gitea/workflows/build-nsis.yml) silently selects the Windows template; Linux `ExtraGuestEnv` secrets are logged in clear text; the composite action outputs metadata is malformed YAML; the Linux Mode 2 PAT injection writes credentials into a remote command string; [Setup-Host.ps1](../Setup-Host.ps1) creates a directory layout that no longer matches the live system. None of these are architectural failures. Each is a 5-to-45-minute fix that the design otherwise supports cleanly.
|
||||
The system is *feature-complete* and *operator-usable*, not yet *unattended-daily-trustworthy*. The gap is small in code volume but real in operational consequence. Five concrete defects can break a live build today: the Linux matrix leg of [gitea/workflows/build-nsInnoUnp.yml](../gitea/workflows/build-nsInnoUnp.yml) silently selects the Windows template; Linux `ExtraGuestEnv` secrets are logged in clear text; the composite action outputs metadata is malformed YAML; the Linux Mode 2 PAT injection writes credentials into a remote command string; [Setup-Host.ps1](../Setup-Host.ps1) creates a directory layout that no longer matches the live system. None of these are architectural failures. Each is a 5-to-45-minute fix that the design otherwise supports cleanly.
|
||||
|
||||
The system makes one large unvalidated claim: `capacity: 4` in [runner/config.yaml](../runner/config.yaml). The IP-allocation mutex and lease design in [scripts/Invoke-CIJob.ps1](../scripts/Invoke-CIJob.ps1) is sound on paper, but the only evidence is single-job e2e runs. Four concurrent real builds have not been measured. This is the single most consequential outstanding question. The remediation is a burn-in, not a redesign.
|
||||
|
||||
@@ -120,15 +120,15 @@ Do not add:
|
||||
|
||||
These must be fixed before the system is trustworthy for unattended daily use. Severity *Critical* means the issue actively breaks production today.
|
||||
|
||||
### C1. Linux matrix leg of build-nsis.yml selects the Windows template
|
||||
### C1. Linux matrix leg of build-nsInnoUnp.yml selects the Windows template
|
||||
|
||||
**Description**: [gitea/workflows/build-nsis.yml](../gitea/workflows/build-nsis.yml) runs a matrix over `[windows, linux]` and dispatches on `runs-on: ${{ matrix.target }}-build`, but does NOT pass `guest-os` or `template-path` to the composite action. The action defaults `template-path` to empty, so [scripts/Invoke-CIJob.ps1](../scripts/Invoke-CIJob.ps1) reads `$env:GITEA_CI_TEMPLATE_PATH` — the Windows path. The orchestrator never reads `GITEA_CI_LINUX_TEMPLATE_PATH`. Result: the Linux leg clones `WinBuild2025` and tries to SSH into a Windows VM (or via Auto-detect, into a Windows VM with WinRM credentials), which fails or produces nonsense.
|
||||
**Description**: [gitea/workflows/build-nsInnoUnp.yml](../gitea/workflows/build-nsInnoUnp.yml) runs a matrix over `[windows, linux]` and dispatches on `runs-on: ${{ matrix.target }}-build`, but does NOT pass `guest-os` or `template-path` to the composite action. The action defaults `template-path` to empty, so [scripts/Invoke-CIJob.ps1](../scripts/Invoke-CIJob.ps1) reads `$env:GITEA_CI_TEMPLATE_PATH` — the Windows path. The orchestrator never reads `GITEA_CI_LINUX_TEMPLATE_PATH`. Result: the Linux leg clones `WinBuild2025` and tries to SSH into a Windows VM (or via Auto-detect, into a Windows VM with WinRM credentials), which fails or produces nonsense.
|
||||
|
||||
**Location**: [gitea/workflows/build-nsis.yml](../gitea/workflows/build-nsis.yml) L20-L40; [gitea/actions/local-ci-build/action.yml](../gitea/actions/local-ci-build/action.yml) L77-L83; [scripts/Invoke-CIJob.ps1](../scripts/Invoke-CIJob.ps1) L108.
|
||||
**Location**: [gitea/workflows/build-nsInnoUnp.yml](../gitea/workflows/build-nsInnoUnp.yml) L20-L40; [gitea/actions/local-ci-build/action.yml](../gitea/actions/local-ci-build/action.yml) L77-L83; [scripts/Invoke-CIJob.ps1](../scripts/Invoke-CIJob.ps1) L108.
|
||||
|
||||
**Impact**: The advertised Windows+Linux matrix workflow is broken for the Linux leg. The only evidence of "Linux works" is direct invocation of `Invoke-CIJob.ps1` with explicit `-TemplatePath`. End-to-end through the workflow has never worked for Linux.
|
||||
|
||||
**Fix**: Either (a) update the composite action to select between `GITEA_CI_TEMPLATE_PATH` and `GITEA_CI_LINUX_TEMPLATE_PATH` based on `guest-os` (or runner label inference) and similarly for snapshot name; or (b) update [gitea/workflows/build-nsis.yml](../gitea/workflows/build-nsis.yml) to pass `guest-os: ${{ matrix.target == 'linux' && 'Linux' || 'Windows' }}` plus an explicit `template-path`. Option (a) is the better one because it makes the action self-sufficient for any caller. Add an `INPUT_GUEST_OS_RESOLVED` step that selects the template-path env var, then pass it as `-TemplatePath`. Also set `BaseClean-Linux` as the snapshot name on Linux.
|
||||
**Fix**: Either (a) update the composite action to select between `GITEA_CI_TEMPLATE_PATH` and `GITEA_CI_LINUX_TEMPLATE_PATH` based on `guest-os` (or runner label inference) and similarly for snapshot name; or (b) update [gitea/workflows/build-nsInnoUnp.yml](../gitea/workflows/build-nsInnoUnp.yml) to pass `guest-os: ${{ matrix.target == 'linux' && 'Linux' || 'Windows' }}` plus an explicit `template-path`. Option (a) is the better one because it makes the action self-sufficient for any caller. Add an `INPUT_GUEST_OS_RESOLVED` step that selects the template-path env var, then pass it as `-TemplatePath`. Also set `BaseClean-Linux` as the snapshot name on Linux.
|
||||
|
||||
**Estimated effort**: 1 hour including a manual smoke test of both legs.
|
||||
|
||||
@@ -236,9 +236,9 @@ These are *High* priority items. Fix in the same stabilization pass as the Criti
|
||||
|
||||
### H8. act_runner service account vs SSH alias mismatch
|
||||
|
||||
**Description**: [Setup-Host.ps1](../Setup-Host.ps1) L294-L306 writes the `gitea-ci` SSH alias to `$env:USERPROFILE\.ssh\config` — the interactive user's profile. The NSSM install at L264-L273 does not set an explicit service account, which on Windows commonly means LocalSystem. LocalSystem's home is `C:\Windows\System32\config\systemprofile\`, not the user profile. [gitea/workflows/build-nsis.yml](../gitea/workflows/build-nsis.yml) uses `repo-url: 'ssh://gitea-ci/Simone/...'`. If the service runs as LocalSystem, the alias resolution fails and every Mode 1 (host-side clone) attempt errors out.
|
||||
**Description**: [Setup-Host.ps1](../Setup-Host.ps1) L294-L306 writes the `gitea-ci` SSH alias to `$env:USERPROFILE\.ssh\config` — the interactive user's profile. The NSSM install at L264-L273 does not set an explicit service account, which on Windows commonly means LocalSystem. LocalSystem's home is `C:\Windows\System32\config\systemprofile\`, not the user profile. [gitea/workflows/build-nsInnoUnp.yml](../gitea/workflows/build-nsInnoUnp.yml) uses `repo-url: 'ssh://gitea-ci/Simone/...'`. If the service runs as LocalSystem, the alias resolution fails and every Mode 1 (host-side clone) attempt errors out.
|
||||
|
||||
**Location**: [Setup-Host.ps1](../Setup-Host.ps1) L264-L273 (NSSM install), L294-L306 (SSH config write); [gitea/workflows/build-nsis.yml](../gitea/workflows/build-nsis.yml) L35.
|
||||
**Location**: [Setup-Host.ps1](../Setup-Host.ps1) L264-L273 (NSSM install), L294-L306 (SSH config write); [gitea/workflows/build-nsInnoUnp.yml](../gitea/workflows/build-nsInnoUnp.yml) L35.
|
||||
|
||||
**Impact**: Potentially blocks all Mode 1 host-side clone builds. Severity is HIGH-PENDING-VERIFICATION; first action is verification.
|
||||
|
||||
@@ -302,7 +302,7 @@ Every item is concrete, references a file, and ends with an effort estimate.
|
||||
|
||||
### Critical [x]
|
||||
|
||||
- [x] Fix Linux matrix template selection — [gitea/actions/local-ci-build/action.yml](../gitea/actions/local-ci-build/action.yml) + [gitea/workflows/build-nsis.yml](../gitea/workflows/build-nsis.yml) — action selects `GITEA_CI_TEMPLATE_PATH` or `GITEA_CI_LINUX_TEMPLATE_PATH` based on `guest-os` input or runner label, also resolves the correct `snapshot-name` (`BaseClean` or `BaseClean-Linux`) — done 2026-05-12.
|
||||
- [x] Fix Linux matrix template selection — [gitea/actions/local-ci-build/action.yml](../gitea/actions/local-ci-build/action.yml) + [gitea/workflows/build-nsInnoUnp.yml](../gitea/workflows/build-nsInnoUnp.yml) — action selects `GITEA_CI_TEMPLATE_PATH` or `GITEA_CI_LINUX_TEMPLATE_PATH` based on `guest-os` input or runner label, also resolves the correct `snapshot-name` (`BaseClean` or `BaseClean-Linux`) — done 2026-05-12.
|
||||
- [x] Redact Linux ExtraGuestEnv secret logging — [scripts/Invoke-RemoteBuild.ps1](../scripts/Invoke-RemoteBuild.ps1) Linux branch — replace `Write-Host "...$buildCmd"` with redacted version; never log `$envPrefix` — done 2026-05-12.
|
||||
|
||||
### High
|
||||
@@ -393,7 +393,7 @@ Goal: clear both Criticals plus the highest-impact Highs that touch production p
|
||||
|
||||
**Task 2.1 — Fix Linux matrix template selection (C1)** [x] done 2026-05-12
|
||||
- [gitea/actions/local-ci-build/action.yml](../gitea/actions/local-ci-build/action.yml): added `$resolvedGuestOS` / `$resolvedTemplatePath` / `$resolvedSnapshotName` resolution block; `Auto` infers from `$env:RUNNER_LABELS`.
|
||||
- [gitea/workflows/build-nsis.yml](../gitea/workflows/build-nsis.yml): explicit `guest-os: ${{ matrix.target == 'linux' && 'Linux' || 'Windows' }}` added as belt-and-suspenders.
|
||||
- [gitea/workflows/build-nsInnoUnp.yml](../gitea/workflows/build-nsInnoUnp.yml): explicit `guest-os: ${{ matrix.target == 'linux' && 'Linux' || 'Windows' }}` added as belt-and-suspenders.
|
||||
- Live smoke test (Task 1.4) still required.
|
||||
|
||||
**Task 2.2 — Redact Linux ExtraGuestEnv logging (C2)** [x] done 2026-05-12
|
||||
@@ -541,7 +541,7 @@ Will NOT do:
|
||||
|
||||
Concrete improvements to workflows and the composite action.
|
||||
|
||||
1. **Make the composite action self-sufficient for guest OS selection** (C1 fix). After this, [gitea/workflows/build-nsis.yml](../gitea/workflows/build-nsis.yml) does not need to pass `guest-os`, `template-path`, or `snapshot-name` for the standard Windows/Linux matrix; the action infers from the runner label or accepts the explicit input.
|
||||
1. **Make the composite action self-sufficient for guest OS selection** (C1 fix). After this, [gitea/workflows/build-nsInnoUnp.yml](../gitea/workflows/build-nsInnoUnp.yml) does not need to pass `guest-os`, `template-path`, or `snapshot-name` for the standard Windows/Linux matrix; the action infers from the runner label or accepts the explicit input.
|
||||
|
||||
2. **Add a top-level `outputs:` block** so downstream consumers can chain (H2 fix).
|
||||
|
||||
@@ -717,7 +717,7 @@ Execute in this exact order. Each phase has a single success criterion that gate
|
||||
|
||||
**Phase 1 — Validation (Sprint 1).** Verify the act_runner service account, confirm the directory inventory, run the 4-way concurrency burn-in, manually trigger the broken Linux matrix to confirm C1. Output: a section appended to [docs/RUNBOOK.md](../docs/RUNBOOK.md) titled "Validation Results 2026-05-XX" documenting findings. Gate: burn-in passed three times (keep `capacity: 4`) or was set to 2 (with reasoning recorded).
|
||||
|
||||
**Phase 2 — Critical Fixes (Sprint 2).** Fix C1 and C2, plus H2/H3/H6/H7. Manually trigger [gitea/workflows/build-nsis.yml](../gitea/workflows/build-nsis.yml) for both matrix legs after each fix. Gate: both Critical items closed and `[x]` in this plan's Critical section; both legs green in the live matrix workflow.
|
||||
**Phase 2 — Critical Fixes (Sprint 2).** Fix C1 and C2, plus H2/H3/H6/H7. Manually trigger [gitea/workflows/build-nsInnoUnp.yml](../gitea/workflows/build-nsInnoUnp.yml) for both matrix legs after each fix. Gate: both Critical items closed and `[x]` in this plan's Critical section; both legs green in the live matrix workflow.
|
||||
|
||||
**Phase 3 — High Priority Fixes (Sprint 3).** Complete the rest of the High items: H4 (bounded vmrun), H5 (stale lock), H8 (SSH alias fix), H9 (Linux validator), H10 (smoke-test workflow), H11 (script-root env var), H12 (benchmark alignment). Gate: smoke-test workflow green; all High items `[x]`.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Technical Review: Local CI/CD System
|
||||
# Technical Review: Local CI/CD System
|
||||
|
||||
Date: 2026-05-11
|
||||
|
||||
@@ -154,7 +154,7 @@ The composite action idea is excellent. A reusable [gitea/actions/local-ci-build
|
||||
|
||||
The current action has a structural YAML problem: it appears to define outputs under `inputs`, and duplicates `artifact-name`. Composite action outputs should be top-level `outputs`. As written, the `Upload artifacts` step may not receive `steps.invoke-ci.outputs.artifact-path` and `artifact-name` as intended. This can make builds succeed inside the VM but fail at artifact upload.
|
||||
|
||||
Workflow flexibility is otherwise good. [gitea/workflows/build-nsis.yml](../gitea/workflows/build-nsis.yml) uses a Windows/Linux matrix and disambiguates job IDs with `job-id-suffix`. That is the right pattern. Missing patterns: PR checks are not represented in the live workflow, scheduled builds are not represented, and dependency caching via `actions/cache` is not shown even though act_runner cache is enabled. For this system, PR checks and manual rebuild are more valuable than scheduled builds.
|
||||
Workflow flexibility is otherwise good. [gitea/workflows/build-nsInnoUnp.yml](../gitea/workflows/build-nsInnoUnp.yml) uses a Windows/Linux matrix and disambiguates job IDs with `job-id-suffix`. That is the right pattern. Missing patterns: PR checks are not represented in the live workflow, scheduled builds are not represented, and dependency caching via `actions/cache` is not shown even though act_runner cache is enabled. For this system, PR checks and manual rebuild are more valuable than scheduled builds.
|
||||
|
||||
Artifact upload to Gitea is done through `actions/upload-artifact@v4` in the composite action. The VM pipeline collects files into `F:\CI\Artifacts\<jobId>`, then upload-artifact reads that host-side directory. That is a good bridge between local VM isolation and Gitea's artifact store, once the outputs block is fixed.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Cross-Review of Opus 4.7 Analysis
|
||||
# Cross-Review of Opus 4.7 Analysis
|
||||
|
||||
Date: 2026-05-11
|
||||
|
||||
@@ -34,7 +34,7 @@ Opus claim: "The alias lives in the user's `~/.ssh/config` - which user? `act_ru
|
||||
|
||||
Verdict: partially correct and over-prioritized as written.
|
||||
|
||||
The code confirms the alias is written under the interactive user's profile: [Setup-Host.ps1](../Setup-Host.ps1#L294-L306) uses `$env:USERPROFILE\.ssh\config`. The live workflow does use the alias: [gitea/workflows/build-nsis.yml](../gitea/workflows/build-nsis.yml#L31-L35) sets `repo-url: 'ssh://gitea-ci/Simone/nsis-plugin-nsinnounp.git'`. If act_runner runs as LocalSystem, OpenSSH will not read the interactive user's SSH config or keys. That would break host-side clone mode.
|
||||
The code confirms the alias is written under the interactive user's profile: [Setup-Host.ps1](../Setup-Host.ps1#L294-L306) uses `$env:USERPROFILE\.ssh\config`. The live workflow does use the alias: [gitea/workflows/build-nsInnoUnp.yml](../gitea/workflows/build-nsInnoUnp.yml#L31-L35) sets `repo-url: 'ssh://gitea-ci/Simone/nsis-plugin-nsinnounp.git'`. If act_runner runs as LocalSystem, OpenSSH will not read the interactive user's SSH config or keys. That would break host-side clone mode.
|
||||
|
||||
The assumption that act_runner definitely runs as SYSTEM is weaker. [scripts/Register-CIScheduledTasks.ps1](../scripts/Register-CIScheduledTasks.ps1#L38-L43) says scheduled maintenance tasks run as SYSTEM; it does not install act_runner. The act_runner NSSM installation in [Setup-Host.ps1](../Setup-Host.ps1#L264-L273) does not set an explicit service account. On Windows, a service installed without an explicit account commonly runs as LocalSystem, so Opus's concern is plausible. But Opus should not have derived act_runner's identity from the scheduled-task script. The correct verification is `Get-CimInstance Win32_Service -Filter "Name='act_runner'" | Select StartName` on the host, plus a test clone under that identity.
|
||||
|
||||
@@ -118,7 +118,7 @@ Opus missed stale `vm-start.lock` cleanup. The lock handle is released correctly
|
||||
|
||||
Opus missed broken or stale test-plan commands that matter because this review is about trust. [docs/TEST-PLAN-v1.3-to-HEAD.md](../docs/TEST-PLAN-v1.3-to-HEAD.md#L56-L58) uses PS7-only `ForEach-Object -Parallel` and the wrong `-RepositoryUrl` parameter, while [scripts/Invoke-CIJob.ps1](../scripts/Invoke-CIJob.ps1#L80) defines `RepoUrl`. That makes the validation plan non-copy-pasteable on the mandated PS5.1 host.
|
||||
|
||||
Both analyses missed a likely Linux matrix wiring bug. [gitea/workflows/build-nsis.yml](../gitea/workflows/build-nsis.yml#L20-L35) runs a matrix over `windows` and `linux`, but it does not pass `guest-os`, `template-path`, or `snapshot-name`. The action defaults `guest-os` to `Auto` in [gitea/actions/local-ci-build/action.yml](../gitea/actions/local-ci-build/action.yml#L52-L57) and leaves `template-path` empty so `Invoke-CIJob.ps1` uses `GITEA_CI_TEMPLATE_PATH` in [scripts/Invoke-CIJob.ps1](../scripts/Invoke-CIJob.ps1#L114). The runner config has a separate `GITEA_CI_LINUX_TEMPLATE_PATH` in [runner/config.yaml](../runner/config.yaml#L27-L30), but the action does not consume it. Unless act_runner has per-label environment behavior not shown here, the Linux leg can clone the Windows template. This is more urgent than several Opus HIGH items because it affects the advertised Windows/Linux matrix directly.
|
||||
Both analyses missed a likely Linux matrix wiring bug. [gitea/workflows/build-nsInnoUnp.yml](../gitea/workflows/build-nsInnoUnp.yml#L20-L35) runs a matrix over `windows` and `linux`, but it does not pass `guest-os`, `template-path`, or `snapshot-name`. The action defaults `guest-os` to `Auto` in [gitea/actions/local-ci-build/action.yml](../gitea/actions/local-ci-build/action.yml#L52-L57) and leaves `template-path` empty so `Invoke-CIJob.ps1` uses `GITEA_CI_TEMPLATE_PATH` in [scripts/Invoke-CIJob.ps1](../scripts/Invoke-CIJob.ps1#L114). The runner config has a separate `GITEA_CI_LINUX_TEMPLATE_PATH` in [runner/config.yaml](../runner/config.yaml#L27-L30), but the action does not consume it. Unless act_runner has per-label environment behavior not shown here, the Linux leg can clone the Windows template. This is more urgent than several Opus HIGH items because it affects the advertised Windows/Linux matrix directly.
|
||||
|
||||
Both analyses also under-emphasized that Mode 1 host-side cloning with `ssh://gitea-ci/...` depends on host SSH identity, while Mode 2 in-guest clone for Linux should probably use HTTPS reachable from the guest plus PAT or deploy key. The test helper [scripts/Test-E2E-Section3.3.ps1](../scripts/Test-E2E-Section3.3.ps1#L113-L115) distinguishes guest HTTPS and host SSH URLs, but the composite workflow presents one `repo-url` for both matrix legs.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Local-CI-CD-System — Comprehensive Technical Review
|
||||
# Local-CI-CD-System — Comprehensive Technical Review
|
||||
|
||||
Reviewer role: lead architect / senior DevOps engineer.
|
||||
Scope: complete repository audit at HEAD.
|
||||
@@ -40,7 +40,7 @@ The system declares itself "production-ready" in `README.md` line 1. Measured ag
|
||||
| In-VM `git clone` (Mode 2) | Complete | `-UseGitClone`, PAT via `http.extraHeader` |
|
||||
| Credential storage (CredentialManager) | Complete | `BuildVMGuest`, `GiteaPAT` |
|
||||
| Reusable composite action | Complete | `gitea/actions/local-ci-build/action.yml` |
|
||||
| Build matrix Windows + Linux | Complete | `gitea/workflows/build-nsis.yml` |
|
||||
| Build matrix Windows + Linux | Complete | `gitea/workflows/build-nsInnoUnp.yml` |
|
||||
| Shared NuGet/pip cache via HGFS | Complete | `Set-TemplateSharedFolders.ps1`, `-UseSharedCache` |
|
||||
| Structured JSONL logs | Complete | `Write-JobEvent` in `Invoke-CIJob.ps1` |
|
||||
| Scheduled maintenance | Complete | `Register-CIScheduledTasks.ps1` (4 tasks) |
|
||||
@@ -112,7 +112,7 @@ This is a clean pipeline. The orchestrator is a single script that owns the try/
|
||||
### 3.2 Layering — What Is Right
|
||||
|
||||
- **`_Common.psm1` and `_Transport.psm1`** correctly separate two distinct concerns: WinRM/vmrun helpers (host-side, used by Windows path) and SSH helpers (host→guest, used by Linux path). `Invoke-Vmrun` returning `[pscustomobject]@{ExitCode, Output}` is the right abstraction — most callers want both, and `$LASTEXITCODE` is fragile across pipelines.
|
||||
- **The composite action `local-ci-build`** is the right boundary. The calling repository (`nsis-plugin-nsinnounp`, per `build-nsis.yml`) declares intent (`build-command`, `artifact-source`) and the action handles transport. Adding a second consumer would require zero changes here.
|
||||
- **The composite action `local-ci-build`** is the right boundary. The calling repository (`nsis-plugin-nsinnounp`, per `build-nsInnoUnp.yml`) declares intent (`build-command`, `artifact-source`) and the action handles transport. Adding a second consumer would require zero changes here.
|
||||
- **The file-based IP mutex + lease** is conceptually correct. Serialize the racey phase (clone + start + IP acquisition), then release. Build phases run parallel. That is the right granularity.
|
||||
- **The Mode 1 / Mode 2 source-transfer split**. Mode 1 (host clone → tar/zip → ship) is the safe default. Mode 2 (`-UseGitClone`, PAT via `http.extraHeader`) is the right optimization for large repos with submodules — and the `http.extraHeader` Basic-auth approach keeps the PAT out of the URL, argv, and `git config`.
|
||||
- **Phase 1 readiness check uses `vmrun list`, not `getGuestIPAddress`**. This is correct and the rationale in the comments of `scripts/Wait-VMReady.ps1` is exactly right. The author has clearly been burned by this in the past.
|
||||
@@ -406,7 +406,7 @@ Concerns:
|
||||
- No input validation. `inputs.guest-os` accepts any string; if a typo `'Linus'` is passed, it propagates to `Invoke-CIJob.ps1` which rejects it via `ValidateSet`. The error is clear at runtime but late. **LOW**.
|
||||
- No timeouts at the action level. Relies entirely on the runner-level `timeout: 2h` in `runner/config.yaml`. **LOW**.
|
||||
|
||||
### 8.2 The Calling Workflow `build-nsis.yml`
|
||||
### 8.2 The Calling Workflow `build-nsInnoUnp.yml`
|
||||
|
||||
- Matrix on `[windows, linux]`, `fail-fast: false`. **GOOD**.
|
||||
- `job-id-suffix: '${{ matrix.target }}'` to disambiguate the artifact directories. **GOOD** — this is exactly the right use of the suffix.
|
||||
@@ -512,7 +512,7 @@ In priority order:
|
||||
### HIGH
|
||||
|
||||
- **No automated end-to-end test**. `Measure-CIBenchmark.ps1` exists but is not wired to CI and runs without assertions. (`scripts/Measure-CIBenchmark.ps1`)
|
||||
- **`act_runner` service account vs SSH alias mismatch potential**. If runner runs as SYSTEM, the `gitea-ci` SSH alias written by `Setup-Host.ps1` lives in the wrong `~/.ssh/config`. (`Setup-Host.ps1`, `gitea/workflows/build-nsis.yml`)
|
||||
- **`act_runner` service account vs SSH alias mismatch potential**. If runner runs as SYSTEM, the `gitea-ci` SSH alias written by `Setup-Host.ps1` lives in the wrong `~/.ssh/config`. (`Setup-Host.ps1`, `gitea/workflows/build-nsInnoUnp.yml`)
|
||||
- **No CI for the CI**: Pester tests never run on commit, no integration test. (`gitea/workflows/`)
|
||||
- **Template-refresh procedure not codified**. KMS re-activation, snapshot rebuild, validation steps live in operator memory. (`docs/`, missing)
|
||||
- **`Validate-DeployState.ps1` does not assert `ci-report-ip.service` presence on Linux templates**. Silent fallback to 120 s timeout if the service is missing. (`template/Validate-DeployState.ps1`)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Cross-Review: GPT-5.5 Analysis of Local-CI-CD-System
|
||||
# Cross-Review: GPT-5.5 Analysis of Local-CI-CD-System
|
||||
|
||||
Reviewer: Claude Opus 4.7, acting as lead architect.
|
||||
Subject under review: [plans/gpt55-analysis.md](gpt55-analysis.md).
|
||||
@@ -32,7 +32,7 @@ The YAML structure issue is real. In [gitea/actions/local-ci-build/action.yml](.
|
||||
|
||||
However, GPT-5.5 escalates this to "VM build can succeed but `actions/upload-artifact` may receive empty `steps.invoke-ci.outputs.artifact-path` or `artifact-name`, causing workflow failure or missing artifacts." That part is wrong. The upload-artifact step explicitly reads `steps.invoke-ci.outputs.artifact-name` and `steps.invoke-ci.outputs.artifact-path`, which are **step-level outputs** set unconditionally in the inner PowerShell block by `"artifact-path=$artifactPath" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8`. Step-level outputs do not depend on the action having a top-level `outputs:` block. The upload works today.
|
||||
|
||||
What the missing `outputs:` block actually breaks is the **caller-facing** action interface: a downstream workflow cannot read `steps.local-ci-build.outputs.artifact-path` from outside this composite action. Since the only consumer today is [gitea/workflows/build-nsis.yml](../gitea/workflows/build-nsis.yml), which does not consume action outputs (artifact upload happens inside the composite step), the user-visible impact is zero today.
|
||||
What the missing `outputs:` block actually breaks is the **caller-facing** action interface: a downstream workflow cannot read `steps.local-ci-build.outputs.artifact-path` from outside this composite action. Since the only consumer today is [gitea/workflows/build-nsInnoUnp.yml](../gitea/workflows/build-nsInnoUnp.yml), which does not consume action outputs (artifact upload happens inside the composite step), the user-visible impact is zero today.
|
||||
|
||||
Correct severity: **HIGH** (latent breakage waiting for a second consumer), not **CRITICAL**. The fix is still trivial — sub-30 minutes — so this distinction does not change the quick-wins list. But the framing matters for trust in the report's prioritisation.
|
||||
|
||||
@@ -161,7 +161,7 @@ Out of 18 verifiable factual claims I cross-checked, 16 are correct, 1 is partia
|
||||
|
||||
What GPT-5.5 missed that my own analysis caught:
|
||||
|
||||
1. **`act_runner` service-account vs SSH alias mismatch** (my §8.2 HIGH). If [Setup-Host.ps1](../Setup-Host.ps1) installs `act_runner` as a Windows service running under `SYSTEM`, the `~/.ssh/config` alias `gitea-ci` referenced in [gitea/workflows/build-nsis.yml](../gitea/workflows/build-nsis.yml) (`repo-url: 'ssh://gitea-ci/Simone/...'`) lives in the *interactive user's* `~/.ssh/config`, not `SYSTEM`'s. This is a runtime-reachable bug: every Linux Mode 2 clone fails with "unknown host gitea-ci" until the alias is reinstalled in `C:\Windows\System32\config\systemprofile\.ssh\config`. GPT-5.5 never mentions this. It is potentially HIGH-severity and definitely worth a verification step.
|
||||
1. **`act_runner` service-account vs SSH alias mismatch** (my §8.2 HIGH). If [Setup-Host.ps1](../Setup-Host.ps1) installs `act_runner` as a Windows service running under `SYSTEM`, the `~/.ssh/config` alias `gitea-ci` referenced in [gitea/workflows/build-nsInnoUnp.yml](../gitea/workflows/build-nsInnoUnp.yml) (`repo-url: 'ssh://gitea-ci/Simone/...'`) lives in the *interactive user's* `~/.ssh/config`, not `SYSTEM`'s. This is a runtime-reachable bug: every Linux Mode 2 clone fails with "unknown host gitea-ci" until the alias is reinstalled in `C:\Windows\System32\config\systemprofile\.ssh\config`. GPT-5.5 never mentions this. It is potentially HIGH-severity and definitely worth a verification step.
|
||||
|
||||
2. **`Measure-CIBenchmark.ps1` uses `getGuestIPAddress` instead of `guestVar ci-ip`** (my §3.3, §11.3). GPT-5.5 mentions this almost as a footnote ("It still uses `getGuestIPAddress` rather than the newer `guestinfo.ci-ip` path"), but does not connect it to the larger issue: the benchmark measures a different IP-discovery path than production, so benchmark results do not represent real timing. This makes capacity-planning data unreliable.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user