57 lines
2.8 KiB
PowerShell
57 lines
2.8 KiB
PowerShell
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Path
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
$raw = Get-Content -Raw -Encoding utf8 $Path
|
|
$report = $raw | ConvertFrom-Json
|
|
|
|
$required = @('schema_version', 'mode', 'decision', 'severity', 'counts', 'security_gate', 'verification', 'top_actions', 'findings', 'limitations')
|
|
foreach ($name in $required) {
|
|
if ($null -eq $report.PSObject.Properties[$name]) {
|
|
throw "missing report field: $name"
|
|
}
|
|
}
|
|
|
|
if ($report.mode -notin @('executive', 'standard', 'full')) { throw "invalid report mode" }
|
|
if ($report.decision -notin @('merge', 'action_required', 'reorder', 'observe', 'blocked')) { throw "invalid report decision" }
|
|
if ($report.top_actions.Count -gt 5) { throw "executive report has more than five top actions" }
|
|
if ($raw -match "`e\[|<span|</span>") { throw "JSON contains presentation markers" }
|
|
if ($raw.Contains([char]0xfffd) -or $raw.Contains([char]0)) { throw "JSON contains encoding control characters" }
|
|
if ($raw -match '(?i)(authorization|bearer)\s+[A-Za-z0-9._-]{20,}') { throw "JSON contains a credential-like value" }
|
|
|
|
foreach ($action in @($report.top_actions)) {
|
|
foreach ($name in @('id', 'owner', 'action', 'evidence')) {
|
|
if ($null -eq $action.PSObject.Properties[$name]) { throw "top action missing field: $name" }
|
|
}
|
|
if ($action.evidence.Count -eq 0) { throw "top action has no evidence: $($action.id)" }
|
|
}
|
|
|
|
if ($null -ne $report.PSObject.Properties['run']) {
|
|
foreach ($name in @('run_id', 'trigger', 'as_of')) {
|
|
if ($null -eq $report.run.PSObject.Properties[$name]) { throw "run missing field: $name" }
|
|
}
|
|
if ($report.run.trigger -notin @('pull_request_opened', 'pull_request_synchronized', 'review_submitted', 'schedule', 'manual')) { throw "invalid run trigger" }
|
|
try { [DateTimeOffset]::Parse($report.run.as_of) | Out-Null } catch { throw "invalid run as_of" }
|
|
}
|
|
|
|
if ($null -ne $report.PSObject.Properties['evidence']) {
|
|
$evidenceIds = @{}
|
|
foreach ($item in @($report.evidence)) {
|
|
foreach ($name in @('id', 'kind', 'status', 'ref')) {
|
|
if ($null -eq $item.PSObject.Properties[$name]) { throw "evidence missing field: $name" }
|
|
}
|
|
if ($item.status -notin @('complete', 'partial', 'failed', 'not_run', 'stale')) { throw "invalid evidence status: $($item.id)" }
|
|
if ($evidenceIds.ContainsKey($item.id)) { throw "duplicate evidence id: $($item.id)" }
|
|
$evidenceIds[$item.id] = $true
|
|
}
|
|
}
|
|
|
|
if ($null -ne $report.PSObject.Properties['next_run']) {
|
|
if ($null -eq $report.next_run.PSObject.Properties['reason'] -or $null -eq $report.next_run.PSObject.Properties['after_minutes']) { throw "next_run requires reason and after_minutes" }
|
|
if ([int]$report.next_run.after_minutes -lt 0) { throw "next_run.after_minutes must be non-negative" }
|
|
}
|
|
|
|
Write-Output "maintenance report contract passed: $Path"
|