PrintToVeraeTimeStamp/platform/windows/scripts/fill-manifest-sha256.ps1
George Lambert da4a0dc4e2
Some checks failed
windows-msi / full-msi-unsigned (push) Has been cancelled
feat: fill-manifest-sha256.ps1 + CERT local font-face first
Hash helper for DOWNLOADS-MANIFEST; certificate.html prefers fonts/*.woff2 when present.
2026-10-14 00:27:11 -04:00

152 lines
4.6 KiB
PowerShell

#Requires -Version 5.1
<#
.SYNOPSIS
Compute SHA-256 of built MSI/NSIS (or companion EXE) and print DOWNLOADS-MANIFEST rows.
.DESCRIPTION
Given one or more paths to release artifacts (setup.exe, .msi, bare helper .exe),
prints SHA256SUMS-style lines matching site/printit.verae.ai/DOWNLOADS-MANIFEST.txt:
<lowercase-hex> <leaf-name>
Optionally prints a Markdown table row for DOWNLOADS-MANIFEST.md.
Does NOT upload, rewrite the site manifests, or sign. Operator order remains:
build → sign (when required) → upload → hash → paste digests over TBD.
.EXITCODES
0 At least one path hashed successfully.
1 No paths, missing file, or terminating error.
.PARAMETER Path
One or more artifact paths (MSI, NSIS setup.exe, optional bare helper).
Also accepts leftover positional args and pipeline input (strings or FileInfo).
.PARAMETER Format
txt — SHA256SUMS lines only (default; paste into DOWNLOADS-MANIFEST.txt).
md — Markdown table rows for DOWNLOADS-MANIFEST.md.
both — txt then md (md after a blank line).
.PARAMETER AsName
Override the leaf name written in the row (single Path only). Use when the
local build name differs from the CDN filename reserved in the manifest.
.EXAMPLE
powershell -NoProfile -ExecutionPolicy Bypass -File fill-manifest-sha256.ps1 `
-Path .\dist\VeraePrintStamp-windows-amd64-0.3.6-setup.exe,
.\platform\windows\wix\out\VeraePrintStamp-windows-amd64-0.3.6.msi
.EXAMPLE
.\fill-manifest-sha256.ps1 -Path .\out\product.msi -AsName VeraePrintStamp-windows-amd64-0.3.6.msi -Format both
#>
param(
[Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
[Alias("FullName", "PSPath")]
[string[]]$Path = @(),
[ValidateSet("txt", "md", "both")]
[string]$Format = "txt",
[string]$AsName = ""
)
begin {
$ErrorActionPreference = "Stop"
$collected = New-Object System.Collections.Generic.List[string]
}
process {
foreach ($p in @($Path)) {
if ($null -eq $p) { continue }
$s = "$p".Trim()
if (-not $s) { continue }
# Pipeline FileInfo often arrives as Microsoft.PowerShell.Core\FileSystem::path
if ($s -match '^Microsoft\.PowerShell\.Core\\FileSystem::(.+)$') {
$s = $Matches[1]
}
[void]$collected.Add($s)
}
}
end {
# Leftover unbound args (powershell -File script.ps1 a.msi b.exe)
if ($args -and $args.Count -gt 0) {
foreach ($a in $args) {
$s = "$a".Trim()
if ($s) { [void]$collected.Add($s) }
}
}
if ($collected.Count -eq 0) {
Write-Error "No artifact paths given. Pass -Path <msi|setup.exe|...> (does not upload)."
}
if ($AsName -and $collected.Count -gt 1) {
Write-Error "-AsName applies to a single -Path only."
}
$rows = New-Object System.Collections.Generic.List[object]
foreach ($raw in $collected) {
if (-not (Test-Path -LiteralPath $raw)) {
Write-Error "Artifact not found: $raw"
}
$item = Get-Item -LiteralPath $raw
if ($item.PSIsContainer) {
Write-Error "Path is a directory (need file): $raw"
}
$hash = (Get-FileHash -LiteralPath $item.FullName -Algorithm SHA256).Hash.ToLowerInvariant()
$leaf = if ($AsName) { $AsName.Trim() } else { $item.Name }
if (-not $leaf) {
Write-Error "Empty leaf name for $raw"
}
[void]$rows.Add([pscustomobject]@{
Hash = $hash
Name = $leaf
FullName = $item.FullName
Length = $item.Length
})
}
function Write-TxtRows {
param($Items)
foreach ($r in $Items) {
# Two spaces between digest and name — same as DOWNLOADS-MANIFEST.txt / shasum -a 256
Write-Output ("{0} {1}" -f $r.Hash, $r.Name)
}
}
function Write-MdRows {
param($Items)
foreach ($r in $Items) {
$role = "artifact"
$channel = "file"
$n = $r.Name
if ($n -match '\.msi$') {
$channel = "Full MSI"
$role = "Dual-ship / fleet path"
} elseif ($n -match '-setup\.exe$') {
$channel = "NSIS"
$role = "Windows setup"
} elseif ($n -match '^verae-print-windows-.*\.exe$') {
$channel = "Bare helper"
$role = "Optional companion EXE"
}
Write-Output ("| `{0}` | {1} | {2} | `{3}` | hashed locally (not uploaded by this script) |" -f $n, $channel, $role, $r.Hash)
}
}
Write-Host "# fill-manifest-sha256: local hash only — does not upload or edit site manifests." -ForegroundColor DarkGray
Write-Host "# Paste over TBD in DOWNLOADS-MANIFEST.txt only after the blob is on the CDN." -ForegroundColor DarkGray
switch ($Format) {
"txt" { Write-TxtRows $rows }
"md" { Write-MdRows $rows }
"both" {
Write-TxtRows $rows
Write-Output ""
Write-MdRows $rows
}
}
exit 0
}