I dont understand why I cant test my Read-VaultSecret.
in my file appsettings.psm1, i have a this function
function Read-VaultSecret($vault, $secretId)
{
try {
return Read-SecureString((Get-AzKeyVaultSecret -VaultName $vault -Name $secretId).SecretValue)
} catch {
Write-Error "Error reading secret $secretId from vault $vault - do you have read access in $vault policies?"
return
}
}
function Read-SecureString {
param (
[Parameter(Mandatory = $true)]
[System.Security.SecureString]$SecureString
)
try {
# Convert SecureString to plain text , linux safe
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString)
return [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($BSTR)
}
catch {
Write-Error "An error occurred while converting the SecureString: $_"
throw # Re-throw the exception if you want it to propagate further
}
finally {
if ($BSTR) {
# Ensure the allocated memory is freed even if there's an error
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)
}
}
}
in my pester test appsettings.Tests.ps1 I have this test
BeforeAll {
# Import the module to be tested
Import-Module "$PSScriptRoot/../appsettings.psm1" -Force
# Mock Get-AzKeyVaultSecret to simulate secret retrieval
function Get-AzKeyVaultSecret {
param (
[string]$VaultName,
[string]$Name
)
# Return an object with a SecretValue that contains the SecureString
return [PSCustomObject]@{
SecretValue = ConvertTo-SecureString "SuperSecretValue" -AsPlainText -Force
}
}
}
Describe "Read-VaultSecret Function Tests" {
It "should return the secret as a plain text string when valid vault and secretId are provided" {
$vault = "TestVault"
$secretId = "TestSecret"
$result = Read-VaultSecret -vault $vault -secretId $secretId
$result | Should -Be "SuperSecretValue"
}
}
when i run the actual test I get these two error messages
Why is it complaining about "Run Connect-AzAccount to login." ? Shouldn't the function Get-AzKeyVaultSecret I have in my pester test bypass the normal azure command-lets called in Read-VaultSecret ?
Ultimately what I want to do is mock up a couple azure command-lets so i can run my tests without actually having to connect to azure infrastructure.
is that possible ?
So there 2 issues in your Pester test, one is described in this answer, essentially you will need to either use global:
scope modifier for your function
or have a helper psm1
that has this function and you import it before running the tests (using global:
for this answer, both should work fine).
Second issue is referencing
Read-SecureString
which doesn't seem to exist (?) or there is no reference of it in your question.
Updated question shows the reference to this function. Even though the code to decrypt the SecureString
is correct, the preferred method, for simplicity, is to use NetworkCredential
as shown in this answer.
Also, this isn't an issue but placing the code in a BeforeAll
or BeforeDiscovery
isn't really mandatory (you can still have it if you want).
In summary, appsettings.psm1
can be:
function Read-VaultSecret($vault, $secretId) {
try {
# using `NetworkCredential` to get the plain text password is the proper method here
[System.Net.NetworkCredential]::new('',
(Get-AzKeyVaultSecret -VaultName $vault -Name $secretId).SecretValue).Password
}
catch {
Write-Error "Error reading secret $secretId from vault $vault - do you have read access in $vault policies?"
}
}
Then your test file can be:
# Import the module to be tested
Import-Module "$PSScriptRoot/../appsettings.psm1" -Force
# Mock Get-AzKeyVaultSecret to simulate secret retrieval
function global:Get-AzKeyVaultSecret {
param (
[string] $VaultName,
[string] $Name
)
# Return an object with a SecretValue that contains the SecureString
[PSCustomObject]@{
SecretValue = ConvertTo-SecureString 'SuperSecretValue' -AsPlainText -Force
}
}
Describe 'Read-VaultSecret Function Tests' {
It 'should return the secret as a plain text string when valid vault and secretId are provided' {
$vault = 'TestVault'
$secretId = 'TestSecret'
$result = Read-VaultSecret -vault $vault -secretId $secretId
$result | Should -Be 'SuperSecretValue'
}
}
And when the test is invoked it should work correctly:
PS ..\pwsh> Invoke-Pester -Path .\testscript.tests.ps1
Starting discovery in 1 files.
Discovery found 1 tests in 220ms.
Running tests.
[+] D:\...\pwsh\testscript.tests.ps1 694ms (112ms|407ms)
Tests completed in 716ms
Tests Passed: 1, Failed: 0, Skipped: 0, Inconclusive: 0, NotRun: 0