Windows installer: payload hash-locking, SBOM, client-IP handling, operator docs
This commit is contained in:
110
deploy/windows/installer/refresh-bundle-lock.ps1
Normal file
110
deploy/windows/installer/refresh-bundle-lock.ps1
Normal file
@@ -0,0 +1,110 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Regenerate bundle-lock.json from the staged bundle, after showing what would
|
||||
change.
|
||||
|
||||
.DESCRIPTION
|
||||
Run this on the machine that assembled the wheelhouse, once the bundle holds
|
||||
the payload you intend to ship:
|
||||
|
||||
bundle\wheels\ the wheels, built with the matching Python
|
||||
bundle\python\ the Python installer
|
||||
bundle\httpplatformhandler\ the IIS module MSI
|
||||
bundle\urlrewrite\ URL Rewrite MSI (optional)
|
||||
bundle\mysql\ MySQL MSI (optional)
|
||||
|
||||
Then COMMIT the resulting bundle-lock.json. That commit is the review: it is
|
||||
the only place a change to what runs as SYSTEM on a customer's server becomes
|
||||
visible to a human. A lock regenerated and committed without reading the diff
|
||||
provides nothing, so this refuses to overwrite an existing lock until you
|
||||
have seen the change and passed -Yes.
|
||||
|
||||
.EXAMPLE
|
||||
.\refresh-bundle-lock.ps1 # show the diff, write nothing
|
||||
.\refresh-bundle-lock.ps1 -Yes # write it
|
||||
|
||||
.NOTES
|
||||
Building the wheelhouse itself no longer requires Windows. From any machine:
|
||||
pip download -r requirements.txt -d wheels --only-binary=:all: `
|
||||
--platform win_amd64 --python-version 314 --implementation cp --abi cp314
|
||||
Do it wherever you like; this script records what came out.
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string] $BundleRoot = (Join-Path $PSScriptRoot 'bundle'),
|
||||
[string] $LockPath = (Join-Path $PSScriptRoot 'bundle-lock.json'),
|
||||
[string] $PythonTag = 'cp314',
|
||||
[string] $Platform = 'win_amd64',
|
||||
[switch] $Yes
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
. (Join-Path $PSScriptRoot 'bundle-lock.ps1')
|
||||
|
||||
function Say { param($m, $c = 'Gray') Write-Host $m -ForegroundColor $c }
|
||||
|
||||
if (-not (Test-Path $BundleRoot)) {
|
||||
Say "bundle not found: $BundleRoot" 'Red'
|
||||
Say 'Stage it first with build-installer.ps1 (or build-installer.sh), then add' 'Yellow'
|
||||
Say 'the wheels and installers by hand.' 'Yellow'
|
||||
exit 1
|
||||
}
|
||||
|
||||
Say ''
|
||||
Say " Hashing $BundleRoot" 'Cyan'
|
||||
$new = New-BundleLock -BundleRoot $BundleRoot -PythonTag $PythonTag -Platform $Platform
|
||||
|
||||
foreach ($name in $new.payloads.Keys) {
|
||||
Say (" {0,-22} {1,4} files" -f $name, $new.payloads[$name].files.Count)
|
||||
}
|
||||
|
||||
$old = Read-BundleLock $LockPath
|
||||
if (-not $old) {
|
||||
Say ''
|
||||
Say ' No existing lock - this will be the first one.' 'Yellow'
|
||||
} else {
|
||||
# Diff by file, per payload, so the operator sees exactly which artifacts
|
||||
# changed rather than "the lock is different".
|
||||
Say ''
|
||||
Say ' Changes against the committed lock:' 'Cyan'
|
||||
$changes = 0
|
||||
foreach ($name in $new.payloads.Keys) {
|
||||
$oldFiles = @{}
|
||||
if ($old.payloads.PSObject.Properties.Name -contains $name) {
|
||||
foreach ($p in $old.payloads.$name.files.PSObject.Properties) { $oldFiles[$p.Name] = $p.Value.sha256 }
|
||||
}
|
||||
$newFiles = $new.payloads[$name].files
|
||||
foreach ($rel in ($newFiles.Keys | Sort-Object)) {
|
||||
if (-not $oldFiles.ContainsKey($rel)) { Say " + $name/$rel" 'Green'; $changes++ }
|
||||
elseif ($oldFiles[$rel] -ne $newFiles[$rel].sha256) { Say " ~ $name/$rel (content changed)" 'Yellow'; $changes++ }
|
||||
}
|
||||
foreach ($rel in ($oldFiles.Keys | Sort-Object)) {
|
||||
if (-not $newFiles.ContainsKey($rel)) { Say " - $name/$rel" 'Red'; $changes++ }
|
||||
}
|
||||
}
|
||||
foreach ($p in $old.payloads.PSObject.Properties.Name) {
|
||||
if (-not $new.payloads.Contains($p)) { Say " - $p/ (whole payload gone)" 'Red'; $changes++ }
|
||||
}
|
||||
if ($changes -eq 0) {
|
||||
Say ' none - the bundle already matches the lock' 'Green'
|
||||
exit 0
|
||||
}
|
||||
Say ''
|
||||
Say (" {0} change(s)." -f $changes) 'White'
|
||||
}
|
||||
|
||||
if (-not $Yes) {
|
||||
Say ''
|
||||
Say ' Nothing written. Read the list above, then re-run with -Yes.' 'Yellow'
|
||||
Say ' Commit the resulting bundle-lock.json - that commit IS the review.' 'Yellow'
|
||||
exit 2
|
||||
}
|
||||
|
||||
# ConvertTo-Json defaults to a depth of 2, which silently flattens the per-file
|
||||
# entries into "System.Collections.Hashtable" strings and produces a lock that
|
||||
# verifies against nothing.
|
||||
$new | ConvertTo-Json -Depth 8 | Set-Content -Path $LockPath -Encoding UTF8
|
||||
Say ''
|
||||
Say " Written: $LockPath" 'Green'
|
||||
Say ' Commit it.' 'Green'
|
||||
Reference in New Issue
Block a user