param( [string]$ManifestPath ) Set-StrictMode -Version Latest $ErrorActionPreference = "Stop" function Resolve-ProjectRoot { return (Resolve-Path (Join-Path $PSScriptRoot "..")).Path } function Resolve-LatestManifestPath { param( [Parameter(Mandatory = $true)] [string]$ProjectRoot ) $argusRoot = Join-Path (Join-Path $ProjectRoot "artifacts") "argus" if (-not (Test-Path -LiteralPath $argusRoot)) { throw "Argus artifacts directory not found: $argusRoot" } $manifests = Get-ChildItem -LiteralPath $argusRoot -Recurse -Filter "argus-release.json" -File | ForEach-Object { $versionText = Split-Path -Leaf (Split-Path -Parent $_.FullName) $version = $null if (-not [version]::TryParse($versionText, [ref]$version)) { throw "Argus manifest directory is not a version: $($_.FullName)" } [pscustomobject]@{ Version = $version Path = $_.FullName } } | Sort-Object Version -Descending $latest = $manifests | Select-Object -First 1 if (-not $latest) { throw "No argus-release.json files found under $argusRoot" } return $latest.Path } function Assert-RequiredString { param( [Parameter(Mandatory = $true)] [object]$Manifest, [Parameter(Mandatory = $true)] [string]$PropertyName ) if (-not ($Manifest.PSObject.Properties.Name -contains $PropertyName)) { throw "Argus manifest is missing required property: $PropertyName" } $value = [string]$Manifest.$PropertyName if ([string]::IsNullOrWhiteSpace($value)) { throw "Argus manifest property is blank: $PropertyName" } return $value } $projectRoot = Resolve-ProjectRoot $resolvedManifestPath = if ($ManifestPath) { (Resolve-Path -LiteralPath $ManifestPath).Path } else { Resolve-LatestManifestPath -ProjectRoot $projectRoot } $manifestDirectory = Split-Path -Parent $resolvedManifestPath $manifest = Get-Content -LiteralPath $resolvedManifestPath -Raw | ConvertFrom-Json $slug = Assert-RequiredString -Manifest $manifest -PropertyName "slug" $name = Assert-RequiredString -Manifest $manifest -PropertyName "name" $version = Assert-RequiredString -Manifest $manifest -PropertyName "version" $channel = Assert-RequiredString -Manifest $manifest -PropertyName "channel" $platform = Assert-RequiredString -Manifest $manifest -PropertyName "platform" $packageKind = Assert-RequiredString -Manifest $manifest -PropertyName "packageKind" $packageFile = Assert-RequiredString -Manifest $manifest -PropertyName "packageFile" $packageSha256 = Assert-RequiredString -Manifest $manifest -PropertyName "packageSha256" $signerInfo = Assert-RequiredString -Manifest $manifest -PropertyName "signerInfo" if ($platform -ne "android") { throw "Expected platform android, got: $platform" } if ($packageKind -ne "apk") { throw "Expected packageKind apk, got: $packageKind" } if ($packageFile -notmatch '\.apk$') { throw "packageFile must point to an APK: $packageFile" } if ($packageSha256 -notmatch '^[0-9a-f]{64}$') { throw "packageSha256 must be a lowercase SHA-256 hex digest: $packageSha256" } if ($signerInfo -notmatch "Signer #1 certificate SHA-256 digest:") { throw "signerInfo does not contain signer SHA-256 digest." } $pathVersion = Split-Path -Leaf $manifestDirectory if ($version -ne $pathVersion) { throw "Manifest version '$version' does not match artifact directory '$pathVersion'." } $apkPath = Join-Path $manifestDirectory $packageFile if (-not (Test-Path -LiteralPath $apkPath)) { throw "APK from Argus manifest not found: $apkPath" } $idsigPath = $apkPath + ".idsig" if (-not (Test-Path -LiteralPath $idsigPath)) { throw "APK idsig file not found: $idsigPath" } $actualSha256 = ((Get-FileHash -LiteralPath $apkPath -Algorithm SHA256).Hash).ToLowerInvariant() if ($actualSha256 -ne $packageSha256) { throw "APK SHA-256 mismatch. Manifest: $packageSha256 Actual: $actualSha256" } Write-Host "Argus manifest smoke test passed:" Write-Host "Manifest: $resolvedManifestPath" Write-Host "Slug: $slug" Write-Host "Name: $name" Write-Host "Version: $version" Write-Host "Channel: $channel" Write-Host "Package: $apkPath" Write-Host "SHA-256: $actualSha256"