Ci/pester v5 coverage re-branching after history re-write - #2
Closed
scweeks wants to merge 74 commits into
Closed
Conversation
…effort step; docs: update changelog and PR template
…to maintain, and easier to read.
…oving safety and performance.
… up into the different phases as much as possible and keeping functions that are used by all in NetClean.psm1.
Additional disclosures
Parameterize the Pester command-coverage floor and set CI overall coverage to 69 percent while retaining the 95 percent changed-file and long-term targets. Document the measured 69.07 percent baseline, adapter and privacy verification behavior, conditional DNS/ARP evidence, restricted backup ACLs, and the associated changelog entries.
Pin the latest stable Pester release across CI, the coverage runner, and contributor documentation. Rebaseline the profiler-based overall coverage ratchet at 68 percent against the measured 68.43 percent result while retaining the 95 percent changed-file target. Make the module integration container self-contained for Pester 6 discovery, reject test files as coverage sources, and make discovery or container failures fatal. Keep experimental parallel execution out of authoritative CI and coverage runs. Validated 251 tests under PowerShell 7 and Windows PowerShell 5.1, an isolated 251-test parallel trial, 3,351 of 4,897 covered production commands, and a clean PSScriptAnalyzer 1.25.0 run across 23 targets.
Exercise real Registry-provider detection, native backup, protected cleanup, and independent post-state verification against synthetic Pester TestRegistry data. Add a private validated registry-root seam, fix reg.exe export quoting for paths containing spaces, include System tests in CI, and ratchet production command coverage to 69%.
Add a Phase 4 verification failure matrix for registry and user artifacts, event logs, DNS and ARP caches, and physical-adapter discovery. Preserve fail-soft registry discovery while allowing post-state verification to surface provider failures, and tolerate physical adapter objects without InterfaceIndex. Raise and align the production-only coverage ratchet from 69% to 71% after reaching 71.29%, with tests excluded from measurement.
Exercise Security Center products, services, drivers, uninstall records, adapters, PnP devices, service registry evidence, file metadata, and registry correlations that define protected components. Allow empty metadata paths to reach the existing fail-soft guard and add complex inventory tests for services, drivers, adapter GUIDs, registry keys, filters, categories, and confidence. Raise and align the production-only coverage ratchet from 71% to 80% after reaching 80.17%, with tests excluded from measurement.
Add functional contracts for menus, confirmation, detect/protect/clean/verify summaries, previews, Preview routing, live backup creation, and mocked dry or live power actions. Make launcher settings explicitly script-scoped, permit empty summary collections, and correct invalid yes/no feedback that used an unsupported Write-Verbose parameter. Keep performance-tuning selection out of this slice and raise the production-only coverage ratchet from 80% to 85% after reaching 85.56%.
Exercise Phase 3 cleanup failure ledgers, Quad9/adapter error handling, and Phase 4 fail-closed verification paths. Harden sparse evidence and empty-context handling under strict mode, and remove fully traced private compatibility wrappers with no repository or export consumers. Raise the overall coverage ratchet from 85% to 90% after reaching 92.05% production command coverage with 363 passing tests on PowerShell 7 and Windows PowerShell 5.1; PSScriptAnalyzer reports zero findings.
Expand Pester 6 coverage across protection discovery, workflow orchestration, registry export validation, cleanup failure handling, and sparse verification ledgers. Preserve vendor inference when file metadata is incomplete and normalize exported Wi-Fi profile basenames used by workflow verification. Raise the overall CI coverage ratchet from 90 to 94 percent after measuring 95.09 percent production command coverage, while retaining the 95 percent changed-file target and excluding tests from coverage. Validated 387 tests on PowerShell 7 and Windows PowerShell 5.1, the module manifest, and PSScriptAnalyzer 1.25.0 with zero findings across 24 targets.
Retry only transient PSScriptAnalyzer null-reference failures once while keeping repeated failures, other exceptions, and findings fatal. Add focused regression tests for the retry boundary. Run the complete suite in a parallel Windows PowerShell 5.1 job and pin workflow actions to immutable Node.js 24 releases. Temporarily remove performance tuning from the interactive menu while preserving explicit mode compatibility, and update tests and project documentation.
Treat Workplace registration as preserved user-level SSO unless independent domain, Entra join, enterprise join, or MDM evidence exists. Keep security, VPN, and virtual-adapter protection boundaries intact. Document and test the narrow Explorer-history and network-event-log cleanup allowlists so identity, token, credential, BrokerPlugin, and account stores remain out of scope. Capture netsh Wi-Fi profile output as UTF-8 and restore the caller encoding so non-ASCII SSID names render correctly across PowerShell hosts.
There was a problem hiding this comment.
Pull request overview
This PR restructures NetClean’s test/CI toolchain around Pester 6 + PSScriptAnalyzer, adds extensive regression/unit/system/functional coverage (including managed-device detection and protection/backup behaviors), and updates project docs/workflows to match the newer phase-oriented module layout.
Changes:
- Add a comprehensive Pester 6 test suite across Unit/Integration/Functional/System layers and introduce a dedicated coverage runner with enforced minimum coverage.
- Replace the legacy single-module/test setup with phase-oriented implementation (notably Phase 2 protect/backup helpers) and updated analyzer runner behavior.
- Update CI workflows, repo docs, and contribution guidance to codify the new quality gates (analyzer clean + coverage ratchet + compatibility job).
Reviewed changes
Copilot reviewed 34 out of 35 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Unit/NetClean.Safety.Unit.Tests.ps1 | Adds safety regression coverage for protected registry boundaries and dry-run backup behavior. |
| tests/Unit/NetClean.Phase2.Unit.Tests.ps1 | Adds unit coverage for Phase 2 protection/backup exports (Wi-Fi, registry, firewall, manifest). |
| tests/Unit/NetClean.Phase1.Unit.Tests.ps1 | Adds extensive unit coverage for Phase 1 detection (evidence sources, inventory correlation, sanitizable artifacts). |
| tests/Unit/NetClean.Coverage.Unit.Tests.ps1 | Adds tests asserting coverage runner and CI workflow gating/pinning behaviors. |
| tests/Unit/NetClean.Core.Unit.Tests.ps1 | Adds unit coverage for core helpers (registry path conversions, GUID normalization, IO seams, native capture). |
| tests/Unit/NetClean.Analyzer.Unit.Tests.ps1 | Adds unit coverage for analyzer runner retry/fail-closed behavior. |
| tests/System/NetClean.Registry.System.Tests.ps1 | Adds isolated system-component registry tests using Pester’s TestRegistry drive. |
| tests/Run-NetClean-Coverage.ps1 | Introduces a Pester 6 coverage runner with minimum coverage enforcement and test-path exclusion. |
| tests/Netclean.Tests.ps1 | Removes legacy Pester v5-era monolithic tests. |
| tests/Invoke-NetCleanAnalyzer.ps1 | Adds a fail-closed analyzer runner with targeted retry for transient NullReferenceException. |
| tests/Integration/NetClean.Script.Integration.Tests.ps1 | Adds integration tests for dot-sourcing the launcher script and launcher function surface. |
| tests/Integration/NetClean.Module.Integration.Tests.ps1 | Adds integration tests for manifest validity and expected exports/aliases. |
| tests/Functional/NetClean.Workflow.Functional.Tests.ps1 | Adds functional workflow contract tests for modes, timings, summaries, and option pass-through. |
| tests/Functional/NetClean.Launcher.Functional.Tests.ps1 | Adds functional tests for launcher UX, options, summaries, and post-run power actions. |
| README.md | Updates user-facing documentation to the new modes/workflow model and CI/tooling expectations. |
| PSScriptAnalyzerSettings.psd1 | Adjusts analyzer settings to work around specific PSScriptAnalyzer 1.25.0 issues. |
| Netclean.psm1 | Removes legacy module implementation in favor of the new module layout. |
| Netclean.psd1 | Updates module manifest metadata, exports, and repository/license metadata. |
| Modules/NetCleanPhase2.ps1 | Adds Phase 2 protect/backup implementation (registry/network/Wi-Fi/firewall/manifest exports). |
| examples/run-netclean.ps1 | Updates example runner defaults and output behavior to match NetClean paths/streams. |
| examples/restore-wifi-profiles.ps1 | Updates Wi-Fi restore helper to match new backup paths and avoid Write-Host. |
| examples/register-scheduledtask.ps1 | Updates scheduled task example output behavior to avoid Write-Host. |
| CONTRIBUTING.md | Rewrites contribution guidance around red-green-refactor, coverage ratchet, and tabled perf-tuning. |
| CHANGELOG.md | Expands changelog entries to reflect the new architecture, coverage gates, and behavioral guarantees. |
| .gitignore | Adds ignores for generated test/coverage output and assistant artifacts. |
| .github/workflows/powershell-check.yml | Removes the old CI workflow. |
| .github/workflows/ci.yml | Adds a new CI workflow with analyzer + coverage job, WinPS 5.1 compatibility job, and PR coverage commenting. |
| .github/PULL_REQUEST_TEMPLATE.md | Updates PR template to include security/CI checklist items. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| BeforeEach { | ||
| Mock New-DirectoryIfNotExist {} | ||
| Mock Set-NetCleanPrivateDirectoryAcl {} | ||
| Mock Invoke-RegExport { $FilePath } |
Comment on lines
+73
to
+81
| Mock Invoke-ExternalCommandSafe { | ||
| [pscustomobject]@{ | ||
| Name = $Name | ||
| ExitCode = 0 | ||
| Succeeded = $true | ||
| DryRun = $true | ||
| Error = $null | ||
| } | ||
| } |
| LicenseUri = 'https://opensource.org/licenses/MIT' | ||
| ProjectUri = 'https://github.com/example/NetworkCleaner' | ||
| ProjectUri = 'https://github.com/scweeks/netclean' | ||
| LicenseUri = 'https://github.com/scweeks/netclean/blob/ci/pester-v5-coverage/LICENSE' |
Comment on lines
+105
to
+111
| .OUTPUTS | ||
| Array of exported file paths. | ||
| #> | ||
| function Export-NetworkList { | ||
| [CmdletBinding()] | ||
| [OutputType([System.Object[]])] | ||
| param( |
Comment on lines
+446
to
+450
| if (-not $PSBoundParameters.ContainsKey('Inventory') -or $null -eq $Inventory) { | ||
| Write-NetCleanLog -Level INFO -Message 'No inventory provided, performing detection to gather current protection inventory.' | ||
| $Inventory = @(Get-ProtectionInventory) | ||
| Write-NetCleanLog -Level INFO -Message ("Detected {0} inventory entries for export." -f @($Inventory).Count) | ||
| } |
scweeks
added a commit
that referenced
this pull request
Jul 24, 2026
…port test The Windows PowerShell 5.1 job's "Ensure repo modules are preferred and PSModulePath set (ps51)" step set $env:PSModulePath to include the Save-Module cache path, but never persisted it to $env:GITHUB_ENV - unlike the equivalent PS7 job step, which does. Each workflow step runs in a fresh process, so that PSModulePath change was silently lost before the next step ran, and Import-Module Pester -RequiredVersion 6.0.1 then failed with "no valid module file was found in any module directory" because the process resolving the import had no idea the cache path existed. Added the missing GITHUB_ENV persistence line, mirroring the working PS7 pattern exactly. NetClean.Coverage.Unit.Tests.ps1's "runs the complete suite under Windows PowerShell 5.1 in CI" test regex-matched the literal text 'Install-Module Pester...RequiredVersion 6.0.1' in ci.yml, which broke when the ps51 job's install step was switched to Save-Module + explicit Import-Module for module-cache support. Updated the pattern to accept either Install-Module or Save-Module and to also check for the explicit Import-Module call, preserving the original intent (Pester 6.0.1 is specifically requested) without being tied to which of the two installation mechanisms is currently in use. Export-WiFiProfile's "falls back to per-profile export when bulk export creates no files" test mocked Get-ChildItem with a hardcoded call-order counter (call #1 = bulk-before, #2 = bulk-after, etc.) - implementation-coupled in exactly the way flagged in the ongoing test-agnosticism audit, and it was flaky: passed consistently in isolation and in a full-file run locally, but failed in CI. Replaced it with a state-driven mock: a virtual exported-file list that grows only when Invoke-ExternalCommandSafe "exports" a named profile, with Get-ChildItem always returning that list's current state. This models the real netsh-creates-a-file/Get-ChildItem-sees-it relationship directly, so the test no longer depends on how many times or in what order the production code happens to call Get-ChildItem. Validated: 455/455 Pester tests passing on PowerShell 7.6 and Windows PowerShell 5.1, PSScriptAnalyzer 1.25.0 clean, production coverage 95.50%.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Working to fix broken managed system detection
Related issues
Checklist
Testing and verification
Describe how this change was tested.