From 5b28b546f1486a3d011af2db00ec66f2b6d7c9e7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 14 May 2026 00:35:07 +0000 Subject: [PATCH 1/2] Initial plan From 86ffb8d6316fe6a3ef62797d518a9ebc884f848a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 14 May 2026 00:47:04 +0000 Subject: [PATCH 2/2] feat(tests): add Invoke-Logging.tests.ps1 and update CHANGELOG Agent-Logs-Url: https://github.com/HeyItsGilbert/Gatekeeper/sessions/a7d2d9f0-2833-4f10-b2d2-7e2ed8094b29 Co-authored-by: HeyItsGilbert <615265+HeyItsGilbert@users.noreply.github.com> --- CHANGELOG.md | 11 +++ tests/Invoke-Logging.tests.ps1 | 118 +++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 tests/Invoke-Logging.tests.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e589e2..d330641 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [Unreleased] + +### Changed + +- `Invoke-Logging` now reads the pre-parsed scriptblock from + `$script:GatekeeperLogging` (populated by `Import-GatekeeperConfig`) instead + of re-creating the scriptblock from raw configuration on every call. This + eliminates redundant compilation overhead and preserves any closure context + that would have been lost by stringifying an existing scriptblock through + `[scriptblock]::Create()`. + ## [0.3.2] 2026-01-30 ### Fixed diff --git a/tests/Invoke-Logging.tests.ps1 b/tests/Invoke-Logging.tests.ps1 new file mode 100644 index 0000000..456dc21 --- /dev/null +++ b/tests/Invoke-Logging.tests.ps1 @@ -0,0 +1,118 @@ +BeforeDiscovery { + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + + Get-Module $env:BHProjectName -All | Remove-Module -Force -ErrorAction Ignore + Get-Module 'Configuration' -All | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop +} + +Describe 'Invoke-Logging' { + BeforeAll { + # Prevent actual config loading during tests + Mock -CommandName 'Import-GatekeeperConfig' -ModuleName $env:BHProjectName {} + + $script:testRule = [Rule]::new(@{ + Name = 'TestRule' + Effect = 'Allow' + Conditions = @{ Property = 'IsCompliant'; Operator = 'Equals'; Value = $true } + }) + } + + AfterEach { + # Reset the logging cache between tests + InModuleScope $env:BHProjectName { + $script:GatekeeperLogging = $null + } + } + + Context 'Uses pre-parsed scriptblock cache' { + It 'invokes the cached scriptblock for the matching effect' { + $captureRule = $script:testRule + + InModuleScope $env:BHProjectName -Parameters @{ Rule = $captureRule } { + param($Rule) + $script:GatekeeperLogging = @{ + Allow = { param($Rule) $script:lastLoggedRule = $Rule } + } + $script:lastLoggedRule = $null + } + + InModuleScope $env:BHProjectName -Parameters @{ Rule = $captureRule } { + param($Rule) + Invoke-Logging -Effect 'Allow' -Rule $Rule + } + + InModuleScope $env:BHProjectName { + $script:lastLoggedRule | Should -Not -BeNull + $script:lastLoggedRule.Name | Should -Be 'TestRule' + } + } + + It 'does not invoke a scriptblock for a different effect' { + $captureRule = $script:testRule + + InModuleScope $env:BHProjectName -Parameters @{ Rule = $captureRule } { + param($Rule) + $script:GatekeeperLogging = @{ + Deny = { param($Rule) $script:lastLoggedRule = $Rule } + } + $script:lastLoggedRule = $null + } + + InModuleScope $env:BHProjectName -Parameters @{ Rule = $captureRule } { + param($Rule) + Invoke-Logging -Effect 'Allow' -Rule $Rule + } + + InModuleScope $env:BHProjectName { + $script:lastLoggedRule | Should -BeNull + } + } + } + + Context 'Graceful no-ops' { + It 'returns without error when GatekeeperLogging cache is null' { + InModuleScope $env:BHProjectName { + $script:GatekeeperLogging = $null + } + + $captureRule = $script:testRule + { + InModuleScope $env:BHProjectName -Parameters @{ Rule = $captureRule } { + param($Rule) + Invoke-Logging -Effect 'Allow' -Rule $Rule + } + } | Should -Not -Throw + } + + It 'returns without error when effect is not present in cache' { + InModuleScope $env:BHProjectName { + $script:GatekeeperLogging = @{} + } + + $captureRule = $script:testRule + { + InModuleScope $env:BHProjectName -Parameters @{ Rule = $captureRule } { + param($Rule) + Invoke-Logging -Effect 'Allow' -Rule $Rule + } + } | Should -Not -Throw + } + } + + Context 'Config loading' { + It 'calls Import-GatekeeperConfig to ensure cache is initialized' { + $captureRule = $script:testRule + InModuleScope $env:BHProjectName -Parameters @{ Rule = $captureRule } { + param($Rule) + Invoke-Logging -Effect 'Allow' -Rule $Rule + } + + Should -Invoke 'Import-GatekeeperConfig' -ModuleName $env:BHProjectName -Times 1 -Exactly + } + } +}