diff --git a/tests/TestHelpers.ps1 b/tests/TestHelpers.ps1 index 99b6d39..4a1c976 100644 --- a/tests/TestHelpers.ps1 +++ b/tests/TestHelpers.ps1 @@ -1,26 +1,51 @@ +function New-TestToken { + <# + .SYNOPSIS + Returns a fresh random string for use as a throwaway test credential. + + .DESCRIPTION + Test fixtures only. Generates a new value per call so no token literal is + ever committed to source. That keeps PSScriptAnalyzer and GitGuardian's + "ConvertTo-SecureString Password" detector quiet and avoids hard-coded + "secrets" in the test suite. The contents are never asserted on; tests + only need *a* token, not a specific one. + #> + [CmdletBinding()] + [OutputType([string])] + param() + + [guid]::NewGuid().ToString('N') +} + function New-TestSecureString { <# .SYNOPSIS - Builds a SecureString from a plaintext literal without going through - ConvertTo-SecureString -AsPlainText. + Builds a SecureString without going through ConvertTo-SecureString + -AsPlainText. Uses a random value when -Value is omitted. .DESCRIPTION Test fixtures only. PSScriptAnalyzer's PSAvoidUsingConvertToSecureStringWithPlainText rule and GitGuardian's "ConvertTo-SecureString Password" detector both flag any literal passed to ConvertTo-SecureString -AsPlainText as a likely-credential leak. Tests legitimately need to construct a - SecureString from a string literal; this helper does that via - SecureString.AppendChar so neither scanner false-positives. + SecureString; this helper does that via SecureString.AppendChar so + neither scanner false-positives. Omit -Value to get a random token + (preferred when the contents are irrelevant to the assertion); pass + -Value only when a test depends on the exact characters. #> - [CmdletBinding()] + [CmdletBinding(DefaultParameterSetName = 'Random')] [OutputType([securestring])] param( - [Parameter(Mandatory)] + [Parameter(Mandatory, ParameterSetName = 'Value')] [AllowEmptyString()] [string] $Value ) + if ($PSCmdlet.ParameterSetName -eq 'Random') { + $Value = New-TestToken + } + $secure = [System.Security.SecureString]::new() foreach ($char in $Value.ToCharArray()) { $secure.AppendChar($char) } $secure.MakeReadOnly() diff --git a/tests/Unit/Public/Connect-JsmService.tests.ps1 b/tests/Unit/Public/Connect-JsmService.tests.ps1 index 9b30c44..9239db7 100644 --- a/tests/Unit/Public/Connect-JsmService.tests.ps1 +++ b/tests/Unit/Public/Connect-JsmService.tests.ps1 @@ -61,7 +61,7 @@ Describe 'Connect-JsmService' { Mock -CommandName 'Invoke-JsmApi' -MockWith { @{ values = @() } } } - $token = New-TestSecureString -Value 'token-1' + $token = New-TestSecureString Connect-JsmService -Email 'me@example.com' -ApiToken $token -CloudId 'c1' InModuleScope -ModuleName $Env:BHProjectName -ScriptBlock { @@ -79,7 +79,7 @@ Describe 'Connect-JsmService' { Mock -CommandName 'Invoke-JsmApi' -MockWith { @{ values = @() } } } - $token = New-TestSecureString -Value 'token-2' + $token = New-TestSecureString $credential = [pscredential]::new('credential@example.com', $token) Connect-JsmService -Credential $credential -CloudId 'c2' @@ -97,7 +97,7 @@ Describe 'Connect-JsmService' { Mock -CommandName 'Invoke-JsmApi' -MockWith { @{ values = @() } } } $env:JSM_EMAIL = 'environment@example.com' - $env:JSM_API_TOKEN = 'environment-token' + $env:JSM_API_TOKEN = New-TestToken $env:JSM_CLOUD_ID = 'environment-cloud' Connect-JsmService @@ -112,7 +112,7 @@ Describe 'Connect-JsmService' { Context 'Validation' { It 'Throws when email is missing entirely' { - $token = New-TestSecureString -Value 'token' + $token = New-TestSecureString { Connect-JsmService -ApiToken $token -CloudId 'c1' } | Should -Throw -ExpectedMessage '*Email is required*' } @@ -123,18 +123,18 @@ Describe 'Connect-JsmService' { } It 'Throws when CloudId is missing entirely' { - $token = New-TestSecureString -Value 'token' + $token = New-TestSecureString { Connect-JsmService -Email 'me@example.com' -ApiToken $token } | Should -Throw -ExpectedMessage '*CloudId is required*' } It 'Fails parameter binding when -Email is explicitly empty' { - $token = New-TestSecureString -Value 'token' + $token = New-TestSecureString { Connect-JsmService -Email '' -ApiToken $token -CloudId 'c1' } | Should -Throw } It 'Fails parameter binding when -CloudId is explicitly empty' { - $token = New-TestSecureString -Value 'token' + $token = New-TestSecureString { Connect-JsmService -Email 'me@example.com' -ApiToken $token -CloudId '' } | Should -Throw } } @@ -145,7 +145,7 @@ Describe 'Connect-JsmService' { InModuleScope -ModuleName $Env:BHProjectName -ScriptBlock { Mock -CommandName 'Invoke-JsmApi' -MockWith { throw 'HTTP 401' } } - $token = New-TestSecureString -Value 'bad' + $token = New-TestSecureString { Connect-JsmService -Email 'me@example.com' -ApiToken $token -CloudId 'c1' } | Should -Throw '*HTTP 401*' @@ -162,7 +162,7 @@ Describe 'Connect-JsmService' { InModuleScope -ModuleName $Env:BHProjectName -ScriptBlock { Mock -CommandName 'Invoke-JsmApi' -MockWith { @{ values = @() } } } - $token = New-TestSecureString -Value 'token' + $token = New-TestSecureString $result = Connect-JsmService -Email 'me@example.com' -ApiToken $token -CloudId 'c1' -PassThru diff --git a/tests/Unit/Public/Get-JsmConnection.tests.ps1 b/tests/Unit/Public/Get-JsmConnection.tests.ps1 index f34679d..9c5ec35 100644 --- a/tests/Unit/Public/Get-JsmConnection.tests.ps1 +++ b/tests/Unit/Public/Get-JsmConnection.tests.ps1 @@ -46,7 +46,7 @@ Describe 'Get-JsmConnection' { } It 'Returns a view of the connection without ApiToken' { - $apiToken = New-TestSecureString -Value 'token' + $apiToken = New-TestSecureString InModuleScope -ModuleName $Env:BHProjectName -Parameters @{ ApiToken = $apiToken } -ScriptBlock { param($ApiToken) $script:JsmConnection = [pscustomobject]@{