Skip to content

fix: publish discovery headers with generated site #112

fix: publish discovery headers with generated site

fix: publish discovery headers with generated site #112

Workflow file for this run

name: CI
on:
push:
branches:
- main
- master
pull_request:
permissions:
contents: read
jobs:
docker-smoke:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Build and probe non-root scratch image
run: make docker-smoke
web:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.3.10
- name: Install web dependencies
run: bun install --frozen-lockfile
- name: Frontend quality gate
run: bun run test
- name: Build site and embedded app
run: bun run build
- name: Verify generated assets and prerender
shell: bash
run: |
test -z "$(git status --porcelain -- docs internal/resources/app/dist)"
grep -Fq 'What is happening on this device?' docs/index.html
if grep -Fq '<div id="root"></div>' docs/index.html; then
echo 'Homepage was not prerendered.' >&2
exit 1
fi
web-build-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.3.10
- name: Install web dependencies
run: bun install --frozen-lockfile
- name: Build site and embedded app on Windows
run: |
bun run build:app
bun run build:site
- name: Verify cross-platform generated assets
shell: pwsh
run: |
$generatedChanges = git status --porcelain -- docs internal/resources/app/dist
if ($generatedChanges) {
$generatedChanges | Write-Error
throw 'Windows generated assets differ from the committed build.'
}
go:
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- macos-latest
- windows-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
- name: Go test
run: go test ./...
- name: Compile both commands
run: go build ./cmd/protopeek ./cmd/pp
installer-unix:
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- macos-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
- name: Exercise verified installer and failure paths
shell: bash
run: |
set -euo pipefail
fixture="$(mktemp -d)"
payload="$fixture/payload"
install_dir="$fixture/install"
man_dir="$fixture/man"
archive="$fixture/protopeek_test_native_x86_64.tar.gz"
mkdir -p "$payload/man"
go build -ldflags '-X main.version=vtest' -o "$payload/protopeek" ./cmd/protopeek
go build -ldflags '-X main.version=vtest' -o "$payload/pp" ./cmd/pp
cp web/site/public/man/protopeek.1 web/site/public/man/pp.1 "$payload/man/"
tar -C "$payload" -czf "$archive" protopeek pp man
if command -v sha256sum >/dev/null 2>&1; then
hash="$(sha256sum "$archive" | awk '{print $1}')"
else
hash="$(shasum -a 256 "$archive" | awk '{print $1}')"
fi
printf '%s %s\n' "$hash" "$(basename "$archive")" > "$fixture/checksums.txt"
PROTOPEEK_DOWNLOAD_URL="file://$archive" \
PROTOPEEK_CHECKSUM_URL="file://$fixture/checksums.txt" \
PROTOPEEK_INSTALL_DIR="$install_dir" \
PROTOPEEK_MAN_DIR="$man_dir" \
sh ./install.sh
"$install_dir/protopeek" -version
"$install_dir/pp" -version
test -f "$man_dir/protopeek.1"
test -f "$man_dir/pp.1"
# Resolve the rolling channel from a local release-shaped fixture, without
# using an explicit download URL or consulting the stable GitHub endpoint.
nightly_os="$(uname -s | tr '[:upper:]' '[:lower:]')"
[ "$nightly_os" != darwin ] || nightly_os=osx
case "$(uname -m)" in arm64|aarch64) nightly_arch=arm64 ;; *) nightly_arch=x86_64 ;; esac
nightly_name="protopeek_0.0.0-nightly_${nightly_os}_${nightly_arch}.tar.gz"
mkdir -p "$fixture/releases/v0.0.0-nightly"
cp "$archive" "$fixture/releases/v0.0.0-nightly/$nightly_name"
printf '%s %s\n' "$hash" "$nightly_name" > "$fixture/releases/v0.0.0-nightly/checksums.txt"
PROTOPEEK_CHANNEL=nightly \
PROTOPEEK_DOWNLOAD_BASE_URL="file://$fixture/releases" \
PROTOPEEK_INSTALL_DIR="$fixture/nightly-install" \
PROTOPEEK_MAN_DIR="$man_dir" \
sh ./install.sh
"$fixture/nightly-install/protopeek" -version
"$fixture/nightly-install/pp" -version
printf 'replaced after install\n' > "$fixture/replaced-pp"
chmod +x "$fixture/replaced-pp"
mv -f "$fixture/replaced-pp" "$install_dir/pp"
PROTOPEEK_DOWNLOAD_URL="file://$archive" \
PROTOPEEK_CHECKSUM_URL="file://$fixture/checksums.txt" \
PROTOPEEK_INSTALL_DIR="$install_dir" \
PROTOPEEK_MAN_DIR="$man_dir" \
sh ./install.sh
grep -Fxq 'replaced after install' "$install_dir/pp"
legacy="$fixture/protopeek_legacy_native_x86_64.tar.gz"
tar -C "$payload" -czf "$legacy" protopeek
if command -v sha256sum >/dev/null 2>&1; then
legacy_hash="$(sha256sum "$legacy" | awk '{print $1}')"
else
legacy_hash="$(shasum -a 256 "$legacy" | awk '{print $1}')"
fi
printf '%s %s\n' "$legacy_hash" "$(basename "$legacy")" > "$fixture/legacy-checksums.txt"
PROTOPEEK_DOWNLOAD_URL="file://$legacy" \
PROTOPEEK_CHECKSUM_URL="file://$fixture/legacy-checksums.txt" \
PROTOPEEK_INSTALL_DIR="$fixture/legacy-install" \
PROTOPEEK_MAN_DIR="$man_dir" \
sh ./install.sh
"$fixture/legacy-install/protopeek" -version
"$fixture/legacy-install/pp" -version
conflict_dir="$fixture/conflict"
mkdir -p "$conflict_dir"
printf 'unrelated pp\n' > "$conflict_dir/pp"
chmod +x "$conflict_dir/pp"
PROTOPEEK_DOWNLOAD_URL="file://$archive" \
PROTOPEEK_CHECKSUM_URL="file://$fixture/checksums.txt" \
PROTOPEEK_INSTALL_DIR="$conflict_dir" \
PROTOPEEK_MAN_DIR="$man_dir" \
sh ./install.sh
grep -Fxq 'unrelated pp' "$conflict_dir/pp"
"$conflict_dir/protopeek" -version
corrupt="$fixture/protopeek_corrupt_native_x86_64.tar.gz"
cp "$archive" "$corrupt"
printf 'corrupt' >> "$corrupt"
sed "s#$(basename "$archive")#$(basename "$corrupt")#" "$fixture/checksums.txt" > "$fixture/corrupt-checksums.txt"
if PROTOPEEK_DOWNLOAD_URL="file://$corrupt" \
PROTOPEEK_CHECKSUM_URL="file://$fixture/corrupt-checksums.txt" \
PROTOPEEK_INSTALL_DIR="$fixture/corrupt-install" \
sh ./install.sh; then
echo 'Corrupt archive unexpectedly installed.' >&2
exit 1
fi
if PROTOPEEK_DOWNLOAD_URL="file://$archive" \
PROTOPEEK_CHECKSUM_URL="file://$fixture/missing-checksums.txt" \
PROTOPEEK_INSTALL_DIR="$fixture/missing-install" \
sh ./install.sh; then
echo 'Archive without checksums unexpectedly installed.' >&2
exit 1
fi
installer-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
- name: Exercise verified installer and failure paths
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
$fixture = Join-Path $env:RUNNER_TEMP 'protopeek-installer'
$env:PROTOPEEK_NO_SHORTCUTS = '1'
$payload = Join-Path $fixture 'payload'
$installDir = Join-Path $fixture 'install'
$archive = Join-Path $fixture 'protopeek_test_windows_x86_64.zip'
New-Item -ItemType Directory -Path $payload -Force | Out-Null
go build -ldflags '-X main.version=vtest' -o (Join-Path $payload 'protopeek.exe') ./cmd/protopeek
go build -ldflags '-X main.version=vtest' -o (Join-Path $payload 'pp.exe') ./cmd/pp
Compress-Archive -Path (Join-Path $payload '*') -DestinationPath $archive -Force
$hash = (Get-FileHash -LiteralPath $archive -Algorithm SHA256).Hash.ToLowerInvariant()
$checksums = Join-Path $fixture 'checksums.txt'
Set-Content -LiteralPath $checksums -Value "$hash $([IO.Path]::GetFileName($archive))"
& ./install.ps1 -DownloadUrl $archive -ChecksumUrl $checksums -InstallDir $installDir -NoPathUpdate
& (Join-Path $installDir 'protopeek.exe') -version
& (Join-Path $installDir 'pp.exe') -version
$nightlyDir = Join-Path $fixture 'releases/v0.0.0-nightly'
New-Item -ItemType Directory -Path $nightlyDir -Force | Out-Null
$nightlyName = 'protopeek_0.0.0-nightly_windows_x86_64.zip'
Copy-Item -LiteralPath $archive -Destination (Join-Path $nightlyDir $nightlyName)
Set-Content -LiteralPath (Join-Path $nightlyDir 'checksums.txt') -Value "$hash $nightlyName"
$env:PROTOPEEK_DOWNLOAD_BASE_URL = Join-Path $fixture 'releases'
try {
& ./install.ps1 -Channel nightly -InstallDir (Join-Path $fixture 'nightly-install') -NoPathUpdate
& (Join-Path $fixture 'nightly-install/protopeek.exe') -version
& (Join-Path $fixture 'nightly-install/pp.exe') -version
} finally {
Remove-Item Env:PROTOPEEK_DOWNLOAD_BASE_URL
}
# Windows PowerShell 5.1 and pwsh must both support the documented
# pipeline invocation, including running from System32.
powershell.exe -NoProfile -File ./scripts/test-install-pipeline.ps1 -Installer ./install.ps1 -Archive $archive -Checksums $checksums -FixtureRoot (Join-Path $fixture 'windows-powershell')
if ($LASTEXITCODE -ne 0) { throw 'Windows PowerShell pipeline installation failed.' }
pwsh -NoProfile -File ./scripts/test-install-pipeline.ps1 -Installer ./install.ps1 -Archive $archive -Checksums $checksums -FixtureRoot (Join-Path $fixture 'pwsh')
if ($LASTEXITCODE -ne 0) { throw 'PowerShell 7 pipeline installation failed.' }
$replacement = Join-Path $fixture 'replaced-pp.exe'
Set-Content -LiteralPath $replacement -Value 'replaced after install' -NoNewline
Move-Item -LiteralPath $replacement -Destination (Join-Path $installDir 'pp.exe') -Force
& ./install.ps1 -DownloadUrl $archive -ChecksumUrl $checksums -InstallDir $installDir -NoPathUpdate
if ((Get-Content -LiteralPath (Join-Path $installDir 'pp.exe') -Raw) -ne 'replaced after install') { throw 'A replaced pp.exe alias was overwritten.' }
$legacy = Join-Path $fixture 'protopeek_legacy_windows_x86_64.zip'
Compress-Archive -Path (Join-Path $payload 'protopeek.exe') -DestinationPath $legacy -Force
$legacyHash = (Get-FileHash -LiteralPath $legacy -Algorithm SHA256).Hash.ToLowerInvariant()
$legacyChecksums = Join-Path $fixture 'legacy-checksums.txt'
Set-Content -LiteralPath $legacyChecksums -Value "$legacyHash $([IO.Path]::GetFileName($legacy))"
$legacyInstall = Join-Path $fixture 'legacy-install'
& ./install.ps1 -DownloadUrl $legacy -ChecksumUrl $legacyChecksums -InstallDir $legacyInstall -NoPathUpdate
& (Join-Path $legacyInstall 'protopeek.exe') -version
& (Join-Path $legacyInstall 'pp.exe') -version
$conflictDir = Join-Path $fixture 'conflict'
New-Item -ItemType Directory -Path $conflictDir -Force | Out-Null
Set-Content -LiteralPath (Join-Path $conflictDir 'pp.exe') -Value 'unrelated pp' -NoNewline
& ./install.ps1 -DownloadUrl $archive -ChecksumUrl $checksums -InstallDir $conflictDir -NoPathUpdate
if ((Get-Content -LiteralPath (Join-Path $conflictDir 'pp.exe') -Raw) -ne 'unrelated pp') { throw 'Conflicting pp.exe was overwritten.' }
& (Join-Path $conflictDir 'protopeek.exe') -version
$corrupt = Join-Path $fixture 'protopeek_corrupt_windows_x86_64.zip'
Copy-Item -LiteralPath $archive -Destination $corrupt
Add-Content -LiteralPath $corrupt -Value 'corrupt'
$corruptChecksums = Join-Path $fixture 'corrupt-checksums.txt'
Set-Content -LiteralPath $corruptChecksums -Value "$hash $([IO.Path]::GetFileName($corrupt))"
try {
& ./install.ps1 -DownloadUrl $corrupt -ChecksumUrl $corruptChecksums -InstallDir (Join-Path $fixture 'corrupt-install') -NoPathUpdate
throw 'Corrupt archive unexpectedly installed.'
} catch {
if ($_.Exception.Message -eq 'Corrupt archive unexpectedly installed.') { throw }
}
try {
& ./install.ps1 -DownloadUrl $archive -ChecksumUrl (Join-Path $fixture 'missing.txt') -InstallDir (Join-Path $fixture 'missing-install') -NoPathUpdate
throw 'Archive without checksums unexpectedly installed.'
} catch {
if ($_.Exception.Message -eq 'Archive without checksums unexpectedly installed.') { throw }
}
release-contract:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
- uses: anchore/sbom-action/download-syft@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0
with:
syft-version: v1.51.0
- name: Check stable GoReleaser configuration
uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7.2.3
with:
distribution: goreleaser
version: v2.17.1
args: check --config .goreleaser.yml
- name: Check edge GoReleaser configuration
uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7.2.3
with:
distribution: goreleaser
version: v2.17.1
args: check --config .goreleaser.edge.yml
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.3.10
- name: Prepare bundled aria2 source companion
run: |
bun test scripts/package-aria2-sources.test.ts
bun scripts/package-aria2-sources.ts .local/aria2-sources
tar -czf .local/aria2-1.37.0-companion-sources.tar.gz -C .local aria2-sources
- name: Build release snapshot
uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7.2.3
with:
distribution: goreleaser
version: v2.17.1
args: release --snapshot --clean --config .goreleaser.yml
- name: Verify archive, checksum, and SBOM contract
shell: bash
run: |
set -euo pipefail
archive_count=0
for archive in dist/protopeek_*.tar.gz; do
test -f "$archive" || continue
archive_count=$((archive_count + 1))
contents="$(tar -tzf "$archive")"
grep -Eq '(^|/)protopeek$' <<<"$contents"
grep -Eq '(^|/)pp$' <<<"$contents"
grep -Eq '(^|/)THIRD_PARTY_NOTICES\.md$' <<<"$contents"
grep -Eq '(^|/)man/protopeek\.1$' <<<"$contents"
grep -Eq '(^|/)man/pp\.1$' <<<"$contents"
grep -Fq "$(basename "$archive")" dist/checksums.txt
test -f "$archive.sbom.json"
done
for archive in dist/protopeek_*.zip; do
test -f "$archive" || continue
archive_count=$((archive_count + 1))
contents="$(unzip -Z1 "$archive")"
grep -Eq '(^|/)protopeek\.exe$' <<<"$contents"
grep -Eq '(^|/)pp\.exe$' <<<"$contents"
grep -Eq '(^|/)THIRD_PARTY_NOTICES\.md$' <<<"$contents"
grep -Eq '(^|/)aria2-notices/COPYING$' <<<"$contents"
grep -Eq '(^|/)aria2-notices/README.md$' <<<"$contents"
grep -Eq '(^|/)third_party/licenses/go-capnp-MIT.txt$' <<<"$contents"
grep -Eq '(^|/)man/protopeek\.1$' <<<"$contents"
grep -Eq '(^|/)man/pp\.1$' <<<"$contents"
grep -Fq "$(basename "$archive")" dist/checksums.txt
test -f "$archive.sbom.json"
done
test "$archive_count" -gt 0
test -s .local/aria2-1.37.0-companion-sources.tar.gz
source_contents="$(tar -tzf .local/aria2-1.37.0-companion-sources.tar.gz)"
grep -Eq '(^|/)SOURCES.json$' <<<"$source_contents"