Commit Graph

26 Commits

Author SHA1 Message Date
Simone 364c51b448 perf(template): NSIS download use WebClient instead of IWR (no progress-bar overhead) 2026-05-11 20:44:50 +02:00
Simone 1ad9b4dd4f fix(template): NSIS download fix meta-refresh regex to match downloads.sf.net token URL 2026-05-11 20:38:36 +02:00
Simone 133701dd60 fix(template): NSIS download browser User-Agent + PE magic bytes guard 2026-05-11 20:32:55 +02:00
Simone 1b4c3be3f5 chore(template): bump PS7 7.6.1, NSIS 3.12, gh CLI 2.92.0 2026-05-11 20:29:23 +02:00
Simone 5c1a197559 refactor(template): promote PS7/NSIS/gh CLI from Tier-2 to Tier-1 (Step 11) 2026-05-11 20:26:06 +02:00
Simone 1bf7c2347b feat(template): add -SkipTier2 switch to skip Tier-2 toolchain installation
Setup-WinBuild2025.ps1:
  - New [switch] \ param (after \)
  - Step 12 block wrapped with if (\) { skip-message } else { ... }
  - Final gate Tier-2 Assert-Step wrapped with if (-not \)

Prepare-WinBuild2025.ps1:
  - New [switch] \ param forwarded to Setup via setupArgs

Validate-SetupState.ps1:
  - New [switch] \ param
  - \ passed into both remote scriptblocks via -ArgumentList
  - Tier-2 Chk calls guarded with if (-not \) in both blocks
2026-05-11 20:13:58 +02:00
Simone 987b36ff3f feat(template): §6.6 Tier-2 toolchain PS7/NSIS/CMake/Node.js/WiX/gh CLI/Sysinternals/vcpkg
Step 12 in Setup-WinBuild2025.ps1 installs all 8 Tier-2 tools:
  - PowerShell 7.4.7 LTS (pwsh.exe)
  - NSIS 3.10 (makensis.exe)
  - CMake 3.31.6 (cmake.exe)
  - Node.js 22.14.0 LTS (node.exe + npm)
  - WiX 4.0.5 via dotnet tool (wix.exe, C:\BuildTools\Wix\)
  - GitHub CLI 2.67.0 (gh.exe)
  - Sysinternals Suite (C:\BuildTools\Sysinternals\, extracted via 7-Zip)
  - vcpkg HEAD shallow clone + bootstrap (C:\BuildTools\vcpkg\)

All tools added to Machine PATH; idempotent (binary-presence check).
Hash entries in \ ready for SHA256 pinning.
knownTempFiles extended; Final gate Assert-Step added for all 8 binaries.

Prepare-WinBuild2025.ps1: 7 new params + pass-through to Setup.
Validate-SetupState.ps1: Tier-2 checks in both main + re-run scriptblocks.
TODO.md: §6.6 [~] -> [x], Sprint 11 summary.
2026-05-11 20:04:50 +02:00
Simone 6b2a23b8f9 chore: Bump 7-Zip 24.07→26.01, Git 2.47→2.54 across docs + setup
Setup-WinBuild2025.ps1: default SevenZipVersion '24.07' → '26.01'
TODO.md: Tier-1 table + bullet list updated to current versions
TEST-PLAN: expected version strings and checklist updated

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 22:32:26 +02:00
Simone e2f1f8b1ea fix(template): Add 7-Zip to machine PATH registry (not just session PATH)
Root cause: Assert-Step 'Final' 'dotnet/python/msbuild' block contains a
registry PATH refresh that overwrites $env:PATH, discarding the temporary
session injection added in §6.6. Next assertion (7z command available) then fails.

Fix: use SetEnvironmentVariable('PATH', ..., 'Machine') to permanently register
C:\Program Files\7-Zip in the system PATH — same pattern used for dotnet and MSBuild.
Follow-up registry refresh ensures $env:PATH is also current.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 21:50:48 +02:00
Simone 0fd931d6a9 fix(template): Fix Git skip path + 7-Zip PATH injection
Two root causes:
1. Git skip check used C:\BuildTools\Git but Git installs to
   C:\Program Files\Git (default). Changed $gitDir to correct path.

2. 7-Zip MSI does not register in system PATH. Registry refresh
   (GetEnvironmentVariable Machine+User) was picking up empty result.
   Fixed: inject sevenZipDir directly into $env:PATH if not present.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 21:42:29 +02:00
Simone c9a9d57b9c fix(template): Always refresh PATH after git/7z check, not just after install
PATH refresh was inside the 'else' block (only during fresh install).
If tools already exist from previous run, PATH not refreshed → validation fails.

Move PATH refresh outside if/else for both Git and 7-Zip:
- Already installed: skip download+install, but refresh PATH anyway
- Fresh install: download+install, then refresh PATH

Ensures validations can always resolve git/7z commands, even on retry runs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 21:35:06 +02:00
Simone a981be62f4 fix(template): Refresh PATH after 7-Zip MSI installation
7-Zip MSI installer adds to system PATH but PowerShell session doesn't
see it until PATH is refreshed. Refresh via:
  $env:PATH = [System.Environment]::GetEnvironmentVariable('PATH', 'Machine') + ';' +
              [System.Environment]::GetEnvironmentVariable('PATH', 'User')

Same pattern already used for Git installer. Fixes validation error:
  '7z command resolvable' now passes after installation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 21:29:59 +02:00
Simone 3283109bed fix(template): Handle Git version tag vs filename mismatch
GitHub release tag: v2.54.0.windows.1
Filename in release: Git-2.54.0-64-bit.exe (no .windows.1)

Extract base version for filename via regex:
  $gitVersionBase = $GitVersion -replace '\.windows\.\d+$', ''

URL now correctly formed as:
  .../download/v2.54.0.windows.1/Git-2.54.0-64-bit.exe

Reverted GitVersion back to '2.54.0.windows.1' (needed for tag).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 21:26:00 +02:00
Simone c6b0957865 fix(template): Correct Git version to 2.54.0 (no .windows.1 suffix)
GitHub release tag is v2.54.0, not v2.54.0.windows.1.
Filename format: Git-2.54.0-64-bit.exe

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 21:25:29 +02:00
Simone be0a5dd065 fix(template): Update Git for Windows to 2.54.0 + add SHA256 hash
Version 2.47.0.windows.1 no longer available on GitHub (network errors).
Updated to latest stable 2.54.0.windows.1 with SHA256 hash pinning (§1.3).

Hash: 2b96e7854f0520f0f6b709c21041d9801b1be44d5e1a0d9fa621b2fbc40f1983
Source: https://github.com/git-for-windows/git/releases

This fixes download failures in Setup-WinBuild2025 Step 11 (Tier-1 Toolchain).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 21:24:18 +02:00
Simone 971d3dc6e9 feat(template): Add Step 11 Tier-1 Toolchain — Git + 7-Zip installation
Implement §6.6 minimal viable product: install Git for Windows and 7-Zip
to the template VM. Critical prerequisites for §3.3 (In-VM Git clone).

Step 11 additions:
- Git for Windows (latest LTS configurable) — silent installer, adds to PATH
- 7-Zip (latest stable configurable) — MSI installer to Program Files
- SHA256 hash pinning for both tools (currently unpinned, warn at runtime)
- Assert-Step validation for git/7z command availability
- Final pre-snapshot gate checks for both tools + cleanup of installers

Parameters added:
- -GitVersion (default: 2.47.0.windows.1)
- -SevenZipVersion (default: 24.07)

Rationale:
- Enables §3.3 in-VM Git clone (git clone directly in VM instead of host-zip-transfer)
- Supports cross-platform builds and multi-tool workflows
- Fallback from §3.2 7-Zip compression finally available in template
- Positions for future expansion of Tier-1 tools (NSIS, CMake, Node.js, WiX, etc.)

Updated documentation:
- Setup-WinBuild2025.ps1 docstring: Step 11 added to list + step ordering rationale
- Removed NOTE about Git not being installed
- Final validation now checks: 9 assertions (was 7)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 20:48:43 +02:00
Simone 8b54ca01b3 feat(setup): Step 3b — Windows KMS activation via slmgr /skms + /ato
Activates Windows against kms8.msguides.com before Windows Update runs
so WU sees correct license state. Uses cscript //NoLogo to route slmgr
output to stdout (dialogs hang in WinRM sessions). Best-effort: activation
failure emits a warning but does not abort Setup — CI builds function
within the grace period.

Placed between Step 3 (WinRM/network confirmed) and Step 4 (user creation).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 17:27:23 +02:00
Simone d63611f78e fix(setup): $sdFiles.Count null-dereference under StrictMode — wrap in @()
$sdFiles is $null when SoftwareDistribution\Download is empty. StrictMode
throws on $null.Count. @($sdFiles).Count safely returns 0 for null.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 17:20:26 +02:00
Simone ee7f406f2a fix(setup): Measure-Object .Sum null-dereference under Set-StrictMode -Version Latest
PS 5.1 treats GenericMeasureInfo.Sum as absent (not null) when the input pipe
is empty. StrictMode throws 'property Sum cannot be found'. Replace Measure-Object
with an explicit foreach loop for SoftwareDistribution size reporting.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 17:17:41 +02:00
Simone edce871644 fix(setup): defeat WaaSMedicSvc wuauserv healing + AutoAdminLogon Final gate
Two persistent Validate-SetupState failures despite §7.4 fixes:

1. wuauserv — Setup's Assert-Steps pass at exit but WaaSMedicSvc (tamper-protected,
   cannot be disabled) polls SCM ~30-60s and resets StartType to Manual.
   Fix: write Start=4 directly to registry key (SCM API alone is overrideable);
   deny WaaSMedicSvc write access to wuauserv registry key via ACL (best-effort,
   non-fatal if WinRM session lacks permission); re-enforce Start=4 after DISM
   in Cleanup; add Pre-Final re-affirmation block before Final gate.

2. AutoAdminLogon — Step 5c re-affirms it mid-script, but Steps 7-10 take hours
   and no Final gate check catches a late reset. Fix: add Pre-Final re-affirmation
   block (same as wuauserv) + add Assert-Step 'Final' 'AutoAdminLogon=1' to Final gate.

Also update WinISO default path to April 2026 refresh ISO.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 16:56:28 +02:00
Simone 68cde01c9d security(sprint1): §1.1/1.3/1.4 — WinRM HTTPS/5986, SHA256 pinning infra, IP regex per-octet
§1.4 — Replace loose IP ValidatePattern with per-octet regex in 4 scripts
  (Invoke-CIJob, Invoke-RemoteBuild, Get-BuildArtifacts, Wait-VMReady)

§1.1 — Migrate all WinRM connections from HTTP/5985 to HTTPS/5986
  - Deploy post-install.ps1: remove AllowUnencrypted=true; self-signed cert + HTTPS listener
    already present; firewall rule restricted to 192.168.79.0/24
  - Setup-WinBuild2025.ps1: assert AllowUnencrypted=false
  - Prepare-WinBuild2025.ps1: preflight uses TCP/5986; Test-WSMan -UseSSL -Port 5986;
    New-PSSession -UseSSL -Port 5986; host AllowUnencrypted save/restore removed (not needed for HTTPS)
  - Invoke-RemoteBuild, Get-BuildArtifacts: New-PSSession -UseSSL -Port 5986 -Authentication Basic
  - Wait-VMReady: New-WSManSessionOption + Test-WSMan -Port 5986 -UseSSL
  - Validate-DeployState, Validate-SetupState: Invoke-Command -UseSSL -Port 5986,
    AllowUnencrypted check → false; AllowUnencrypted host-side removed from both
  - Docs: PLAN, README, ARCHITECTURE, BEST-PRACTICES, HOST-SETUP, WINDOWS-TEMPLATE-SETUP,
    LINUX-TEMPLATE-SETUP, TODO updated

§1.3 — SHA256 hash pinning infrastructure
  - Assert-Hash function + $script:Hashes hashtable added to Setup-WinBuild2025.ps1
  - Assert-Hash called after dotnet-install.ps1, python installer, vs_buildtools.exe downloads
  - Hashes initialized to '' (warn-skip); must be filled before next snapshot refresh

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 14:46:41 +02:00
Simone 41611d46a7 fix(template): §7.4 Validate-SetupState -Remediate flag + Setup/Deploy tweaks 2026-05-10 14:26:35 +02:00
Simone 7d6ae42fcf fix(template): §7.4 e2e fixes + autologin + validation scripts
Fix emerged during §7.4 e2e test run (2026-05-10):
- Deploy: set UsoSvc to Manual explicitly (Server 2025 default = Automatic)
- Setup cleanup: re-apply Set-Service Disabled on wuauserv/UsoSvc after DISM
  StartComponentCleanup (WaaSMedicSvc resets StartType during component store cleanup)
- Deploy + Setup: add Administrator autologin (AutoAdminLogon, DefaultUserName,
  DefaultPassword, DefaultDomainName) in post-install.ps1; Assert-Step 5c validates it
- Add Validate-DeployState.ps1: standalone host-side check of all Deploy-set state
- Add Validate-SetupState.ps1: standalone host-side check of full post-Setup state
- Mark §7.4, §7.1 and §7.2 e2e validation items as complete in TODO.md
- Update docs: WINDOWS-TEMPLATE-SETUP.md (arch table, validation scripts section,
  autologin in confine Deploy/Setup); TEST-7.4-e2e.md checklist marked done

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 11:30:11 +02:00
Simone 260e275b89 refactor(template): §7 — move OS hardening to Deploy, Setup becomes validation-only
§7.1 — Setup Steps 1/3/4b/5b/5c converted to Assert-Step only:
  - Deploy post-install.ps1 now owns: Firewall (all profiles disabled),
    WinRM MaxMemory=2048MB/IdleTimeout=2h/MaxProcesses=25/StartupType=Automatic,
    lock screen (NoLockScreen), SM GPO policy key + scheduled task disable,
    DisableCAD in Winlogon, OOBE non-policy key.
  - Setup no longer re-applies these — validates them, throws if Deploy missed any.

§7.2 — WU lifecycle Strategy B:
  - Deploy: replaces sc.exe disable with GPO locks only (NoAutoUpdate=1,
    DisableWindowsUpdateAccess=1); services remain Manual (Windows default).
  - Setup Step 6 Step A already clears these locks before COM API; Step 6b
    permanently disables services post-update. No Setup changes needed.

§7.3 — Docs updated:
  - Deploy .DESCRIPTION reflects full hardening ownership.
  - Setup .DESCRIPTION marks validation-only steps, updates step ordering rationale.
  - WINDOWS-TEMPLATE-SETUP.md: three-script architecture table, CI-WinBuild.vmx
    path, Fase C step list + rationale + validation table updated.

TODO: §7.1/7.2/7.3 marked done. §7.4 e2e pending (requires new VM snapshot).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 01:27:29 +02:00
Simone ab636a0ec1 refactor(template): Defender validation-only + auto WU-reboot loop in Prepare
Setup-WinBuild2025.ps1 (Step 2):
- Defender is now disabled at deploy time by Deploy-WinBuild2025.ps1 via
  DisableAntiSpyware=1 GPO + RTP off during unattended install.
- Step 2 reduced to a single Assert-Step sanity check (GPO key present = 1).
  Exclusion paths removed: scanner is not running, they would be moot.

Prepare-WinBuild2025.ps1 (Setup invocation):
- Replace one-shot Invoke-Command + manual 're-run with -SkipWindowsUpdate'
  message with an automated loop (max 10 iterations):
  * Invoke-GuestSetup helper runs Setup inside the VM and returns exit code.
  * Exit 3010 (ERROR_SUCCESS_REBOOT_REQUIRED) triggers Restart-Computer on
    the guest, waits for WinRM via Wait-GuestWinRMReady (20 min timeout),
    reopens PSSession and loops.
  * Exit 0 breaks the loop; any other code throws immediately.
  * Hard cap prevents infinite loops if WU never converges.
2026-05-10 01:01:30 +02:00
Simone 644258f59c refactor(template): rename Setup-TemplateVM.ps1 -> Setup-WinBuild2025.ps1
- git mv Setup-TemplateVM.ps1 Setup-WinBuild2025.ps1
- git mv Prepare-TemplateSetup.ps1 -> Prepare-WinBuild2025.ps1 (name already in place)
- Updated all references across the workspace:
    template/Prepare-WinBuild2025.ps1 (script copy, assertions, comments)
    template/Setup-WinBuild2025.ps1 (self-references in docblock and final message)
    README.md (directory tree)
    TODO.md (all inline links and task descriptions)
    docs/WINDOWS-TEMPLATE-SETUP.md (table, step descriptions, phase header, troubleshooting)
    docs/LINUX-TEMPLATE-SETUP.md (Windows equivalent reference)
2026-05-09 23:28:36 +02:00