ci / verify (push) Canceled after 0s
Add customer and operator login, BLE provisioning, device fleet controls, call memory, memoir generation, and refreshed family and maintenance portals. Include API contracts, migrations, firmware sources, tests, assets, and deployment documentation.
56 lines
3.7 KiB
PowerShell
56 lines
3.7 KiB
PowerShell
param([Parameter(Mandatory=$true)][string]$Archive)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
$archivePath = (Resolve-Path -LiteralPath $Archive).Path
|
|
$archiveDirectory = Split-Path -Parent $archivePath
|
|
$sidecarPath = $archivePath + '.sha256'
|
|
if (-not (Test-Path -LiteralPath $sidecarPath -PathType Leaf)) { throw 'Archive checksum sidecar is missing' }
|
|
$sidecarHash = ((Get-Content -LiteralPath $sidecarPath -Raw).Trim() -split '\s+')[0]
|
|
$archiveHash = (Get-FileHash -LiteralPath $archivePath -Algorithm SHA256).Hash.ToLowerInvariant()
|
|
if ($sidecarHash -ne $archiveHash) { throw 'Archive checksum sidecar does not match' }
|
|
|
|
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
|
$zip = [IO.Compression.ZipFile]::OpenRead($archivePath)
|
|
try {
|
|
$forbidden = @($zip.Entries | Where-Object {
|
|
$_.FullName -match '(^|/)(\.env|node_modules|runtime)(/|$)' -or
|
|
$_.FullName -match '\.(pem|key|p12|pfx)$'
|
|
})
|
|
if ($forbidden.Count -gt 0) { throw ('Bundle contains forbidden entries: ' + ($forbidden.FullName -join ', ')) }
|
|
$entryCount = $zip.Entries.Count
|
|
} finally {
|
|
$zip.Dispose()
|
|
}
|
|
|
|
$verificationRoot = Join-Path $archiveDirectory ('.verify-' + [Guid]::NewGuid().ToString('N'))
|
|
New-Item -ItemType Directory -Path $verificationRoot | Out-Null
|
|
try {
|
|
Expand-Archive -LiteralPath $archivePath -DestinationPath $verificationRoot
|
|
$payload = @(Get-ChildItem -LiteralPath $verificationRoot -Directory)
|
|
if ($payload.Count -ne 1) { throw 'Bundle must contain exactly one top-level directory' }
|
|
$manifestPath = Join-Path $payload[0].FullName 'deploy-manifest.json'
|
|
$checksumsPath = Join-Path $payload[0].FullName 'SHA256SUMS'
|
|
$manifest = Get-Content -LiteralPath $manifestPath -Raw | ConvertFrom-Json
|
|
$expectedMigration = (Get-ChildItem -LiteralPath (Join-Path $payload[0].FullName 'migrations') -Filter '*.up.sql' | ForEach-Object { [int]($_.Name -split '_')[0] } | Measure-Object -Maximum).Maximum
|
|
if ($manifest.schema_version -ne 'server-deployment-bundle-v1' -or $manifest.schema_migration_target -ne $expectedMigration -or $expectedMigration -le 0 -or $manifest.hardware_runtime -ne 'volc_hardware_agent') {
|
|
throw 'Deployment manifest metadata is invalid'
|
|
}
|
|
$verifiedFiles = 0
|
|
foreach ($line in Get-Content -LiteralPath $checksumsPath) {
|
|
if ($line -notmatch '^([0-9a-f]{64}) (.+)$') { throw "Invalid checksum line: $line" }
|
|
$target = [IO.Path]::GetFullPath((Join-Path $payload[0].FullName $Matches[2]))
|
|
if (-not $target.StartsWith($payload[0].FullName + [IO.Path]::DirectorySeparatorChar, [StringComparison]::OrdinalIgnoreCase)) { throw 'Checksum target escapes bundle root' }
|
|
if (-not (Test-Path -LiteralPath $target -PathType Leaf)) { throw "Checksum target is missing: $($Matches[2])" }
|
|
if ((Get-FileHash -LiteralPath $target -Algorithm SHA256).Hash.ToLowerInvariant() -ne $Matches[1]) { throw "Checksum mismatch: $($Matches[2])" }
|
|
$verifiedFiles++
|
|
}
|
|
if ($verifiedFiles -ne ($manifest.files.Count + 1)) { throw 'Checksum coverage does not match manifest plus manifest file' }
|
|
[ordered]@{ archive = $archivePath; sha256 = $archiveHash; zip_entries = $entryCount; verified_files = $verifiedFiles; candidate_version = $manifest.candidate_version; schema_migration_target = $manifest.schema_migration_target } | ConvertTo-Json -Compress
|
|
} finally {
|
|
$resolvedVerificationRoot = [IO.Path]::GetFullPath($verificationRoot)
|
|
$resolvedArchiveDirectory = [IO.Path]::GetFullPath($archiveDirectory)
|
|
if ($resolvedVerificationRoot.StartsWith($resolvedArchiveDirectory + [IO.Path]::DirectorySeparatorChar, [StringComparison]::OrdinalIgnoreCase) -and (Test-Path -LiteralPath $resolvedVerificationRoot)) {
|
|
Remove-Item -LiteralPath $resolvedVerificationRoot -Recurse -Force
|
|
}
|
|
}
|