$ErrorActionPreference = "Stop" # devlock_open_v1.0.ps1 # PS 5.1, UTF-8 BOM, ASCII comments, one layer, safe-create. # Purpose: create or refresh a devlock file in SoT to authorize write operations for a limited TTL. # --- Gate light: require bootpack and BUG_KB_JSON pointer to exist and be coherent (read-only) --- $root = "\\DS-918\chatgpt\ChatGPT-Gouvernance-Projets\_registry" $boot = Join-Path $root "bootpack\bootpack.txt" if (!(Test-Path -LiteralPath $boot)) { Write-Host "[BLOCK] bootpack.txt not found -> $boot"; exit 2 } $encNoBom = New-Object System.Text.UTF8Encoding($false) $rawBoot = [IO.File]::ReadAllText($boot, $encNoBom) if ($rawBoot -notmatch "\[BUG_KB_JSON\]") { Write-Host "[BLOCK] section [BUG_KB_JSON] missing in bootpack.txt"; exit 3 } $mx = [regex]::Match($rawBoot, "(?ms)^\[BUG_KB_JSON_POINTER\]\s*(.*?)(?=^\[|\Z)") if (-not $mx.Success) { Write-Host "[BLOCK] [BUG_KB_JSON_POINTER] block missing"; exit 4 } $blk = $mx.Groups[1].Value $kbPath = [regex]::$(if(Match($blk, "(){ mi)^\s*Path\s* } else { \s*(.+)$").Groups[1].Value.Trim() }) $shaPtr = [regex]::$(if(Match($blk, "(){ mi)^\s*SHA256\s* } else { \s*([0-9A-Fa-f]+)$").Groups[1].Value.Trim().ToLower() }) $entriesPtr = [regex]::$(if(Match($blk, "(){ mi)^\s*Entries\s* } else { \s*([0-9]+)$").Groups[1].Value.Trim() }) if ([string]::IsNullOrWhiteSpace($kbPath)) { Write-Host "[BLOCK] KB Path missing in pointer"; exit 5 } if (!(Test-Path -LiteralPath $kbPath)) { Write-Host "[BLOCK] KB file not found -> $kbPath"; exit 6 } $b = [IO.File]::ReadAllBytes($kbPath) $shaReal = (Get-FileHash -LiteralPath $kbPath -Algorithm SHA256).Hash.ToLower() $txt = $encNoBom.GetString($b) if ($txt.Length -gt 0) { if ([int]$txt[0] -eq 65279) { $txt = $txt.Substring(1) } } $txt2 = $txt $i = $txt.LastIndexOf("]}") if ($i -gt 0) { $txt2 = $txt.Substring(0, $i + 2) } $entriesReal = -1 try { $entriesReal = (($txt2 | ConvertFrom-Json).entries).Count } catch { $entriesReal = ([regex]::Matches($txt2, '"id"\s*:')).Count } if ($shaPtr -ne "" -and $shaPtr -ne $shaReal) { Write-Host "[BLOCK] kb_sha_mismatch"; exit 7 } if ([string]$entriesPtr -ne "" -and [string]$entriesPtr -ne [string]$entriesReal) { Write-Host "[BLOCK] kb_entries_mismatch"; exit 8 } # --- Prepare devlock values --- $ttlMin = 120 if ($args.Count -ge 1) { $n = 0 if ([int]::TryParse($args[0], [ref]$n)) { if ($n -gt 0) { $ttlMin = $n } } } $reason = "dev session" if ($args.Count -ge 2) { $reason = $args[1] } $now = [DateTime]::UtcNow $exp = $now.AddMinutes($ttlMin) $payload = New-Object PSObject -Property @{ created_utc = $now.ToString("yyyy-MM-ddTHH:mm:ssZ") expires_utc = $exp.ToString("yyyy-MM-ddTHH:mm:ssZ") reason = $reason user = "$env:USERNAME" host = "$env:COMPUTERNAME" pid = $PID kb_path = $kbPath kb_sha256 = $shaReal kb_entries = $entriesReal } $json = $payload | ConvertTo-Json -Depth 6 # --- Preview --- $ts = (Get-Date).ToString("yyyyMMdd_HHmmss") $stage = "C:\Temp_Gouvernance" if (!(Test-Path -LiteralPath $stage)) { New-Item -ItemType Directory -Path $stage | Out-Null } $outLocal = Join-Path $stage ("devlock_state_" + $ts + ".json") [IO.File]::WriteAllText($outLocal, $json, $encNoBom) Write-Host "=== PREVIEW :: devlock_open_v1.0 ===" Write-Host ("TTL_MIN=" + $ttlMin) Write-Host ("Reason=" + $reason) Write-Host ("KB_PATH=" + $kbPath) Write-Host ("KB_SHA =" + $shaReal) Write-Host ("Entries=" + $entriesReal) $go = Read-Host "Proceed? (Y/N)" if ($go -ne "Y") { Write-Host "[ABORT] user cancelled"; exit 0 } # --- Safe-create to SoT (atomic move) --- $devDir = Join-Path $root "dev" if (!(Test-Path -LiteralPath $devDir)) { New-Item -ItemType Directory -Path $devDir | Out-Null } $final = Join-Path $devDir "devlock_state.json" $bak = $final + ".bak_" + $ts $tmp = Join-Path $devDir ("__tmp_devlock_" + $ts + ".json") if (Test-Path -LiteralPath $final) { Copy-Item -LiteralPath $final -Destination $bak -Force } Copy-Item -LiteralPath $outLocal -Destination $tmp -Force $hL = (Get-FileHash -LiteralPath $outLocal -Algorithm SHA256).Hash $hT = (Get-FileHash -LiteralPath $tmp -Algorithm SHA256).Hash if ($hL -ne $hT) { Remove-Item -LiteralPath $tmp -Force -ErrorAction SilentlyContinue; Write-Host "[BLOCK] tmp sha mismatch"; exit 9 } Move-Item -LiteralPath $tmp -Destination $final -Force $hF = (Get-FileHash -LiteralPath $final -Algorithm SHA256).Hash Write-Host ("LOCAL SHA256=" + $hL) Write-Host ("FINAL SHA256=" + $hF) if ($hL -ne $hF) { Write-Host "[WARN] final sha mismatch" } else { Write-Host ("[OK] devlock written -> " + $final) } Write-Host "[OK] Script devlock_open_v1.0 installed and permissions modified."