# kb_bootpack_acceptance_v1.0.ps1 # Purpose: Validate BootPack gate ([BUG_KB_JSON] + [BUG_KB_JSON_POINTER]) and list blocking entries. # Strict PS 5.1: ASCII-only literals, no PS7 ops, no ternary, no here-strings. # Output: # 1) Summary: entries=|blocking=|ptr_exists=|ptr_sha_match=|ptr_entries_note=|json_entries= # 2) Either: [GATE-BLOCK] blocking ids: (exit 9) # Or : [PASS] BootPack acceptance OK. (exit 0) param( [string]$Root='\\DS-918\\chatgpt\\ChatGPT-Gouvernance-Projets\\_registry' ) function New-Dir([string]$p){ if(-not (Test-Path -LiteralPath $p)){ New-Item -ItemType Directory -Force -Path $p | Out-Null } } function Read-All([string]$p){ Get-Content -LiteralPath $p -Encoding UTF8 } function Get-SHA256([string]$p){ if(-not (Test-Path -LiteralPath $p)){ return '' } try{ (Get-FileHash -Algorithm SHA256 -LiteralPath $p).Hash.ToUpperInvariant() }catch{ '' } } $ts=(Get-Date).ToString('yyyyMMdd_HHmmss') $boot=Join-Path $Root 'bootpack\\bootpack.txt' $logs=Join-Path $Root 'logs' New-Dir $logs $log=Join-Path $logs ('bootpack_accept_'+$ts+'.log') if(-not (Test-Path -LiteralPath $boot)){ Write-Host '[GATE-BLOCK] bootpack.txt not found.' -ForegroundColor Red exit 1 } $lines=Read-All $boot # ---- Parse [BUG_KB_JSON_POINTER] (Path/SHA256/Entries) ---- $ptrPath='' $ptrSha='' $ptrEntries=-1 $inPtr=$false for($i=0;$i -lt $lines.Length;$i++){ $line=$lines[$i] if($line -match '^\s*\[BUG_KB_JSON_POINTER\]\s*$'){ $inPtr=$true; continue } if($inPtr){ if($line -match '^\s*\['){ break } elseif($line -match '^\s*Path:\s*(.+)\s*$'){ $ptrPath=$Matches[1] } elseif($line -match '^\s*SHA256:\s*([0-9a-fA-F]{64})\s*$'){ $ptrSha=$Matches[1].ToUpperInvariant() } elseif($line -match '^\s*Entries:\s*(\d+)\s*$'){ $ptrEntries=[int]$Matches[1] } } } # ---- Extract fenced JSON from [BUG_KB_JSON] ---- $idxStart=-1; $idxFenceStart=-1; $idxFenceEnd=-1 for($i=0;$i -lt $lines.Length;$i++){ $line=$lines[$i] if($idxStart -lt 0){ if($line -match '^\s*\[BUG_KB_JSON\]\s*$'){ $idxStart=$i; continue } } else { if($idxFenceStart -lt 0){ if($line -match '^\s*```'){ $idxFenceStart=$i+1; continue } } else { if($line -match '^\s*```'){ $idxFenceEnd=$i-1; break } } } } if($idxStart -lt 0 -or $idxFenceStart -lt 0 -or $idxFenceEnd -lt 0 -or $idxFenceEnd -lt $idxFenceStart){ Write-Host '[GATE-BLOCK] [BUG_KB_JSON] missing or not fenced.' -ForegroundColor Red Add-Content -LiteralPath $log -Value 'reason=missing_or_unfenced' exit 2 } $buf=New-Object System.Collections.Generic.List[string] for($j=$idxFenceStart;$j -le $idxFenceEnd;$j++){ $buf.Add($lines[$j]) } $json=($buf -join "`n") try{ $kbObj = $json | ConvertFrom-Json } catch{ Write-Host '[GATE-BLOCK] invalid JSON in [BUG_KB_JSON].' -ForegroundColor Red Add-Content -LiteralPath $log -Value 'reason=json_parse_error' exit 3 } # ---- Validate pointer file and compute SHA ---- $ptrExists = $false $ptrShaReal = '' $ptrCountJson = -1 if($kbObj.entries){ $ptrCountJson = $kbObj.entries.Count } if(-not [string]::IsNullOrWhiteSpace($ptrPath)){ if(Test-Path -LiteralPath $ptrPath){ $ptrExists=$true; $ptrShaReal = Get-SHA256 $ptrPath } } # ---- Blocking scan ---- $blocking=@() $entriesCount=0 if($kbObj.entries){ foreach($e in $kbObj.entries){ $entriesCount++ if($e.blocking -eq $true){ $blocking+=,$e } } } $ids=($blocking | ForEach-Object { $_.id }) -join ',' # ---- Emit summary ---- $summary=('entries=' + $entriesCount + '|blocking=' + ($blocking.Count) + '|ptr_exists=' + ($ptrExists) + '|ptr_sha_match=' + ([string]::Equals($ptrShaReal,$ptrSha,[System.StringComparison]::OrdinalIgnoreCase)) + '|ptr_entries_note=' + $ptrEntries + '|json_entries=' + $ptrCountJson) Write-Host $summary Add-Content -LiteralPath $log -Value $summary if(-not $ptrExists){ Write-Host ('[GATE-BLOCK] KB pointer path not found: ' + $ptrPath) -ForegroundColor Red exit 8 } if(($blocking.Count) -gt 0){ Write-Host ('[GATE-BLOCK] blocking ids: ' + $ids) -ForegroundColor Red exit 9 } Write-Host '[PASS] BootPack acceptance OK.' -ForegroundColor Green exit 0 # [OK] Script kb_bootpack_acceptance_v1.0.ps1 généré (livrable).