Skip to content

feat(tests,bootstrap): add static tests and winget/sophia markers#6

Merged
Timpan4 merged 1 commit intomainfrom
ci-add-pester-github-actions
Jan 11, 2026
Merged

feat(tests,bootstrap): add static tests and winget/sophia markers#6
Timpan4 merged 1 commit intomainfrom
ci-add-pester-github-actions

Conversation

@Timpan4
Copy link
Copy Markdown
Owner

@Timpan4 Timpan4 commented Jan 11, 2026

  • Add static Pester tests for autounattend.xml and bootstrap.ps1 asserting:

    • bootstrap script is invoked from C:\Setup
    • execution policy is set
    • WinGet and Sophia completion markers are tracked
    • a desktop summary is created
    • a desktop shortcut is created
    • network probing via ping (1.1.1.1), Test-NetConnection, and HTTPS fallback with Invoke-WebRequest
  • Introduce Sophia and WinGet completion marker files in bootstrap.ps1 ($SophiaMarker and $WingetMarker)

  • Update WinGet install logic to:

    • skip work when a winget.completed marker exists
    • check network availability first
    • parse apps.json only when needed
    • compute missing packages before attempting installation
  • Improve idempotency and efficiency by avoiding redundant WinGet work when markers indicate completion

Summary by CodeRabbit

  • New Features

    • Added an automated Windows test workflow to run validation on push and pull requests.
  • Tests

    • Added multiple Pester-based static test suites to validate setup, bootstrap and ISO build scripts.
  • Chores

    • Made setup flows idempotent to avoid redundant actions and improved overall stability.
    • Updated project TODOs to reflect many completed tasks and testing additions.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 11, 2026

Warning

Rate limit exceeded

@Timpan4 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 5 minutes and 25 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between ce38799 and 19ab7a1.

📒 Files selected for processing (6)
  • .github/workflows/pester.yml
  • TODO.md
  • bootstrap.ps1
  • tests/Autounattend.Tests.ps1
  • tests/Bootstrap.Tests.ps1
  • tests/BuildIso.Tests.ps1
📝 Walkthrough

Walkthrough

Adds a GitHub Actions workflow to run Pester tests on Windows, makes bootstrap.ps1 idempotent via sophia.completed and winget.completed marker files, and introduces three new Pester static-check test suites for autounattend.xml, bootstrap.ps1, and build-iso.ps1.

Changes

Cohort / File(s) Summary
CI/CD Automation
.github/workflows/pester.yml
New workflow triggered on push and pull_request that checks out repo, installs the Pester module for current user, and runs Pester against the tests directory with detailed output.
Bootstrap Script (idempotency)
bootstrap.ps1
Adds $SophiaMarker and $WingetMarker variables and marker-aware logic: computes hashes, reads/writes sophia.completed and winget.completed, skips steps when markers match, executes WinGet import and Sophia preset only when needed, and updates summary accordingly.
Pester Test Suites
tests/Autounattend.Tests.ps1, tests/Bootstrap.Tests.ps1, tests/BuildIso.Tests.ps1
New static-content Pester tests: Autounattend checks for bootstrap.ps1 and Set-ExecutionPolicy; Bootstrap checks for marker names, summary/shortcut, and network call patterns; BuildIso checks Setup path references, boot image error messages, and ISO dismount cleanup.
Project Tasking
TODO.md
Multiple task items toggled to complete across Sophia Script, Bootstrap Script, ISO generation, testing, and quick-start checklist (status updates only).

Sequence Diagram

sequenceDiagram
    participant CI as GitHub Actions
    participant Bootstrap as bootstrap.ps1
    participant FS as Marker File System
    participant WinGet as winget (import)
    participant Sophia as Sophia-Preset.ps1
    participant Desktop as Desktop Assets

    CI->>Bootstrap: Trigger (push / PR) or manual run
    Bootstrap->>FS: Check `winget.completed` (and compare apps.json hash)
    alt winget marker missing or hash differs
        Bootstrap->>WinGet: Compute missing packages, create temp manifest if needed
        WinGet->>WinGet: Import packages (winget import)
        WinGet->>FS: Write `winget.completed` with apps.json hash
    else marker matches
        Bootstrap->>Bootstrap: Skip WinGet import
    end

    Bootstrap->>FS: Check `sophia.completed` (compare preset hash)
    alt sophia marker missing or hash differs
        Bootstrap->>Sophia: Execute `Sophia-Preset.ps1`
        Sophia->>FS: On success write `sophia.completed` with preset hash
    else marker matches
        Bootstrap->>Bootstrap: Skip Sophia preset
    end

    Bootstrap->>Desktop: Create `Run Windows Setup.lnk` and `Setup Summary.txt`
    Bootstrap->>CI: Exit with summary/status
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 Hop, I stitched a marker trail so neat,

winget and sophia skip repeat,
CI hums tests on Windows shore,
Pester guards the scripts we store,
A rabbit cheers — idempotence complete!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: adding static Pester tests and introducing WinGet/Sophia completion markers in bootstrap.ps1.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d8b1bc78c7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread bootstrap.ps1 Outdated
Comment thread bootstrap.ps1
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
bootstrap.ps1 (1)

93-140: Network fallback isn’t really a “fallback” on Win11, and winget import should handle spaces in temp paths.

  • Wait-ForNetwork: Invoke-WebRequest is only attempted when Test-NetConnection is missing; on Windows 11 it usually exists, so the HTTPS “fallback” path may never run.
  • winget import $tempAppsJson ... should quote or use an args array (TEMP paths can include spaces).
Proposed diff
 function Wait-ForNetwork {
@@
-        if ($canTestNetConnection) {
-            $httpsSuccess = Test-NetConnection -ComputerName $httpsHost -Port $httpsPort -InformationLevel Quiet
-            if ($httpsSuccess) {
-                Write-Log "Network connectivity confirmed via HTTPS ($httpsHost)" -Level SUCCESS
-                return $true
-            }
-        }
-        elseif ($canInvokeWebRequest) {
+        if ($canTestNetConnection) {
+            $httpsSuccess = Test-NetConnection -ComputerName $httpsHost -Port $httpsPort -InformationLevel Quiet
+            if ($httpsSuccess) {
+                Write-Log "Network connectivity confirmed via HTTPS ($httpsHost)" -Level SUCCESS
+                return $true
+            }
+        }
+
+        if ($canInvokeWebRequest) {
             try {
                 Invoke-WebRequest -Uri $httpsUri -Method Head -UseBasicParsing -TimeoutSec 5 | Out-Null
                 Write-Log "Network connectivity confirmed via HTTPS ($httpsHost)" -Level SUCCESS
                 return $true
             }
             catch {
                 # continue waiting
             }
         }
@@
-                            Write-Log "Running: winget import $tempAppsJson --accept-package-agreements --accept-source-agreements" -Level INFO
-
-                            $wingetResult = winget import $tempAppsJson --accept-package-agreements --accept-source-agreements 2>&1
+                            $wingetArgs = @(
+                                'import', $tempAppsJson,
+                                '--accept-package-agreements',
+                                '--accept-source-agreements'
+                            )
+                            Write-Log ("Running: winget {0}" -f ($wingetArgs -join ' ')) -Level INFO
+
+                            $wingetResult = winget @wingetArgs 2>&1

Also applies to: 233-279

🤖 Fix all issues with AI agents
In @bootstrap.ps1:
- Around line 299-324: The Sophia step currently relies on $LASTEXITCODE which
can be sticky and misreport script success; change the success check to use the
PowerShell automatic variable $? to determine if the invoked script
($SophiaPreset via &) succeeded, and only consult $LASTEXITCODE if $? is $false
and $LASTEXITCODE is not $null to include an explicit exit code in the warning
path. Update the conditional around the execution of & $SophiaPreset to mark
success with $? (then create the $SophiaMarker via New-Item and Add-SummaryItem
with ✓), and on failure use $LASTEXITCODE only when set to decide between
warning vs error summary messages (preserve the existing catch block for
exceptions).
🧹 Nitpick comments (4)
tests/BuildIso.Tests.ps1 (1)

1-19: Tighten the $OEM$\$1\Setup assertion and simplify escaping.
Current test only proves $1\Setup appears somewhere; adding $OEM$ reduces false positives, and single-quoted regex avoids backtick escaping noise. Based on learnings, build-iso is expected to populate the OEM setup path.

Proposed diff
 Describe "build-iso.ps1 static checks" {
     BeforeAll {
         $scriptPath = Resolve-Path (Join-Path $PSScriptRoot "..\build-iso.ps1")
         $scriptContent = Get-Content $scriptPath -Raw
     }

     It "uses $OEM$ $1 Setup path" {
-        $scriptContent | Should -Match "`\$1\\Setup"
+        $scriptContent | Should -Match '\$OEM\$\s*\\\$1\\Setup'
     }
tests/Autounattend.Tests.ps1 (1)

1-14: Consider asserting FirstLogonCommands (not just the path).
This better matches the requirement that autounattend.xml triggers bootstrap on first logon. Based on learnings, this is a key contract.

Proposed diff
 Describe "autounattend.xml static checks" {
     BeforeAll {
         $filePath = Resolve-Path (Join-Path $PSScriptRoot "..\autounattend.xml")
         $fileContent = Get-Content $filePath -Raw
     }

+    It "triggers bootstrap via FirstLogonCommands" {
+        $fileContent | Should -Match "FirstLogonCommands"
+    }
+
     It "runs bootstrap from C:\\Setup" {
         $fileContent | Should -Match "C:\\Setup\\bootstrap\.ps1"
     }
tests/Bootstrap.Tests.ps1 (1)

1-28: LGTM: static checks cover the key bootstrap contracts (markers, desktop artifacts, network checks).
If you want to reduce brittleness later, consider matching $SophiaMarker / $WingetMarker variable names in addition to raw filenames.

.github/workflows/pester.yml (1)

1-22: Use -CI flag for reliable test failure detection and pin Pester version (also add minimal permissions).
Right now CI pulls "latest Pester", which can break unexpectedly. In Pester v5, use Invoke-Pester -CI which automatically exits with non-zero on test failure—this is simpler and the officially recommended approach for CI. Pin Pester to a stable version (e.g., 5.6.1) to avoid breaking changes. Also add the permissions: contents: read block to follow least-privilege principle.

Proposed diff
 name: Pester

 on:
   push:
   pull_request:

+permissions:
+  contents: read
+
 jobs:
   pester:
     runs-on: windows-latest
     steps:
       - name: Checkout
         uses: actions/checkout@v4

       - name: Install Pester
         shell: pwsh
         run: |
-          Install-Module Pester -Force -Scope CurrentUser
+          $pesterVersion = '5.6.1'
+          Install-Module Pester -RequiredVersion $pesterVersion -Force -Scope CurrentUser
+          Import-Module Pester -RequiredVersion $pesterVersion

       - name: Run Pester tests
         shell: pwsh
         run: |
-          Invoke-Pester -Path tests -Output Detailed
+          Invoke-Pester -Path tests -Output Detailed -CI
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ea1d695 and d8b1bc7.

📒 Files selected for processing (5)
  • .github/workflows/pester.yml
  • bootstrap.ps1
  • tests/Autounattend.Tests.ps1
  • tests/Bootstrap.Tests.ps1
  • tests/BuildIso.Tests.ps1
🧰 Additional context used
📓 Path-based instructions (2)
**/*.ps1

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ps1: Do not create any PowerShell scripts (.ps1) during the planning phase
All scripts must target Windows 11 (22H2+) only; do not implement or test Windows 10 compatibility

Files:

  • tests/BuildIso.Tests.ps1
  • tests/Bootstrap.Tests.ps1
  • bootstrap.ps1
  • tests/Autounattend.Tests.ps1
bootstrap.ps1

📄 CodeRabbit inference engine (CLAUDE.md)

bootstrap.ps1: bootstrap.ps1 must be idempotent: skip already-installed apps and already-applied tweaks, and produce clear status for each step
bootstrap.ps1 must produce logs: Desktop summary at C:\Users[User]\Desktop\Setup Summary.txt and detailed log at C:\Setup\install.log
Provide a desktop shortcut to re-run bootstrap.ps1 manually

Files:

  • bootstrap.ps1
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to bootstrap.ps1 : bootstrap.ps1 must be idempotent: skip already-installed apps and already-applied tweaks, and produce clear status for each step
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to build-iso.ps1 : build-iso.ps1 must place autounattend.xml at ISO root and populate the $OEM$\$$\Setup directory with bootstrap.ps1, apps.json, and Sophia.ps1

Applied to files:

  • tests/BuildIso.Tests.ps1
  • tests/Bootstrap.Tests.ps1
  • bootstrap.ps1
  • tests/Autounattend.Tests.ps1
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to **/*.ps1 : All scripts must target Windows 11 (22H2+) only; do not implement or test Windows 10 compatibility

Applied to files:

  • tests/BuildIso.Tests.ps1
  • tests/Bootstrap.Tests.ps1
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to bootstrap.ps1 : bootstrap.ps1 must be idempotent: skip already-installed apps and already-applied tweaks, and produce clear status for each step

Applied to files:

  • tests/BuildIso.Tests.ps1
  • tests/Bootstrap.Tests.ps1
  • bootstrap.ps1
  • tests/Autounattend.Tests.ps1
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to bootstrap.ps1 : bootstrap.ps1 must produce logs: Desktop summary at C:\Users\[User]\Desktop\Setup Summary.txt and detailed log at C:\Setup\install.log

Applied to files:

  • tests/Bootstrap.Tests.ps1
  • bootstrap.ps1
  • tests/Autounattend.Tests.ps1
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to bootstrap.ps1 : Provide a desktop shortcut to re-run bootstrap.ps1 manually

Applied to files:

  • tests/Bootstrap.Tests.ps1
  • bootstrap.ps1
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to autounattend.xml : autounattend.xml must trigger bootstrap via FirstLogonCommands for automatic execution on first boot

Applied to files:

  • tests/Autounattend.Tests.ps1
🔇 Additional comments (1)
bootstrap.ps1 (1)

27-28: Good: marker files make bootstrap re-runs idempotent.
Matches the repo requirement that bootstrap.ps1 be safe to run multiple times and produce clear per-step status. Based on learnings / coding guidelines.

Comment thread bootstrap.ps1
@Timpan4 Timpan4 force-pushed the ci-add-pester-github-actions branch 2 times, most recently from 102d6bb to ce38799 Compare January 11, 2026 13:32
@Timpan4
Copy link
Copy Markdown
Owner Author

Timpan4 commented Jan 11, 2026

@codex review

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (6)
.github/workflows/pester.yml (2)

14-17: Pin the Pester module version for reproducible builds.

Installing Pester without a version constraint can lead to inconsistent test results if future Pester releases introduce breaking changes.

📌 Proposed fix to pin Pester version
       - name: Install Pester
         shell: pwsh
         run: |
-          Install-Module Pester -Force -Scope CurrentUser
+          Install-Module Pester -Force -Scope CurrentUser -MaximumVersion 5.6.1

10-17: Consider caching the Pester module installation.

Adding PowerShell module caching can speed up workflow runs by avoiding repeated downloads.

⚡ Optional enhancement to cache Pester module

Add a caching step before installing Pester:

      - name: Cache Pester module
        uses: actions/cache@v4
        with:
          path: ~\Documents\PowerShell\Modules\Pester
          key: ${{ runner.os }}-pester-${{ hashFiles('**/pester.yml') }}

      - name: Install Pester
        shell: pwsh
        run: |
          Install-Module Pester -Force -Scope CurrentUser -MaximumVersion 5.6.1
bootstrap.ps1 (4)

240-264: Consider more robust marker file reading.

The current implementation reads the marker hash with -ErrorAction SilentlyContinue, which might hide legitimate errors (e.g., permission issues). While the logic handles null/empty values correctly, distinguishing between "file doesn't exist" and "file read error" would improve diagnostics.

🔧 Optional enhancement for marker file reading
                     $appsHash = (Get-FileHash -Path $AppsJson -Algorithm SHA256).Hash
                     $markerHash = $null

                     if (Test-Path $WingetMarker) {
-                        $markerHash = (Get-Content -Path $WingetMarker -ErrorAction SilentlyContinue | Select-Object -First 1).Trim()
+                        try {
+                            $markerHash = (Get-Content -Path $WingetMarker -First 1 -ErrorAction Stop).Trim()
+                        }
+                        catch {
+                            Write-Log "WARNING: Failed to read marker file: $($_.Exception.Message)" -Level WARNING
+                            $markerHash = $null
+                        }
                     }

279-283: Add error handling for marker file write operation.

If the marker file write fails (due to permissions, disk space, etc.), the next run will unnecessarily re-install all packages. While re-installation is safe due to idempotency, logging the failure would help diagnose issues.

🛡️ Proposed fix to add error handling
                         if ($LASTEXITCODE -eq 0) {
                             Write-Log "WinGet import completed successfully" -Level SUCCESS
-                            Set-Content -Path $WingetMarker -Value $appsHash -Force
+                            try {
+                                Set-Content -Path $WingetMarker -Value $appsHash -Force -ErrorAction Stop
+                            }
+                            catch {
+                                Write-Log "WARNING: Failed to write marker file: $($_.Exception.Message)" -Level WARNING
+                            }
                             Add-SummaryItem -Step "WinGet" -Status "✓" -Message "Installed $($missingPackages.Count) packages ($WingetMarker)"

255-264: Add error handling for marker write when packages already installed.

Similar to the installation case, the marker write at line 257 lacks error handling. If this write fails, subsequent runs may produce inconsistent status messages.

🛡️ Proposed fix to add error handling
                     if ($missingPackages.Count -eq 0) {
                         Write-Log "All WinGet packages already installed" -Level SUCCESS
-                        Set-Content -Path $WingetMarker -Value $appsHash -Force
+                        try {
+                            Set-Content -Path $WingetMarker -Value $appsHash -Force -ErrorAction Stop
+                        }
+                        catch {
+                            Write-Log "WARNING: Failed to write marker file: $($_.Exception.Message)" -Level WARNING
+                        }

                         if ($markerHash -and $markerHash -eq $appsHash) {

311-346: Apply consistent error handling to Sophia marker operations.

The Sophia Script marker logic has the same robustness concerns as the WinGet marker:

  1. Marker file reading (line 315) uses -ErrorAction SilentlyContinue which might hide errors
  2. Marker file writing (line 335) lacks error handling
🛡️ Proposed fix for consistent marker error handling
         $presetHash = (Get-FileHash -Path $SophiaPreset -Algorithm SHA256).Hash
         $markerHash = $null

         if (Test-Path $SophiaMarker) {
-            $markerHash = (Get-Content -Path $SophiaMarker -ErrorAction SilentlyContinue | Select-Object -First 1).Trim()
+            try {
+                $markerHash = (Get-Content -Path $SophiaMarker -First 1 -ErrorAction Stop).Trim()
+            }
+            catch {
+                Write-Log "WARNING: Failed to read Sophia marker: $($_.Exception.Message)" -Level WARNING
+                $markerHash = $null
+            }
         }

         if ($markerHash -and $markerHash -eq $presetHash) {
             Write-Log "Sophia Script already applied; skipping" -Level INFO
             Add-SummaryItem -Step "Sophia" -Status "✓" -Message "Already applied ($SophiaMarker)"
         }
         else {
             if ($markerHash) {
                 Write-Log "Sophia preset changed since last run; reapplying" -Level INFO
             }

             try {
                 Write-Log "Found Sophia preset at $SophiaPreset" -Level INFO
                 Write-Log "Executing Sophia Script..." -Level INFO

                 & $SophiaPreset

                 if ($LASTEXITCODE -eq 0 -or $null -eq $LASTEXITCODE) {
                     Write-Log "Sophia Script execution completed" -Level SUCCESS
-                    Set-Content -Path $SophiaMarker -Value $presetHash -Force
+                    try {
+                        Set-Content -Path $SophiaMarker -Value $presetHash -Force -ErrorAction Stop
+                    }
+                    catch {
+                        Write-Log "WARNING: Failed to write Sophia marker: $($_.Exception.Message)" -Level WARNING
+                    }
                     Add-SummaryItem -Step "Sophia" -Status "✓" -Message "Sophia preset applied ($SophiaMarker)"
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d8b1bc7 and ce38799.

📒 Files selected for processing (6)
  • .github/workflows/pester.yml
  • TODO.md
  • bootstrap.ps1
  • tests/Autounattend.Tests.ps1
  • tests/Bootstrap.Tests.ps1
  • tests/BuildIso.Tests.ps1
🚧 Files skipped from review as they are similar to previous changes (3)
  • tests/Autounattend.Tests.ps1
  • tests/BuildIso.Tests.ps1
  • tests/Bootstrap.Tests.ps1
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ps1

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ps1: Do not create any PowerShell scripts (.ps1) during the planning phase
All scripts must target Windows 11 (22H2+) only; do not implement or test Windows 10 compatibility

Files:

  • bootstrap.ps1
bootstrap.ps1

📄 CodeRabbit inference engine (CLAUDE.md)

bootstrap.ps1: bootstrap.ps1 must be idempotent: skip already-installed apps and already-applied tweaks, and produce clear status for each step
bootstrap.ps1 must produce logs: Desktop summary at C:\Users[User]\Desktop\Setup Summary.txt and detailed log at C:\Setup\install.log
Provide a desktop shortcut to re-run bootstrap.ps1 manually

Files:

  • bootstrap.ps1
{README.md,TODO.md,RESEARCH.md,SECURITY.md,CLAUDE.md,docs/**/*.md}

📄 CodeRabbit inference engine (CLAUDE.md)

All documentation must assume Windows 11 (22H2+) only and explicitly exclude Windows 10 support

Files:

  • TODO.md
🧠 Learnings (6)
📓 Common learnings
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to bootstrap.ps1 : bootstrap.ps1 must be idempotent: skip already-installed apps and already-applied tweaks, and produce clear status for each step
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to build-iso.ps1 : build-iso.ps1 must place autounattend.xml at ISO root and populate the $OEM$\$$\Setup directory with bootstrap.ps1, apps.json, and Sophia.ps1
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to bootstrap.ps1 : bootstrap.ps1 must be idempotent: skip already-installed apps and already-applied tweaks, and produce clear status for each step

Applied to files:

  • bootstrap.ps1
  • TODO.md
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to bootstrap.ps1 : bootstrap.ps1 must produce logs: Desktop summary at C:\Users\[User]\Desktop\Setup Summary.txt and detailed log at C:\Setup\install.log

Applied to files:

  • bootstrap.ps1
  • TODO.md
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to bootstrap.ps1 : Provide a desktop shortcut to re-run bootstrap.ps1 manually

Applied to files:

  • bootstrap.ps1
  • TODO.md
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to build-iso.ps1 : build-iso.ps1 must place autounattend.xml at ISO root and populate the $OEM$\$$\Setup directory with bootstrap.ps1, apps.json, and Sophia.ps1

Applied to files:

  • bootstrap.ps1
  • TODO.md
📚 Learning: 2025-10-02T09:50:23.485Z
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to autounattend.xml : autounattend.xml must trigger bootstrap via FirstLogonCommands for automatic execution on first boot

Applied to files:

  • TODO.md
🔇 Additional comments (4)
bootstrap.ps1 (1)

27-28: LGTM! Marker paths properly defined.

The marker file paths are correctly constructed and stored in the C:\Setup directory alongside other setup files, supporting the idempotency requirements.

Based on learnings, this aligns with the requirement that bootstrap.ps1 must be idempotent.

TODO.md (3)

46-47: Documentation accurately reflects implementation.

The error handling for Sophia Script execution is properly implemented in bootstrap.ps1 (lines 327-345) with try-catch blocks and appropriate logging.


67-76: Bootstrap Script task completions look accurate.

The marked completions for idempotent WinGet/Sophia flows, marker tracking, desktop assets, network checks, and logging align with the implementation in bootstrap.ps1.

Based on learnings, these completions correctly reflect the idempotency requirements.


143-147: Consider updating Pester tests task status.

Line 147 shows "Add Pester smoke tests for scripts" as incomplete, but this PR introduces a Pester workflow (.github/workflows/pester.yml) and test suites referenced in the AI summary. Consider marking this task as complete or updating it to reflect the current implementation status.

⛔ Skipped due to learnings
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to bootstrap.ps1 : bootstrap.ps1 must be idempotent: skip already-installed apps and already-applied tweaks, and produce clear status for each step
Learnt from: CR
Repo: Timpan4/declarative-windows PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-02T09:50:23.485Z
Learning: Applies to bootstrap.ps1 : bootstrap.ps1 must produce logs: Desktop summary at C:\Users\[User]\Desktop\Setup Summary.txt and detailed log at C:\Setup\install.log

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ce3879971e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/BuildIso.Tests.ps1 Outdated
@Timpan4 Timpan4 force-pushed the ci-add-pester-github-actions branch 2 times, most recently from ae2f26e to a5263b5 Compare January 11, 2026 13:46
Add static Pester tests for autounattend.xml and bootstrap.ps1 to assert
that the bootstrap script is invoked from C:\Setup, execution policy is set,
WinGet and Sophia completion markers are tracked, a desktop summary is
created, and desktop shortcut is created. The bootstrap tests also check
network probing via ping (1.1.1.1), Test-NetConnection and HTTPS fallback
with Invoke-WebRequest.

Introduce Sophia and WinGet completion marker files in bootstrap.ps1
($SophiaMarker and $WingetMarker). Update WinGet install logic to skip
work when a winget.completed marker exists, and reorganize the branch to
first check for network availability, parse apps.json only when needed,
and compute missing packages before attempting installation.

These changes improve test coverage for static expectations and make the
bootstrap flow idempotent and more efficient by avoiding redundant WinGet
work when markers indicate completion.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant