Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ function New-IdleExchangeOnlineAdapter {
[switch] $UseRestApi
)

# Regex patterns for sanitizing error messages (captured by scriptblock closure)
$bearerTokenPattern = 'Bearer\s+[^\s]+'
$tokenAssignmentPattern = 'token[^\s]*\s*=\s*[^\s,;]+'

$adapter = [pscustomobject]@{
PSTypeName = 'IdLE.ExchangeOnlineAdapter'
UseRestApi = [bool]$UseRestApi
Expand All @@ -37,6 +33,10 @@ function New-IdleExchangeOnlineAdapter {
[hashtable] $Parameters = @{}
)

# Regex patterns for sanitizing error messages (defined inside scriptblock for reliable scoping)
$bearerTokenPattern = 'Bearer\s+[^\s]+'
$tokenAssignmentPattern = 'token[^\s]*\s*=\s*[^\s,;]+'

try {
$result = & $CommandName @Parameters
return $result
Expand Down
40 changes: 40 additions & 0 deletions tests/Providers/ExchangeOnlineProvider.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,46 @@ Describe 'ExchangeOnline provider - Unit tests' {
}
}

Context 'New-IdleExchangeOnlineAdapter - InvokeSafely scoping regression' {
BeforeAll {
# Import private adapter function directly for unit testing
$repoRoot = Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent
$adapterPath = Join-Path -Path $repoRoot -ChildPath 'src\IdLE.Provider.ExchangeOnline\Private\New-IdleExchangeOnlineAdapter.ps1'
Comment thread
blindzero marked this conversation as resolved.

if (-not (Test-Path -LiteralPath $adapterPath)) {
throw "Private adapter function file not found at path: $adapterPath"
}
. $adapterPath

# Dot-source provider test helpers so Invoke-IdleTestBearerTokenError is available at run time
. (Join-Path -Path $PSScriptRoot -ChildPath '_testHelpers.Providers.ps1')
}

It 'InvokeSafely can be called from another ScriptMethod without variable-not-set error' {
# Regression test: $bearerTokenPattern and $tokenAssignmentPattern must be in scope
# when InvokeSafely is invoked via $this.InvokeSafely() from another ScriptMethod.
$adapter = New-IdleExchangeOnlineAdapter

# Wrap the real adapter with a ScriptMethod that calls $this.InvokeSafely() to
# simulate the same execution path as GetMailbox -> InvokeSafely.
$adapter | Add-Member -MemberType ScriptMethod -Name TestViaMethod -Value {
$this.InvokeSafely('Write-Output', @{ InputObject = 'ok' })
} -Force

{ $adapter.TestViaMethod() } | Should -Not -Throw
}

It 'InvokeSafely sanitizes bearer tokens in error messages without variable-not-set error' {
$adapter = New-IdleExchangeOnlineAdapter

$adapter | Add-Member -MemberType ScriptMethod -Name TestErrorSanitization -Value {
$this.InvokeSafely('Invoke-IdleTestBearerTokenError', @{})
} -Force

{ $adapter.TestErrorSanitization() } | Should -Throw -ExpectedMessage "*Bearer <REDACTED>*"
}
}

Context 'Normalize-IdleExchangeOnlineAutoReplyMessage' {
BeforeAll {
# Import the private normalization function for direct testing
Expand Down
17 changes: 15 additions & 2 deletions tests/Providers/_testHelpers.Providers.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,18 @@ directly by test files.
#>

# Provider-specific helpers will be added here as needed.
# This file is currently empty but provides a clear extension point for
# provider-related test infrastructure.

function Invoke-IdleTestBearerTokenError {
<#
.SYNOPSIS
Test helper: throws an exception whose message contains a bearer token.

.DESCRIPTION
Used by adapter unit tests to verify that InvokeSafely correctly sanitizes
bearer tokens from error messages without leaking sensitive data.
#>
[CmdletBinding()]
param()

throw 'Authentication failed: Bearer eyJhbGciOiJSUzI1NiJ9.payload.sig'
}