test: add sandbox, path guard, and elevation helpers for the tests
Tests/TestHelpers.psm1 lets a test that changes files, links, ACLs,
owners, audit entries, or inheritance work in its own sandbox below
$env:TEMP\NTFSSecurity.Tests:
- New-TestSandbox creates the folder; Assert-TestSandboxPath throws
unless every target, relative ones resolved against the location, is
inside it.
- Remove-TestSandbox removes the links first without following them
(Windows PowerShell 5.1 follows directory links when it removes a
folder), resets ACL changes, and deletes the folder.
- Test-IsElevated and Test-PrivilegeHeld decide which tests can run; CI
runners are elevated, the workstation isn't.
Tests/TestHelpers.Tests.ps1 (14 tests) covers the helpers. CI runs every
*.Tests.ps1 file in Tests, so new test files need no workflow change.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
4 weeks ago
|
|
|
<#
|
|
|
|
|
Tests the shared helpers in TestHelpers.psm1, which keep the tests that change files, links, and security
|
|
|
|
|
descriptors inside their sandbox folders. CI runs every *.Tests.ps1 file of this folder.
|
|
|
|
|
#>
|
|
|
|
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
|
|
|
|
|
'PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Pester shares variables between blocks.'
|
|
|
|
|
)]
|
|
|
|
|
param ()
|
|
|
|
|
|
|
|
|
|
BeforeAll {
|
|
|
|
|
Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath 'TestHelpers.psm1') -Force
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AfterAll {
|
|
|
|
|
Remove-Module -Name TestHelpers -Force -ErrorAction SilentlyContinue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Describe 'Test helpers' {
|
|
|
|
|
Context 'New-TestSandbox' {
|
|
|
|
|
BeforeAll {
|
|
|
|
|
$sandbox = New-TestSandbox -Name 'Helpers'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AfterAll {
|
|
|
|
|
Remove-TestSandbox -Sandbox $sandbox
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
It 'Should create an empty folder below $env:TEMP\NTFSSecurity.Tests' {
|
|
|
|
|
$sandbox | Should -Exist
|
|
|
|
|
Get-ChildItem -LiteralPath $sandbox -Force | Should -BeNullOrEmpty
|
|
|
|
|
$expectedParent = [IO.Path]::GetFullPath((Join-Path -Path ([IO.Path]::GetTempPath()) -ChildPath 'NTFSSecurity.Tests'))
|
|
|
|
|
Split-Path -Path $sandbox -Parent | Should -Be $expectedParent
|
|
|
|
|
Split-Path -Path $sandbox -Leaf | Should -BeLike 'Helpers-*'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Context 'Assert-TestSandboxPath' {
|
|
|
|
|
BeforeAll {
|
|
|
|
|
$sandbox = New-TestSandbox -Name 'Helpers'
|
|
|
|
|
Push-Location -LiteralPath $sandbox
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AfterAll {
|
|
|
|
|
Pop-Location
|
|
|
|
|
Remove-TestSandbox -Sandbox $sandbox
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
It 'Should accept a full path inside the sandbox' {
|
|
|
|
|
{ Assert-TestSandboxPath -Sandbox $sandbox -Path (Join-Path -Path $sandbox -ChildPath 'Folder\File.txt') } |
|
|
|
|
|
Should -Not -Throw
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
It 'Should resolve a relative path against the current location' {
|
|
|
|
|
{ Assert-TestSandboxPath -Sandbox $sandbox -Path '.\File.txt', 'Folder\File.txt' } | Should -Not -Throw
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
It 'Should reject <_>' -ForEach @('..', '..\Other', 'C:\Windows', '\Windows') {
|
|
|
|
|
{ Assert-TestSandboxPath -Sandbox $sandbox -Path $_ } | Should -Throw -ExpectedMessage 'Refusing to change*'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
It 'Should reject a sibling folder whose name starts with the name of the sandbox' {
|
|
|
|
|
{ Assert-TestSandboxPath -Sandbox $sandbox -Path "$sandbox-Other\File.txt" } |
|
|
|
|
|
Should -Throw -ExpectedMessage 'Refusing to change*'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
It 'Should reject a sandbox that New-TestSandbox did not create' {
|
|
|
|
|
{ Assert-TestSandboxPath -Sandbox $env:TEMP -Path (Join-Path -Path $env:TEMP -ChildPath 'File.txt') } |
|
|
|
|
|
Should -Throw -ExpectedMessage '*is not a test sandbox*'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
It 'Should reject a path below a link, which can point outside the sandbox' {
|
|
|
|
|
$otherSandbox = New-TestSandbox -Name 'Helpers'
|
|
|
|
|
try {
|
|
|
|
|
$link = Join-Path -Path $sandbox -ChildPath 'Link'
|
|
|
|
|
Assert-TestSandboxPath -Sandbox $sandbox -Path $link
|
|
|
|
|
New-Item -ItemType Junction -Path $link -Value $otherSandbox | Out-Null
|
|
|
|
|
|
|
|
|
|
{ Assert-TestSandboxPath -Sandbox $sandbox -Path (Join-Path -Path $link -ChildPath 'File.txt') } |
|
|
|
|
|
Should -Throw -ExpectedMessage '*is a link*'
|
|
|
|
|
}
|
|
|
|
|
finally {
|
|
|
|
|
Remove-TestSandbox -Sandbox $otherSandbox
|
|
|
|
|
}
|
|
|
|
|
}
|
test: add sandbox, path guard, and elevation helpers for the tests
Tests/TestHelpers.psm1 lets a test that changes files, links, ACLs,
owners, audit entries, or inheritance work in its own sandbox below
$env:TEMP\NTFSSecurity.Tests:
- New-TestSandbox creates the folder; Assert-TestSandboxPath throws
unless every target, relative ones resolved against the location, is
inside it.
- Remove-TestSandbox removes the links first without following them
(Windows PowerShell 5.1 follows directory links when it removes a
folder), resets ACL changes, and deletes the folder.
- Test-IsElevated and Test-PrivilegeHeld decide which tests can run; CI
runners are elevated, the workstation isn't.
Tests/TestHelpers.Tests.ps1 (14 tests) covers the helpers. CI runs every
*.Tests.ps1 file in Tests, so new test files need no workflow change.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
4 weeks ago
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Context 'Remove-TestSandbox' {
|
|
|
|
|
BeforeAll {
|
|
|
|
|
$sandbox = New-TestSandbox -Name 'Helpers'
|
|
|
|
|
$otherSandbox = New-TestSandbox -Name 'Helpers'
|
|
|
|
|
$target = Join-Path -Path $otherSandbox -ChildPath 'Target'
|
|
|
|
|
$link = Join-Path -Path $sandbox -ChildPath 'Link'
|
|
|
|
|
$locked = Join-Path -Path $sandbox -ChildPath 'Locked'
|
|
|
|
|
|
|
|
|
|
Assert-TestSandboxPath -Sandbox $otherSandbox -Path $target
|
|
|
|
|
New-Item -ItemType Directory -Path $target | Out-Null
|
|
|
|
|
Set-Content -LiteralPath (Join-Path -Path $target -ChildPath 'Keep.txt') -Value 'Keep'
|
|
|
|
|
# An explicit entry that a reset through the link would remove
|
|
|
|
|
$targetAcl = Get-Acl -LiteralPath $target
|
|
|
|
|
$targetAcl.AddAccessRule((New-Object -TypeName 'System.Security.AccessControl.FileSystemAccessRule' -ArgumentList (
|
|
|
|
|
(New-Object -TypeName 'System.Security.Principal.SecurityIdentifier' -ArgumentList 'S-1-1-0'),
|
|
|
|
|
[System.Security.AccessControl.FileSystemRights]::ReadData, [System.Security.AccessControl.AccessControlType]::Allow
|
|
|
|
|
)))
|
|
|
|
|
Set-Acl -LiteralPath $target -AclObject $targetAcl
|
|
|
|
|
$targetSddl = (Get-Acl -LiteralPath $target).Sddl
|
test: add sandbox, path guard, and elevation helpers for the tests
Tests/TestHelpers.psm1 lets a test that changes files, links, ACLs,
owners, audit entries, or inheritance work in its own sandbox below
$env:TEMP\NTFSSecurity.Tests:
- New-TestSandbox creates the folder; Assert-TestSandboxPath throws
unless every target, relative ones resolved against the location, is
inside it.
- Remove-TestSandbox removes the links first without following them
(Windows PowerShell 5.1 follows directory links when it removes a
folder), resets ACL changes, and deletes the folder.
- Test-IsElevated and Test-PrivilegeHeld decide which tests can run; CI
runners are elevated, the workstation isn't.
Tests/TestHelpers.Tests.ps1 (14 tests) covers the helpers. CI runs every
*.Tests.ps1 file in Tests, so new test files need no workflow change.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
4 weeks ago
|
|
|
Assert-TestSandboxPath -Sandbox $sandbox -Path $link, $locked
|
|
|
|
|
New-Item -ItemType Junction -Path $link -Value $target | Out-Null
|
|
|
|
|
New-Item -ItemType Directory -Path $locked | Out-Null
|
|
|
|
|
Set-Content -LiteralPath (Join-Path -Path $locked -ChildPath 'File.txt') -Value 'Locked'
|
|
|
|
|
# An empty, protected DACL that grants nobody access, as some tests leave behind
|
|
|
|
|
& icacls.exe $locked /inheritance:r *> $null
|
|
|
|
|
|
|
|
|
|
Remove-TestSandbox -Sandbox $sandbox
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AfterAll {
|
|
|
|
|
Remove-TestSandbox -Sandbox $otherSandbox
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
It 'Should remove the sandbox, even with a folder that denies access' {
|
|
|
|
|
$sandbox | Should -Not -Exist
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
It 'Should remove a junction without removing the files of its target' {
|
|
|
|
|
Join-Path -Path $target -ChildPath 'Keep.txt' | Should -Exist
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
It 'Should not change the ACL of the target of a junction' {
|
|
|
|
|
(Get-Acl -LiteralPath $target).Sddl | Should -BeExactly $targetSddl
|
|
|
|
|
}
|
test: add sandbox, path guard, and elevation helpers for the tests
Tests/TestHelpers.psm1 lets a test that changes files, links, ACLs,
owners, audit entries, or inheritance work in its own sandbox below
$env:TEMP\NTFSSecurity.Tests:
- New-TestSandbox creates the folder; Assert-TestSandboxPath throws
unless every target, relative ones resolved against the location, is
inside it.
- Remove-TestSandbox removes the links first without following them
(Windows PowerShell 5.1 follows directory links when it removes a
folder), resets ACL changes, and deletes the folder.
- Test-IsElevated and Test-PrivilegeHeld decide which tests can run; CI
runners are elevated, the workstation isn't.
Tests/TestHelpers.Tests.ps1 (14 tests) covers the helpers. CI runs every
*.Tests.ps1 file in Tests, so new test files need no workflow change.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
4 weeks ago
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Context 'Test-IsElevated and Test-PrivilegeHeld' {
|
|
|
|
|
It 'Should tell whether the process is elevated' {
|
|
|
|
|
Test-IsElevated | Should -BeOfType [bool]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
It 'Should find SeChangeNotifyPrivilege, which every access token holds' {
|
|
|
|
|
Test-PrivilegeHeld -Name 'SeChangeNotifyPrivilege' | Should -BeTrue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
It 'Should not find a privilege that does not exist' {
|
|
|
|
|
Test-PrivilegeHeld -Name 'SeNoSuchPrivilege' | Should -BeFalse
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|