# build_bootpack_and_manifest_seedbox_v1.0.ps1 # Objet : idem HUB mais PROJECT_PROFILE_REF=SEEDBOX_MANAGER ; rappel encodage annexe .ps1 (UTF-8 BOM) et scripts /bin/sh ASCII-only côté Seedbox. param([switch]$Preview,[switch]$Write) function New-Nonce([int]$n=10){ $a=(48..57+65..90+97..122); -join (1..$n|%{[char]($a|Get-Random)}) } function Write-NoBOM([string]$Path,[string]$Text){ $enc=New-Object System.Text.UTF8Encoding($false); [IO.File]::WriteAllText($Path,$Text,$enc) } function Get-FileSHA256([string]$Path){ if(Test-Path $Path){ (Get-FileHash -Algorithm SHA256 -LiteralPath $Path).Hash } else { '' } } function Compute-TextSHA256([string]$Text){ $sha=[Security.Cryptography.SHA256]::Create(); $bytes=[Text.Encoding]::UTF8.GetBytes($Text); ($sha.ComputeHash($bytes)|%{ $_.ToString('x2') }) -join '' } function Ensure-Parent([string]$Path){ $p=Split-Path -Parent $Path; if($p -and !(Test-Path $p)){ New-Item -ItemType Directory -Force -Path $p|Out-Null } } function Safe-ReplaceFile([string]$Target,[string]$Text){ Ensure-Parent $Target $ts=Get-Date -Format 'yyyyMMdd_HHmmss' $tmp="$Target.$ts.tmp"; $bak="$Target.bak_$ts" Write-NoBOM $tmp $Text $shaTmp=(Get-FileHash -Algorithm SHA256 -LiteralPath $tmp).Hash if(Test-Path $Target){ Copy-Item -LiteralPath $Target -Destination $bak -Force } Move-Item -LiteralPath $tmp -Destination $Target -Force $shaFinal=(Get-FileHash -Algorithm SHA256 -LiteralPath $Target).Hash @{Bak=$bak;ShaTmp=$shaTmp;ShaFinal=$shaFinal} } function Replace-Section([string]$Content,[string]$Name,[string]$Body){ $pattern = "(?ms)^\[" + [regex]::Escape($Name) + "\]\s*.*?(?=^\[|\Z)" $block = "["+$Name+"]`r`n"+($Body.Trim())+"`r`n" if([regex]::IsMatch($Content,$pattern)){ return [regex]::Replace($Content,$pattern,$block) } else { return ($Content.TrimEnd()+"`r`n`r`n"+$block) } } function Read-FileText([string]$p){ if(Test-Path $p){ [IO.File]::ReadAllText($p,[Text.UTF8Encoding]::new($true)) } else { '' } } function Count-KBEntries([string]$kbPath){ $raw=Read-FileText $kbPath $idx=$raw.LastIndexOf(']}'); if($idx -gt 0){ $raw=$raw.Substring(0,$idx+2) } try{ ($raw | ConvertFrom-Json).entries.Count }catch{ [regex]::Matches($raw,'"id"\s*:').Count } } $Root='\\DS-918\chatgpt\ChatGPT-Gouvernance-Projets\_registry' $BootPack="$Root\bootpack\bootpack.txt" $KBPointerPath="$Root\bootpack\bootpack_paste.txt" $ProfileFile="$Root\profiles\project\SEEDBOX\PROJECT_PROFILE.txt" $Snapshot="$Root\snapshots\snapshot_{0}.json" -f (Get-Date -Format 'yyyy-MM-dd') $L0=@('GOV_SCRIPT_GATE v1.4','SAFE-WRITE v1.1','TXT-ONLY v1.0','SYNC-MEM-ARCHIVE-RULE v1.0','SYNC-GUARD v1.1') if(!(Test-Path $BootPack)){ throw "[BLOCKING] BootPack introuvable: $BootPack" } $bp=Read-FileText $BootPack $bp=Replace-Section $bp 'POLICY' ($L0 -join ' ; ') $profileBody = "PROFILE_FILE: $ProfileFile`r`nPROFILE_SHA256: " $bp=Replace-Section $bp 'PROJECT_PROFILE_REF' $profileBody $kbSha=Get-FileSHA256 $KBPointerPath $kbEntries=Count-KBEntries $KBPointerPath $kbSize=(Test-Path $KBPointerPath) ? (Get-Item $KBPointerPath).Length : 0 $kbUpdated=(Get-Item $KBPointerPath).LastWriteTimeUtc.ToString("yyyy-MM-ddTHH:mm:ssZ") $kbBody = "Path: $KBPointerPath`r`nSHA256: $kbSha`r`nEntries: $kbEntries`r`nSizeBytes: $kbSize`r`nUpdated: $kbUpdated" $bp=Replace-Section $bp 'BUG_KB_JSON_POINTER' $kbBody if(!(Test-Path $Snapshot)){ Ensure-Parent $Snapshot; Write-NoBOM $Snapshot "{}`r`n" } $snapSha=Get-FileSHA256 $Snapshot $files=@("$Root\REGLES_GOUVERNANCE.txt","$Root\SAFE-WRITE-RULE_v1.1.txt","$Root\GOV_SCRIPT_GATE_v1.4.txt","$Root\TXT-ONLY-POLICY_v1.0.txt") $lines=@(); foreach($f in $files){ $h=Get-FileSHA256 $f; if(!$h){$h='MISSING'}; $lines+=" $f = $h" } $filesShaBlock=($lines -join "`r`n") $memId=(Get-Date).ToString('yyyy-MM-ddTHH:mm:ssK'); $nonce=New-Nonce 10 $syncCore=("MEM_SYNC_ID: {0}`r`nRULESET_ACTIVE: {1}`r`nSNAPSHOT_FILE: {2}`r`nSNAPSHOT_SHA256: {3}`r`nFILES_SHA256:`r`n{4}`r`nNONCE: {5}" -f $memId,($L0 -join ' ; '),$Snapshot,$snapSha,$filesShaBlock,$nonce).Trim() $manifestSha=Compute-TextSHA256 $syncCore $syncBody="$syncCore`r`nMANIFEST_SHA256: $manifestSha" $bp=Replace-Section $bp 'SYNC_MANIFEST' $syncBody $kbAsserts=@" KB-AUTO-ps-5-1-operateur-ternaire-non-supporte-20251018_135633 = covered_by: RULE_PS51_NO_TERNARY v1.0 KB-AUTO-ps-5-1-select-string-sans-recurse-boucler-fichiers-20251018_160307 = covered_by: RULE_SEARCH_NO_RECURSE v1.0 KB-AUTO-join-path-ne-pas-passer-un-tableau-en-childpath-20251018_161141 = covered_by: RULE_SAFE_JOINPATH v1.0 KB-AUTO-safe-write-creer-repertoires-avant-tmp-20251018_160648 = covered_by: RULE_SAFE_WRITE_ENSURE_PARENT v1.0 KB-AUTO-ps-5-1-ps1-en-utf-8-avec-bom-ou-ascii-strict-20251018_162239 = covered_by: RULE_PS1_UTF8_BOM v1.0 KB-AUTO-executionpolicy-allsigned-sur-unc-utiliser-bypass-... = covered_by: RULE_CMD_WRAPPER_BYPASS v1.0 "@ $bp=Replace-Section $bp 'KB_GUARD_ASSERTS' $kbAsserts $profileTxt=@" PROJECT=SEEDBOX_MANAGER RUNTIME=POSIX_sh ENCODING=.sh=ASCII_only ; .ps1=UTF8_BOM (annexes Windows) CONSTRAINTS=NoAdmin ; UNC ; OneDrivePersonalSeparate "@ Ensure-Parent $ProfileFile; Write-NoBOM $ProfileFile $profileTxt $profileSha=Get-FileSHA256 $ProfileFile $bp=Replace-Section $bp 'PROJECT_PROFILE_REF' ("PROFILE_FILE: {0}`r`nPROFILE_SHA256: {1}" -f $ProfileFile,$profileSha) $footer="; DOC-VERSION-FOOTER: build_bootpack_and_manifest_seedbox_v1.0.ps1 | "+(Get-Date -Format 'yyyy-MM-dd')+" | SHA="+(Compute-TextSHA256 $bp) $plan=@" == PREVIEW :: BUILD BOOTPACK (SEEDBOX) == Target BootPack : $BootPack Snapshot : $Snapshot (SHA=$snapSha) PROFILE_FILE : $ProfileFile (SHA=$profileSha) KB Pointer : $KBPointerPath (SHA=$kbSha, Entries=$kbEntries, Size=$kbSize, Updated=$kbUpdated) RULESET_ACTIVE : $($L0 -join ' ; ') MEM_SYNC_ID : $memId MANIFEST_SHA256 : $manifestSha "@ Write-Host $plan if(-not $Write){ if(-not $Preview){ $r=Read-Host "Confirmer l'écriture ? (O/N)"; if($r -notin @('O','o','Y','y')){ Write-Host "Abandon (preview only)."; exit 0 } } else { Write-Host "Mode PREVIEW : aucune écriture effectuée."; exit 0 } } $final=($bp.TrimEnd()+"`r`n"+$footer+"`r`n") $result=Safe-ReplaceFile -Target $BootPack -Text $final Write-Host ("Backup : {0}" -f $result.Bak) Write-Host ("SHA tmp/final: {0} / {1}" -f $result.ShaTmp,$result.ShaFinal) Write-Host ("SYNC-COMMIT-OK - MEM_SYNC_ID={0}" -f $memId)