gitlink-cli/skills/gitlink-shared/examples/validate-maintenance-report...

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"