diff --git a/.github/scripts/Invoke-TestsAsBasicUser.ps1 b/.github/scripts/Invoke-TestsAsBasicUser.ps1 index 60d33c6..89b6645 100644 --- a/.github/scripts/Invoke-TestsAsBasicUser.ps1 +++ b/.github/scripts/Invoke-TestsAsBasicUser.ps1 @@ -11,7 +11,7 @@ results through a file of this account, which the restricted token can write. .PARAMETER ResultPath - Specifies the path of the result file in the NUnit format. + Specifies an absolute path, or a path relative to the repository, for the result file in the NUnit format. .PARAMETER Title Specifies the heading of the test results in the job summary. It can't contain a double quote, a percent sign, or a @@ -167,7 +167,7 @@ public static class NTFSSecurityBasicUserProcess '@ $repositoryPath = (Resolve-Path -LiteralPath (Join-Path -Path $PSScriptRoot -ChildPath '..\..')).ProviderPath -$resultFullPath = [IO.Path]::GetFullPath((Join-Path -Path $repositoryPath -ChildPath $ResultPath)) +$resultFullPath = [IO.Path]::GetFullPath([IO.Path]::Combine($repositoryPath, $ResultPath)) $resultFolder = Split-Path -Path $resultFullPath -Parent if (-not (Test-Path -LiteralPath $resultFolder)) { New-Item -ItemType Directory -Path $resultFolder | Out-Null diff --git a/Tests/BasicUserRunner.Tests.ps1 b/Tests/BasicUserRunner.Tests.ps1 new file mode 100644 index 0000000..1ac46bb --- /dev/null +++ b/Tests/BasicUserRunner.Tests.ps1 @@ -0,0 +1,81 @@ +<# + Tests the basic-user CI wrapper without creating a process or changing privileges. A fake native process writes + the same result-file boundary as the child; only the Add-Type call of the copied wrapper is mocked. +#> +[Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Pester shares variables between blocks.' +)] +param () + +BeforeAll { + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath 'TestHelpers.psm1') -Force + $sandbox = New-TestSandbox -Name 'BasicUserWrapper' + $repository = Join-Path -Path $sandbox -ChildPath 'Repository' + $scripts = Join-Path -Path $repository -ChildPath '.github\scripts' + Assert-TestSandboxPath -Sandbox $sandbox -Path $scripts + New-Item -ItemType Directory -Path $scripts -Force | Out-Null + $wrapper = Join-Path -Path $scripts -ChildPath 'Invoke-TestsAsBasicUser.ps1' + Copy-Item -LiteralPath (Join-Path -Path $PSScriptRoot -ChildPath '..\.github\scripts\Invoke-TestsAsBasicUser.ps1') -Destination $wrapper + Add-Type -TypeDefinition @" +using System; +using System.IO; +using System.Text.RegularExpressions; + +public static class NTFSSecurityBasicUserProcess +{ + public static int Calls; + public static string WorkingDirectory; + + public static int Run(string applicationName, string commandLine, string currentDirectory) + { + Calls++; + WorkingDirectory = currentDirectory; + var match = Regex.Match(commandLine, "-ResultPath \"([^\"]+)\""); + if (!match.Success) + throw new InvalidOperationException("The child command has no result path."); + File.WriteAllText(match.Groups[1].Value, ""); + return 0; + } +} +"@ +} + +AfterAll { + Remove-TestSandbox -Sandbox $sandbox +} + +Describe 'Invoke-TestsAsBasicUser.ps1 result paths' { + BeforeEach { + [NTFSSecurityBasicUserProcess]::Calls = 0 + [NTFSSecurityBasicUserProcess]::WorkingDirectory = $null + Mock -CommandName Add-Type -ParameterFilter { $TypeDefinition -like '*class NTFSSecurityBasicUserProcess*' } + } + + It 'Should copy the result to an absolute path, also when that path contains spaces' { + $result = Join-Path -Path $sandbox -ChildPath 'Absolute results\Result.xml' + Assert-TestSandboxPath -Sandbox $sandbox -Path $result + + & $wrapper -ResultPath $result -Title 'Absolute result path' | Out-Null + + Get-Content -LiteralPath $result -Raw | Should -BeExactly '' + [NTFSSecurityBasicUserProcess]::Calls | Should -Be 1 + [NTFSSecurityBasicUserProcess]::WorkingDirectory | Should -Be $repository + Should -Invoke -CommandName Add-Type -Times 1 -Exactly + } + + It 'Should resolve a relative path against the repository, not the caller location' { + $result = Join-Path -Path $repository -ChildPath 'Relative results\Result.xml' + Assert-TestSandboxPath -Sandbox $sandbox -Path $result + Push-Location -LiteralPath $sandbox + try { + & $wrapper -ResultPath 'Relative results\Result.xml' -Title 'Relative result path' | Out-Null + } + finally { + Pop-Location + } + + Get-Content -LiteralPath $result -Raw | Should -BeExactly '' + [NTFSSecurityBasicUserProcess]::Calls | Should -Be 1 + [NTFSSecurityBasicUserProcess]::WorkingDirectory | Should -Be $repository + } +}