77 lines
4.9 KiB
PowerShell
77 lines
4.9 KiB
PowerShell
#Requires -Version 5.1
|
|
# Shared prebuilt-artifact packaging helpers. No builds or downloads.
|
|
function Assert-PackageOrdinaryFile([string]$Path) {
|
|
$item = Get-Item -LiteralPath $Path
|
|
if ($item.PSIsContainer) { throw "Package input is a directory: $Path" }
|
|
$current = $item
|
|
while ($null -ne $current) {
|
|
if (($current.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) { throw "Package input has a symlink/reparse ancestor: $($current.FullName)" }
|
|
$current = if ($current -is [IO.FileInfo]) { $current.Directory } else { $current.Parent }
|
|
}
|
|
}
|
|
|
|
function Invoke-PackageHelper([string]$Python, [string[]]$Arguments) {
|
|
$raw = @(& $Python (Join-Path $PSScriptRoot 'package-artifacts.py') @Arguments)
|
|
if ($LASTEXITCODE -ne 0) { throw 'Package artifact preflight/verification failed.' }
|
|
if ($raw.Count) { return (($raw -join "`n") | ConvertFrom-Json) }
|
|
}
|
|
|
|
function Get-PackageDocumentation([string]$Repository, [string]$Platform, [string]$Python) {
|
|
$result = Invoke-PackageHelper $Python @('docs', '--repository', $Repository, '--platform', $Platform)
|
|
$inputs = [ordered]@{}
|
|
foreach ($entry in $result.files) { $inputs[$entry.path] = $entry.source }
|
|
return $inputs
|
|
}
|
|
|
|
function Read-PackageBuildEvidence([string]$Path, [string]$Target, $BinaryHashes) {
|
|
if (-not $Path) { return $null }
|
|
$evidence = Get-Content -LiteralPath $Path -Raw | ConvertFrom-Json
|
|
foreach ($field in @('source_identity', 'profile', 'compiler', 'target', 'binary_sha256')) {
|
|
if (-not $evidence.PSObject.Properties[$field]) { throw "Build evidence missing $field" }
|
|
}
|
|
if ($evidence.target -ne $Target) { throw 'Build evidence target differs from requested package target.' }
|
|
foreach ($field in @('source_identity', 'profile', 'compiler')) {
|
|
if ($evidence.$field -isnot [string] -or [string]::IsNullOrWhiteSpace($evidence.$field)) { throw "Build evidence $field must be explicit nonempty text." }
|
|
}
|
|
foreach ($name in $BinaryHashes.Keys) {
|
|
if (-not $evidence.binary_sha256.PSObject.Properties[$name] -or $evidence.binary_sha256.$name -cne $BinaryHashes[$name]) { throw "Build evidence binary hash mismatch: $name" }
|
|
}
|
|
return [ordered]@{ assertion = 'Caller-supplied build evidence; target and binary hashes checked, source/compiler/profile statements not inferred or independently proven by packaging.'; evidence = $evidence }
|
|
}
|
|
|
|
function Write-PackageNotices([string]$Stage, $Notices) {
|
|
$encoding = New-Object Text.UTF8Encoding($false)
|
|
[IO.File]::WriteAllText((Join-Path $Stage 'dependency-notices.json'), ($Notices.Inventory | ConvertTo-Json -Depth 18) + "`n", $encoding)
|
|
$index = @('Third-party notice inventory', '', 'Exact versions, license expressions, source hashes and notice paths: dependency-notices.json', 'License texts and embedded-asset notices: licenses/', 'Rust distribution notices: licenses/rust/', 'Collection does not establish binary/source equivalence or a universal license audit.', '')
|
|
foreach ($package in $Notices.Inventory.packages) { $index += "$($package.name) $($package.version) -- $($package.license) -- licenses/dependencies/$($package.name)-$($package.version)/" }
|
|
[IO.File]::WriteAllText((Join-Path $Stage 'THIRD-PARTY-NOTICES.txt'), ($index -join "`n") + "`n", $encoding)
|
|
}
|
|
|
|
function Copy-PackageInputs([string]$Stage, $Inputs, $InspectedHashes) {
|
|
$hashes = [ordered]@{}
|
|
foreach ($name in $Inputs.Keys) {
|
|
Assert-PackageOrdinaryFile $Inputs[$name]
|
|
$source = Get-Item -LiteralPath $Inputs[$name]
|
|
if ($source.PSIsContainer -or ($source.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) { throw "Package input must be an ordinary file: $name" }
|
|
$destination = Join-Path $Stage $name
|
|
[void][IO.Directory]::CreateDirectory([IO.Path]::GetDirectoryName($destination))
|
|
$before = (Get-FileHash -LiteralPath $source.FullName -Algorithm SHA256).Hash.ToLowerInvariant()
|
|
if ($InspectedHashes.ContainsKey($name) -and $InspectedHashes[$name] -ne $before) { throw "Input changed after inspection: $name" }
|
|
[IO.File]::Copy($source.FullName, $destination, $false)
|
|
if ((Get-FileHash -LiteralPath $destination -Algorithm SHA256).Hash.ToLowerInvariant() -ne $before) { throw "Input changed during staging: $name" }
|
|
$hashes[$name] = $before
|
|
}
|
|
return $hashes
|
|
}
|
|
|
|
function Write-PackageChecksums([string]$Stage) {
|
|
$encoding = New-Object Text.UTF8Encoding($false)
|
|
$lines = New-Object 'Collections.Generic.List[string]'
|
|
foreach ($file in Get-ChildItem -LiteralPath $Stage -Recurse -File | Sort-Object FullName) {
|
|
$relative = $file.FullName.Substring($Stage.Length + 1).Replace('\', '/')
|
|
if ($relative -eq 'SHA256SUMS.txt') { throw 'Package checksum manifest already exists.' }
|
|
$lines.Add((Get-FileHash -LiteralPath $file.FullName -Algorithm SHA256).Hash.ToLowerInvariant() + ' ' + $relative)
|
|
}
|
|
[IO.File]::WriteAllText((Join-Path $Stage 'SHA256SUMS.txt'), ($lines -join "`n") + "`n", $encoding)
|
|
}
|