Payload/scripts/kaden/advisory/AdvisoryReportScan.ps1
|
function Get-AdvisoryWorkflowRecordFenceBody { <# .SYNOPSIS Returns the advisory-record body. The record ends only when a line is three backticks and nothing else. .DESCRIPTION Fence text inside the JSON stays in the body. An interior fence sequence does not end the record. #> param([AllowNull()][string]$Text) if ([string]::IsNullOrWhiteSpace([string]$Text)) { return $null } $lines = [regex]::Split([string]$Text, "\r?\n") $start = -1 for ($i = 0; $i -lt $lines.Length; $i++) { if ($lines[$i].Trim() -eq '```advisory-record') { $start = $i break } } if ($start -lt 0) { return $null } $body = [System.Collections.Generic.List[string]]::new() for ($j = $start + 1; $j -lt $lines.Length; $j++) { if ($lines[$j].Trim() -eq '```') { return ($body -join "`n") } [void]$body.Add($lines[$j]) } return $null } function Read-AdvisoryWorkflowScan { param( [Parameter(Mandatory = $true)][string]$FeatureRoot, [Parameter(Mandatory = $true)][string]$Feature ) $files = @() $diagnostics = @() $valid = @() $seen = @{} $unreadable = $false foreach ($file in @(Get-AdvisoryWorkflowReportFile -FeatureRoot $FeatureRoot)) { $relative = Get-AdvisoryWorkflowRepoRelativeReportPath -Feature $Feature -FileName $file.Name try { $read = Read-AdvisoryWorkflowReportText -Path $file.FullName } catch { $unreadable = $true $diagnostics += New-AdvisoryWorkflowDiagnostic -Path $relative -Code 'unreadable' -ObservedProblem 'advisory report is unreadable' -Provenance 'report-scan' continue } $files += [pscustomobject]@{ relative_path = $relative; hash = $read.hash; historical = (Test-AdvisoryWorkflowHistoricalText -Text $read.text) } if (Test-AdvisoryWorkflowHistoricalText -Text $read.text) { continue } # The record ends only on a line that is three backticks. A missing body is partial; an unparseable body is malformed. Both are diagnostics. $fenceBody = Get-AdvisoryWorkflowRecordFenceBody -Text $read.text if ($null -eq $fenceBody) { $diagnostics += New-AdvisoryWorkflowDiagnostic -Path $relative -Code 'partial' -ObservedProblem 'advisory report is partial' continue } $record = Get-AdvisoryWorkflowRecordFromText -Text $read.text if ($null -eq $record) { $diagnostics += New-AdvisoryWorkflowDiagnostic -Path $relative -Code 'malformed' -ObservedProblem 'advisory report record is malformed' continue } $nameMatch = [regex]::Match($file.Name, $script:AdvisoryWorkflowReportNamePattern) $class = Get-AdvisoryReportClassification -Record $record -Feature $Feature -FileTarget $nameMatch.Groups[1].Value ` -FileIteration ([int]$nameMatch.Groups[2].Value) -SeenKeys $seen if ($class.disposition -eq 'exclude') { continue } if ($class.disposition -eq 'diagnostic') { $diagnostics += New-AdvisoryWorkflowDiagnostic -Path $relative -Code $class.code -ObservedProblem $class.problem continue } $seen[$class.key] = $true if ([string](Get-AdvisoryWorkflowProperty -Record $record -Name 'relative_path') -ne $relative) { $record | Add-Member -NotePropertyName relative_path -NotePropertyValue $relative -Force } $valid += $record } $unreadableDiagnostic = $null foreach ($item in @($diagnostics)) { if ([string](Get-AdvisoryWorkflowProperty -Record $item -Name 'code') -eq 'unreadable') { $unreadableDiagnostic = $item break } } return [pscustomobject]@{ failed = $unreadable diagnostic = $unreadableDiagnostic files = @($files | Where-Object { -not $_.historical }) diagnostics = @($diagnostics) valid = @($valid) } } |