Tests/Unit/Private/Resolve-SIAError.Tests.ps1

BeforeAll {
    $moduleRoot = (Resolve-Path (Join-Path $PSScriptRoot '../../..')).Path
    Import-Module (Join-Path $moduleRoot 'psSIA.psd1') -Force

    function New-TestErrorRecord {
        param(
            [System.Net.HttpStatusCode]$StatusCode = [System.Net.HttpStatusCode]::Forbidden,
            [string]$Body,
            [hashtable]$Headers
        )

        $response = [System.Net.Http.HttpResponseMessage]::new($StatusCode)
        if ($Headers) {
            foreach ($key in $Headers.Keys) {
                $response.Headers.Add($key, $Headers[$key])
            }
        }

        $exception = [System.Exception]::new('Request failed')
        $exception | Add-Member -NotePropertyName Response -NotePropertyValue $response

        $errorRecord = [System.Management.Automation.ErrorRecord]::new(
            $exception, 'TestError', [System.Management.Automation.ErrorCategory]::InvalidOperation, $null)

        if ($Body) {
            $errorRecord.ErrorDetails = [System.Management.Automation.ErrorDetails]::new($Body)
        }

        $errorRecord
    }
}

Describe 'Resolve-SIAError' {
    It 'includes the HTTP status code, operation, and endpoint' {
        $errorRecord = New-TestErrorRecord -StatusCode Forbidden

        $message = InModuleScope psSIA -Parameters @{ errorRecord = $errorRecord } {
            param($errorRecord)
            Resolve-SIAError -ErrorRecord $errorRecord -Operation 'Get-SIAConnector' -Uri 'https://contoso.dpa.cyberark.cloud/api/connectors'
        }

        $message | Should -Match 'HTTP 403'
        $message | Should -Match 'Get-SIAConnector'
        $message | Should -Match 'contoso\.dpa\.cyberark\.cloud'
    }

    It 'extracts a message from a JSON error body' {
        $errorRecord = New-TestErrorRecord -Body '{"message":"Insufficient permissions."}'

        $message = InModuleScope psSIA -Parameters @{ errorRecord = $errorRecord } {
            param($errorRecord)
            Resolve-SIAError -ErrorRecord $errorRecord -Operation 'Get-SIAConnector' -Uri 'https://contoso.dpa.cyberark.cloud/api/connectors'
        }

        $message | Should -Match 'Insufficient permissions\.'
    }

    It 'falls back to the raw body when it is not valid JSON' {
        $errorRecord = New-TestErrorRecord -Body 'plain text failure'

        $message = InModuleScope psSIA -Parameters @{ errorRecord = $errorRecord } {
            param($errorRecord)
            Resolve-SIAError -ErrorRecord $errorRecord -Operation 'Get-SIAConnector' -Uri 'https://contoso.dpa.cyberark.cloud/api/connectors'
        }

        $message | Should -Match 'plain text failure'
    }

    It 'includes a request ID when a correlation header is present' {
        $errorRecord = New-TestErrorRecord -Headers @{ 'x-correlation-id' = 'abc-123' }

        $message = InModuleScope psSIA -Parameters @{ errorRecord = $errorRecord } {
            param($errorRecord)
            Resolve-SIAError -ErrorRecord $errorRecord -Operation 'Get-SIAConnector' -Uri 'https://contoso.dpa.cyberark.cloud/api/connectors'
        }

        $message | Should -Match 'Request ID: abc-123'
    }

    It 'never includes a secret value found in the error body' {
        $errorRecord = New-TestErrorRecord -Body '{"message":"client_secret=hunter2 is invalid"}'

        $message = InModuleScope psSIA -Parameters @{ errorRecord = $errorRecord } {
            param($errorRecord)
            Resolve-SIAError -ErrorRecord $errorRecord -Operation 'New-SIASession' -Uri 'https://contoso.id.cyberark.cloud/oauth2/platformtoken'
        }

        $message | Should -Not -Match 'hunter2'
    }
}