Skip to content

Commit

Permalink
Add the report UUID to the ScubaResults.json filename (#1426)
Browse files Browse the repository at this point in the history
* Initial implementation of adding UUID to the file name

* Add back missing ConvertFrom-Json call

* Mock Get-ChildItem in unit tests

* Document addition of UUID to ScubaResults file name

* Add unit tests for when there are multiple ScubaResults*.json files

* Correct minor typo in documentation

* remove wildcard search in ConvertTo-ResultsCSV code path

* add error handling of window path length limit errors

* fix some of the tests

* fix the all the current broken unit tests

* additional unit tests

* add back in accidentally removed fields in config

* complete lorem ipsum

* todo message

* remove UUID truncation for now

* first draft

* add truncation param to documentation

* spacing

* fix failing test cases; handle full truncation case

* make code consistent; add code comments to describe it's purpose

* review feedback; point to additional options in the error message

* PR Review: Fix absolute path check; fix config file override

* review feedback; move new parameter in alphabetical order in docs

* keep documentation consistent

* remove configuration paramset from scubacached

* code comments for the new edge case

* Remove OBE unit test

* Remove duplicate word

* fix typos, wording and formatting in config

* Refactor truncation logic into own function

* rm duplicate text from PowerShell as well

* captialize

* remove long path check let the set-content naturally error out

* add long path error check within the catch block

* remove todo

* Add UUID to mock data for cached tests

* Fix unit tests

* Remove commented out validation code.

Co-authored-by: mitchelbaker-cisa <[email protected]>

* add validation set to check invalid config file parameter

* Remove stacktrace

---------

Co-authored-by: buidav <[email protected]>
Co-authored-by: mitchelbaker-cisa <[email protected]>
  • Loading branch information
3 people authored and schrolla committed Nov 25, 2024
1 parent 3f33804 commit ffae2e1
Show file tree
Hide file tree
Showing 10 changed files with 392 additions and 161 deletions.
242 changes: 178 additions & 64 deletions PowerShell/ScubaGear/Modules/Orchestrator.psm1

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions PowerShell/ScubaGear/Modules/ScubaConfig/ScubaConfig.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class ScubaConfig {
DefaultOutJsonFileName = "ScubaResults"
DefaultOutCsvFileName = "ScubaResults"
DefaultOutActionPlanFileName = "ActionPlan"
DefaultNumberOfUUIDCharactersToTruncate = 18
DefaultPrivilegedRoles = @(
"Global Administrator",
"Privileged Role Administrator",
Expand Down Expand Up @@ -156,6 +157,10 @@ class ScubaConfig {
$this.Configuration.OutActionPlanFileName = [ScubaConfig]::ScubaDefault('DefaultOutActionPlanFileName')
}

if (-Not $this.Configuration.NumberOfUUIDCharactersToTruncate){
$this.Configuration.NumberOfUUIDCharactersToTruncate = [ScubaConfig]::ScubaDefault('DefaultNumberOfUUIDCharactersToTruncate')
}

return
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
},
"Tool": "ScubaGear",
"ToolVersion": "1.4.0",
"TimestampZulu": "2024-08-02T19:25:11.166Z"
"TimestampZulu": "2024-08-02T19:25:11.166Z",
"ReportUUID": "21189b0e-f045-43ee-b9ba-653b32744e45"
},
"Summary": {
"AAD": {
Expand Down Expand Up @@ -1339,6 +1340,7 @@
"module_version": "1.4.0",
"date": "08/02/2024 14:25:11 Central Daylight Time",
"timestamp_zulu": "2024-08-02T19:25:11.166Z",
"report_uuid": "21189b0e-f045-43ee-b9ba-653b32744e45",
"tenant_details": [
{
"AADAdditionalData": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ InModuleScope Orchestrator {
Mock -CommandName Get-FileEncoding
Mock -CommandName ConvertTo-Csv { "" }
Mock -CommandName Write-Warning {}
Mock -CommandName Get-ChildItem {
[pscustomobject]@{"FullName"="ScubaResults_00000000-0000-0000-0000-000000000000.json"; "CreationTime"=[DateTime]"2024-01-01"}
}
}

It 'Handles multiple products, control groups, and controls' {
Expand Down Expand Up @@ -56,10 +59,10 @@ InModuleScope Orchestrator {
}}
}
$CsvParameters = @{
ProductNames = @("exo", "aad");
OutFolderPath = ".";
OutJsonFileName = "ScubaResults";
OutCsvFileName = "ScubaResults";
ProductNames = @("exo", "aad");
OutFolderPath = ".";
FullScubaResultsName = "ScubaResults";
OutCsvFileName = "ScubaResults";
OutActionPlanFileName = "ActionPlan";
}
{ ConvertTo-ResultsCsv @CsvParameters} | Should -Not -Throw
Expand All @@ -74,10 +77,10 @@ InModuleScope Orchestrator {
Mock -CommandName ConvertFrom-Json {}
Mock -CommandName Get-Content { throw "File not found" }
$CsvParameters = @{
ProductNames = @("exo", "aad");
OutFolderPath = ".";
OutJsonFileName = "ScubaResults";
OutCsvFileName = "ScubaResults";
ProductNames = @("exo", "aad");
OutFolderPath = ".";
FullScubaResultsName = "ScubaResults";
OutCsvFileName = "ScubaResults";
OutActionPlanFileName = "ActionPlan";
}
{ ConvertTo-ResultsCsv @CsvParameters} | Should -Not -Throw
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
$OrchestratorPath = '../../../../Modules/Orchestrator.psm1'
Import-Module (Join-Path -Path $PSScriptRoot -ChildPath $OrchestratorPath) -Function 'Get-FullOutJsonName'

Describe -Tag 'Orchestrator' -Name 'Get-FullOutJsonName' {
InModuleScope Orchestrator {
It 'Adds the full UUID' {
$FullNameParams = @{
'OutJsonFileName' = "ScubaResults";
'Guid' = "30ebce05-f8f0-4a09-8ec2-589efbbd0e72";
'NumberOfUUIDCharactersToTruncate' = 0;
}
(Get-FullOutJsonName @FullNameParams) | Should -eq "ScubaResults_30ebce05-f8f0-4a09-8ec2-589efbbd0e72.json"
}
It 'Handles partial truncation' {
$FullNameParams = @{
'OutJsonFileName' = "ScubaResults";
'Guid' = "30ebce05-f8f0-4a09-8ec2-589efbbd0e72";
'NumberOfUUIDCharactersToTruncate' = 18;
}
(Get-FullOutJsonName @FullNameParams) | Should -eq "ScubaResults_30ebce05-f8f0-4a09.json"
}
It 'Handles full truncation' {
$FullNameParams = @{
'OutJsonFileName' = "ScubaResults";
'Guid' = "30ebce05-f8f0-4a09-8ec2-589efbbd0e72";
'NumberOfUUIDCharactersToTruncate' = 36;
}
(Get-FullOutJsonName @FullNameParams) | Should -eq "ScubaResults.json"
}
It 'Handles non-default names' {
$FullNameParams = @{
'OutJsonFileName' = "my_results";
'Guid' = "30ebce05-f8f0-4a09-8ec2-589efbbd0e72";
'NumberOfUUIDCharactersToTruncate' = 18;
}
(Get-FullOutJsonName @FullNameParams) | Should -eq "my_results_30ebce05-f8f0-4a09.json"
}
}
}

AfterAll {
Remove-Module Orchestrator -ErrorAction SilentlyContinue
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,13 @@ Describe -Tag 'Orchestrator' -Name 'Invoke-ProviderList' {
BeforeAll {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'ProviderParameters')]
$ProviderParameters = @{
OutFolderPath = "./output";
OutProviderFileName = "ProviderSettingsExport";
M365Environment = "commercial";
TenantDetails = '{"DisplayName": "displayName"}';
ModuleVersion = '1.0';
BoundParameters = @{};
OutFolderPath = "./output";
OutProviderFileName = "ProviderSettingsExport";
M365Environment = "commercial";
TenantDetails = '{"DisplayName": "displayName"}';
ModuleVersion = '1.0';
BoundParameters = @{};
Guid = "00000000-0000-0000-0000-000000000000"
}
}
It 'With -ProductNames "aad", should not throw' {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,16 @@ InModuleScope Orchestrator {

Mock -CommandName Write-Debug {}
Mock -CommandName New-Item {}
Mock -CommandName Get-Content {}
Mock -CommandName Get-Content { "" }
Mock -CommandName Get-Member { $true }
Mock -CommandName New-Guid { "00000000-0000-0000-0000-000000000000" }
Mock -CommandName Get-ChildItem {
[pscustomobject]@{"FullName"="ScubaResults.json"; "CreationTime"=[DateTime]"2024-01-01"}
}
Mock -CommandName Remove-Item {}
Mock -CommandName ConvertFrom-Json {
[PSCustomObject]@{"report_uuid"="00000000-0000-0000-0000-000000000000"}
}
}
Context 'When checking the conformance of commercial tenants' {
BeforeAll {
Expand Down Expand Up @@ -126,6 +133,7 @@ InModuleScope Orchestrator {
Should -Invoke -CommandName New-Guid -Exactly -Times 0
}
It 'Given output without a UUID should generate a new one' {
Mock -CommandName ConvertFrom-Json { [PSCustomObject]@{} }
Mock -CommandName Get-Member { $false }
# Now Get-Member will return False so as far as the provider
# can tell, the existing output does not have a UUID
Expand Down Expand Up @@ -166,6 +174,27 @@ InModuleScope Orchestrator {
{Invoke-SCuBACached @SplatParams} | Should -Throw
}
}
Context "When there are multiple ScubaResults*.json files" {
# It's possible (but not expected) that there are multiple files matching
# "ScubaResults*.json". In this case, ScubaGear should choose the file
# created most recently.
It 'Should select the most recently created' {
Mock -CommandName Get-ChildItem { @(
[pscustomobject]@{"FullName"="ScubaResultsOld.json"; "CreationTime"=[DateTime]"2023-01-01"},
[pscustomobject]@{"FullName"="ScubaResultsNew.json"; "CreationTime"=[DateTime]"2024-01-01"},
[pscustomobject]@{"FullName"="ScubaResultsOldest.json"; "CreationTime"=[DateTime]"2022-01-01"}
) }

Mock -CommandName Get-Content {
if ($Path -ne "ScubaResultsNew.json") {
# Should be the new one, throw if not
throw
}
}

{Invoke-SCuBACached @SplatParams} | Should -Throw
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ Import-Module (Join-Path -Path $PSScriptRoot -ChildPath $OrchestratorPath) -Func
InModuleScope Orchestrator {
Describe -Tag 'Orchestrator' -Name 'Merge-JsonOutput' {
BeforeAll {
Mock -CommandName Join-Path { "." }
Mock -CommandName Out-File {}
Mock -CommandName Set-Content {}
Mock -CommandName Remove-Item {}
Mock -CommandName Get-Content { "" }
Mock -CommandName ConvertFrom-Json { @{
"ReportSummary"=@{"Date"=""}
"Results"=@();
"timestamp_zulu"="";
}
"ReportSummary" = @{"Date" = "" }
"Results" = @();
"timestamp_zulu" = "";
"report_uuid" = "00000000-0000-0000-0000-000000000000"
}
}
Mock -CommandName Add-Member {}
Mock -CommandName ConvertTo-Json { "" }
Expand All @@ -22,34 +22,38 @@ InModuleScope Orchestrator {
BeforeAll {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'JsonParameters')]
$JsonParameters = @{
TenantDetails = @{"DisplayName" = "displayName"; "TenantId" = "tenantId"; "DomainName" = "domainName"};
ModuleVersion = '1.0';
OutFolderPath = "./"
OutProviderFileName = "ProviderSettingsExport"
OutJsonFileName = "ScubaResults"
TenantDetails = @{"DisplayName" = "displayName"; "TenantId" = "tenantId"; "DomainName" = "domainName" };
ModuleVersion = '1.0';
OutFolderPath = "./";
OutProviderFileName = "ProviderSettingsExport";
FullScubaResultsName = "ScubaResults.json";
Guid = "00000000-0000-0000-0000-000000000000";
}
}
It 'Merge single result' {
Mock -CommandName Join-Path { "." }
$JsonParameters += @{
ProductNames = @("aad")
ProductNames = @("aad");
}
{ Merge-JsonOutput @JsonParameters} | Should -Not -Throw
{ Merge-JsonOutput @JsonParameters } | Should -Not -Throw
Should -Invoke -CommandName ConvertFrom-Json -Exactly -Times 2
$JsonParameters.ProductNames = @()
}
It 'Merge multiple results' {
Mock -CommandName Join-Path { "." }
$JsonParameters += @{
ProductNames = @("aad", "teams")
ProductNames = @("aad", "teams");
}
{ Merge-JsonOutput @JsonParameters} | Should -Not -Throw
{ Merge-JsonOutput @JsonParameters } | Should -Not -Throw
Should -Invoke -CommandName ConvertFrom-Json -Exactly -Times 3
$JsonParameters.ProductNames = @()
}
It 'Delete redundant files' {
Mock -CommandName Join-Path { "." }
$JsonParameters += @{
ProductNames = @("aad", "teams")
ProductNames = @("aad", "teams");
}
{ Merge-JsonOutput @JsonParameters} | Should -Not -Throw
{ Merge-JsonOutput @JsonParameters } | Should -Not -Throw
Should -Invoke -CommandName Remove-Item -Exactly -Times 3
$JsonParameters.ProductNames = @()
}
Expand Down
Loading

0 comments on commit ffae2e1

Please sign in to comment.