tests/Get-MsecSharePointTenantSetting.Tests.ps1
|
#Requires -Module Pester # # Tests for Get-MsecSharePointTenantSetting. # # The tenant settings are the CEILING every site sits under: a locked-down site in a tenant # where anyone-links are on is still exposed, and reviewing sites one at a time never shows it. # # Two things worth pinning. First, an empty domain list must not render blank - with # SharingDomainRestrictionMode = allowList, an EMPTY allowed list means nobody outside can be # invited, which is the opposite of what a blank cell suggests. Second, the 403 has to name the # permission: Graph's own error names none, and Sites.Read.All (which the app already holds) # does not cover this endpoint. BeforeAll { $modulePath = Join-Path $PSScriptRoot '..' 'msec.psm1' Import-Module $modulePath -Force -ErrorAction Stop } AfterAll { Remove-Module Msec -Force -ErrorAction SilentlyContinue } Describe 'Get-MsecSharePointTenantSetting' { BeforeEach { InModuleScope Msec { $script:MsecSession = @{ TenantId = 't'; ClientId = 'c'; Tokens = @{} } } } It 'flattens to one row per setting, keeping only the security-relevant ones' { $rows = InModuleScope Msec { Mock Invoke-MsecGraphRequest -MockWith { [pscustomobject]@{ sharingCapability = 'ExternalUserAndGuestSharing' sharingDomainRestrictionMode = 'AllowList' sharingAllowedDomainList = @('partner.com', 'vendor.com') isLegacyAuthProtocolsEnabled = $true # Not a security control - must not appear in the default projection. tenantDefaultTimezone = 'W. Europe Standard Time' } } Get-MsecSharePointTenantSetting } @($rows | ForEach-Object { $_.Setting }) | Should -Contain 'sharingCapability' @($rows | ForEach-Object { $_.Setting }) | Should -Not -Contain 'tenantDefaultTimezone' ($rows | Where-Object Setting -eq 'sharingAllowedDomainList').Value | Should -Be 'partner.com; vendor.com' ($rows | Where-Object Setting -eq 'sharingCapability').Category | Should -Be 'Sharing' # Legacy auth bypasses Conditional Access entirely, so it is grouped where a reviewer # will look for it rather than under sharing. ($rows | Where-Object Setting -eq 'isLegacyAuthProtocolsEnabled').Category | Should -Be 'Authentication' } It 'says (none) for an empty list, never blank' { $rows = InModuleScope Msec { Mock Invoke-MsecGraphRequest -MockWith { [pscustomobject]@{ sharingDomainRestrictionMode = 'AllowList' sharingAllowedDomainList = @() } } Get-MsecSharePointTenantSetting } # With an allowList mode, an EMPTY allowed list means nobody outside can be invited at # all. A blank cell reads as "we did not look", which is the one reading that is wrong. ($rows | Where-Object Setting -eq 'sharingAllowedDomainList').Value | Should -Be '(none)' } It 'says (not set) for a null, so it is not confused with off' { $rows = InModuleScope Msec { Mock Invoke-MsecGraphRequest -MockWith { [pscustomobject]@{ sharingCapability = $null } } Get-MsecSharePointTenantSetting } ($rows | Where-Object Setting -eq 'sharingCapability').Value | Should -Be '(not set)' } It 'flattens a nested setting instead of printing a type name' { $rows = InModuleScope Msec { Mock Invoke-MsecGraphRequest -MockWith { [pscustomobject]@{ idleSessionSignOut = [pscustomobject]@{ isEnabled = $true signOutAfterInSeconds = 3600 } } } Get-MsecSharePointTenantSetting } # 'Value = System.Management.Automation.PSCustomObject' tells a reader nothing. ($rows | Where-Object Setting -eq 'idleSessionSignOut.isEnabled').Value | Should -Be 'True' ($rows | Where-Object Setting -eq 'idleSessionSignOut.signOutAfterInSeconds').Value | Should -Be '3600' } It 'returns everything under -All, so the projection can be checked' { $rows = InModuleScope Msec { Mock Invoke-MsecGraphRequest -MockWith { [pscustomobject]@{ sharingCapability = 'Disabled' tenantDefaultTimezone = 'W. Europe Standard Time' } } Get-MsecSharePointTenantSetting -All } # Which settings count as security controls is this command's judgement, so there has # to be a way to see what it left out. ($rows | Where-Object Setting -eq 'tenantDefaultTimezone').Category | Should -Be 'Other' } It 'skips a setting this tenant does not report, rather than inventing a null row' { $rows = InModuleScope Msec { # The property set moves as Microsoft adds settings. A row of nulls for an absent # one reads as "configured off" rather than "not present here". Mock Invoke-MsecGraphRequest -MockWith { [pscustomobject]@{ sharingCapability = 'Disabled' } } Get-MsecSharePointTenantSetting } @($rows).Count | Should -Be 1 } It 'names the permission on a 403, because Graph names none' { InModuleScope Msec { Mock Invoke-MsecGraphRequest -MockWith { throw 'Response status code does not indicate success: 403 (Forbidden).' } # The app already holds Sites.Read.All, so "you need a SharePoint permission" would # send the reader to check one they have. This endpoint needs its own. { Get-MsecSharePointTenantSetting } | Should -Throw '*SharePointTenantSettings.Read.All*' } } It 'throws a clear error when not connected' { InModuleScope Msec { $script:MsecSession = $null { Get-MsecSharePointTenantSetting } | Should -Throw '*Connect-Msec*' } } } |