Framework/Core/SVT/SVTControlAttestation.ps1
Set-StrictMode -Version Latest class SVTControlAttestation { [SVTEventContext[]] $ControlResults = $null hidden [bool] $dirtyCommitState = $false; hidden [bool] $abortProcess = $false; hidden [ControlStateExtension] $controlStateExtension = $null; hidden [AttestControls] $AttestControlsChoice; SVTControlAttestation([SVTEventContext[]] $ctrlResults, [AttestControls] $tempAttestControlsChoice ) { $this.ControlResults = $ctrlResults; $this.AttestControlsChoice = $tempAttestControlsChoice; $this.controlStateExtension = [ControlStateExtension]::new() $this.controlStateExtension.Initialize($true) } [AttestationStatus] GetAttestationValue([string] $AttestationCode) { switch($AttestationCode.ToUpper()) { "1" { return [AttestationStatus]::NotAnIssue;} "2" { return [AttestationStatus]::NotFixed;} "9" { $this.abortProcess = $true; return [AttestationStatus]::None; } Default { return [AttestationStatus]::None;} } return [AttestationStatus]::None } [ControlState] ComputeEffectiveControlState([ControlState] $controlState, [ControlSeverity] $ControlSeverity, [bool] $isSubscriptionControl, [SVTEventContext] $controlItem, [ControlResult] $controlResult) { Write-Host "`tControlId : $($controlState.ControlId)`n`tControlSeverity : $ControlSeverity`n`tDescription : $($controlItem.ControlItem.Description)`n`tCurrentControlStatus : $($controlState.ActualVerificationResult)`n" $userChoice = "" $isPrevAttested = $false; if($controlResult.AttestationStatus -ne [AttestationStatus]::None) { $isPrevAttested = $true; } if($isPrevAttested -and ($this.AttestControlsChoice -eq [AttestControls]::All -or $this.AttestControlsChoice -eq [AttestControls]::AlreadyAttested)) { while($userChoice -ne '0' -and $userChoice -ne '1' -and $userChoice -ne '2' -and $userChoice -ne '9' ) { Write-Host "`tPrevious attestation details are as below:`n`tAttestation Status: $($controlState.AttestationStatus)`n`tVerificationResult: $($controlState.EffectiveVerificationResult)`n`tAttested By : $($controlState.State.AttestedBy)`n`tJustification : $($controlState.State.Justification)`n" Write-Host "`tPlease select an action from below: `n`t[0]: None`n`t[1]: Attest`n`t[2]: Clear Attestation" $userChoice = Read-Host "`tUser Choice" $userChoice = $userChoice.Trim(); } } else { while($userChoice -ne '0' -and $userChoice -ne '1' -and $userChoice -ne '9' ) { Write-Host "`tPlease select an action from below: `n`t[0]: None`n`t[1]: Attest" $userChoice = Read-Host "`tUser Choice" $userChoice = $userChoice.Trim(); } } $Justification="" $Attestationstate="" switch ($userChoice.ToUpper()){ "0" #None { } "1" #Attest { $attestationState = "" while($attestationState -ne '0' -and $attestationState -ne '1' -and $attestationState -ne '2' -and $attestationState -ne '9' ) { Write-Host "`n`t`tPlease select an attestation status from below: `n`t`t[0]: None`n`t`t[1]: NotAnIssue`n`t`t[2]: NotFixed" $attestationState = Read-Host "`t`tUser Choice" $attestationState = $attestationState.Trim(); } $attestValue = $this.GetAttestationValue($attestationState); if($attestValue -ne [AttestationStatus]::None) { $controlState.AttestationStatus = $attestValue; } elseif($this.abortProcess) { return $null; } if($controlState.AttestationStatus -ne [AttestationStatus]::None) { $Justification = Read-Host "`t`tJustification" $this.dirtyCommitState = $true } $controlState.EffectiveVerificationResult = [Helpers]::EvaluateVerificationResult($controlState.ActualVerificationResult,$controlState.AttestationStatus); if($null -ne $controlResult.StateManagement -and $null -ne $controlResult.StateManagement.CurrentStateData) { $controlState.State = $controlResult.StateManagement.CurrentStateData; } if($null -eq $controlState.State) { $controlState.State = [StateData]::new(); } $controlState.State.AttestedBy = [Helpers]::GetCurrentSessionUser(); $controlState.State.AttestedDate = [DateTime]::UtcNow; $controlState.State.Justification = $Justification break; } "2" #Clear Attestation { $this.dirtyCommitState = $true #Clears the control state. This overrides the previous attested controlstate. $controlState.State = $null; $controlState.EffectiveVerificationResult = $controlState.ActualVerificationResult $controlState.AttestationStatus = [AttestationStatus]::None } "9" #Abort { $this.abortProcess = $true; return $null; } Default { } } return $controlState; } [void] StartControlAttestation() { try { Write-Host $([Constants]::HashLine) -ForegroundColor Green Write-Host "Starting Control Attestation workflow...`n" -ForegroundColor Cyan Write-Host "Note: Enter 9 during the attestation workflow to abort." if($null -eq $this.ControlResults) { Write-Host "No control results found." -ForegroundColor Yellow } $this.abortProcess = $false; #filtering the controls - Removing all the passed controls #Step1 Group By IDs $filteredControlResults = @() $filteredControlResults += $this.ControlResults | Group-Object { $_.GetUniqueId() } #show warning if the keys count is greater than certain number. #start iterating resource after resource foreach($resource in $filteredControlResults) { $resourceValueKey = $resource.Name $this.dirtyCommitState = $false; $resourceValue = $resource.Group; $isSubscriptionScan = $false; if(($resourceValue | Measure-Object).Count -gt 0) { $SubscriptionId = $resourceValue[0].SubscriptionContext.SubscriptionId if($null -ne $resourceValue[0].ResourceContext) { $ResourceId = $resourceValue[0].ResourceContext.ResourceId Write-Host $([String]::Format([Constants]::ModuleAttestStartHeading, $resourceValue[0].FeatureName, $resourceValue[0].ResourceContext.ResourceGroupName, $resourceValue[0].ResourceContext.ResourceName)) -ForegroundColor Cyan } else { $isSubscriptionScan = $true; Write-Host $([String]::Format([Constants]::ModuleAttestStartHeadingSub, $resourceValue[0].FeatureName, $resourceValue[0].SubscriptionContext.SubscriptionName, $resourceValue[0].SubscriptionContext.SubscriptionId)) -ForegroundColor Cyan } [ControlState[]] $resourceControlStates = @() $count = 0; [SVTEventContext[]] $filteredControlItems = @() $resourceValue | ForEach-Object { $controlItem = $_; $matchedControlItem = $false; if(($controlItem.ControlResults | Measure-Object).Count -gt 0) { [ControlResult[]] $matchedControlResults = @(); $controlItem.ControlResults | ForEach-Object { $controlResult = $_ if($controlResult.ActualVerificationResult -ne [VerificationResult]::Passed) { if($this.AttestControlsChoice -eq [AttestControls]::All) { $matchedControlItem = $true; $matchedControlResults += $controlResult; $count++; } elseif($this.AttestControlsChoice -eq [AttestControls]::AlreadyAttested -and $controlResult.AttestationStatus -ne [AttestationStatus]::None) { $matchedControlItem = $true; $matchedControlResults += $controlResult; $count++; } elseif($this.AttestControlsChoice -eq [AttestControls]::NotAttested -and $controlResult.AttestationStatus -eq [AttestationStatus]::None) { $matchedControlItem = $true; $matchedControlResults += $controlResult; $count++; } } } } if($matchedControlItem) { $controlItem.ControlResults = $matchedControlResults; $filteredControlItems += $controlItem; } } if($count -gt 0) { Write-Host "`tNo. of controls that need to be attested: $count`n$([Constants]::SingleDashLine)" foreach( $controlItem in $filteredControlItems) { $controlId = $controlItem.ControlItem.ControlID $controlSeverity = $controlItem.ControlItem.ControlSeverity $controlResult = $null; $controlStatus = ""; $isPrevAttested = $false; if(($controlItem.ControlResults | Measure-Object).Count -gt 0) { foreach( $controlResult in $controlItem.ControlResults) { $controlStatus = $controlResult.ActualVerificationResult; [ControlState] $controlState = [ControlState]::new($controlId,$controlItem.ControlItem.Id,$controlResult.ChildResourceName,$controlStatus,"1.0"); if($null -ne $controlResult.StateManagement -and $null -ne $controlResult.StateManagement.AttestedStateData) { $controlState.State = $controlResult.StateManagement.AttestedStateData } $controlState.AttestationStatus = $controlResult.AttestationStatus $controlState.EffectiveVerificationResult = $controlResult.VerificationResult $controlState = $this.ComputeEffectiveControlState($controlState, $controlSeverity, $isSubscriptionScan, $controlItem, $controlResult) $resourceControlStates +=$controlState; if($this.abortProcess) { Write-Host "`tAborted the attestation workflow." return; } } } Write-Host $([Constants]::SingleDashLine) -ForegroundColor Cyan } } else { Write-Host "`tNo attestable controls found.`n$([Constants]::SingleDashLine)" } #remove the entries which doesnt have any state #$resourceControlStates = $resourceControlStates | Where-Object {$_.State} #persist the value back to state if($this.dirtyCommitState) { if(($resourceControlStates | Measure-Object).Count -gt 0) { Write-Host "`tSummary:" $output = @() $resourceControlStates | ForEach-Object { $out = "" | Select-Object ControlId, ActualVerificationResult, EffectiveVerificationResult, AttestationStatus $out.ControlId = $_.ControlId $out.ActualVerificationResult = $_.ActualVerificationResult $out.EffectiveVerificationResult = $_.EffectiveVerificationResult $out.AttestationStatus = $_.AttestationStatus.ToString() $output += $out } Write-Host ($output | FT ControlId, ActualVerificationResult, EffectiveVerificationResult, AttestationStatus | Out-String) } $this.controlStateExtension.SetControlState($resourceValueKey, $resourceControlStates, $false) Write-Host "`tSuccessfully persisted the attestation." } if($null -ne $resourceValue[0].ResourceContext) { $ResourceId = $resourceValue[0].ResourceContext.ResourceId Write-Host $([String]::Format([Constants]::CompletedAttestAnalysis, $resourceValue[0].FeatureName, $resourceValue[0].ResourceContext.ResourceGroupName, $resourceValue[0].ResourceContext.ResourceName)) -ForegroundColor Cyan } else { $isSubscriptionScan = $true; Write-Host $([String]::Format([Constants]::CompletedAttestAnalysisSub, $resourceValue[0].FeatureName, $resourceValue[0].SubscriptionContext.SubscriptionName, $resourceValue[0].SubscriptionContext.SubscriptionId)) -ForegroundColor Cyan } } } } finally { $this.controlStateExtension.CleanTempFolder(); } } } |