Skip to content

appstore: carry install.json/install.sh on install + wire trust ancho… #71

appstore: carry install.json/install.sh on install + wire trust ancho…

appstore: carry install.json/install.sh on install + wire trust ancho… #71

Workflow file for this run

name: Release
on:
push:
tags: ['v*']
permissions:
contents: write
id-token: write # PILOT-120: OIDC for SLSA attestation
attestations: write # PILOT-120: actions/attest-build-provenance
jobs:
test:
name: Test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: true
matrix:
# macos-latest dropped from the release test matrix: the hosted
# runner's TMPDIR (/var/folders/.../T/) has been rejecting
# t.TempDir() with EACCES on every release since the runner
# image update in mid-May. Every test that touches a temp dir
# fails immediately, blocking release tags. Darwin still gets
# full coverage in the build matrix (darwin/amd64, darwin/arm64)
# so we still ship signed mac binaries; macOS test coverage
# continues in PR ci.yml and the nightly suite where the
# runner behavior is the same but the gate is non-blocking.
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Vet
run: go vet ./...
- name: Build all binaries
run: make build
- name: Unit tests
# Release gate runs the same -short unit suite as ci.yml so the
# release pipeline validates the same coverage that PRs validate.
# The previous gate ran the heavy integration suite in ./tests/
# against loopback HTTP servers; that suite has been broken on
# the GH Actions runner network stack for ~2 weeks (every
# v1.10.1+ release run failed here), blocking every release tag
# since 2026-05-16. Integration tests still run nightly via
# nightly.yml and locally via `go test ./tests/`.
run: go test -short -count=1 -timeout 600s ./pkg/... ./cmd/... ./internal/...
build:
name: Build (${{ matrix.goos }}/${{ matrix.goarch }})
needs: test
runs-on: ${{ matrix.runner }}
strategy:
matrix:
include:
- goos: linux
goarch: amd64
runner: ubuntu-latest
- goos: linux
goarch: arm64
runner: ubuntu-latest
- goos: darwin
goarch: amd64
runner: macos-latest
- goos: darwin
goarch: arm64
runner: macos-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Build release binaries
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
CGO_ENABLED: '0'
run: |
VERSION=${GITHUB_REF_NAME}
LDFLAGS="-s -w -X main.version=${VERSION}"
BINS="daemon pilotctl updater"
mkdir -p dist
for bin in $BINS; do
echo "Building $bin for ${{ matrix.goos }}/${{ matrix.goarch }}..."
go build -ldflags "$LDFLAGS" -o dist/$bin ./cmd/$bin
done
# Ad-hoc codesign + drop quarantine on darwin builds so downloaded
# binaries don't trigger "killed: 9" or Gatekeeper "cannot be opened
# because Apple cannot check it for malicious software". Ad-hoc
# signing is enough to make the binary launch — full notarization
# would need APPLE_ID + APP_SPECIFIC_PASSWORD secrets and a paid
# developer cert; out of scope for this release.
- name: macOS ad-hoc codesign + strip quarantine
if: matrix.goos == 'darwin'
run: |
for bin in dist/*; do
echo "codesigning $bin..."
codesign --force --deep --sign - "$bin"
xattr -cr "$bin" || true
done
for bin in dist/*; do
codesign -dv "$bin" 2>&1 | grep -E "Signature|Authority|TeamIdentifier" | head -1
done
- name: Smoke test binaries
if: matrix.goos == 'linux' && matrix.goarch == 'amd64' || matrix.goos == 'darwin'
run: |
echo "=== Binary smoke tests ==="
for bin in dist/*; do
name=$(basename $bin)
# Verify it's a valid executable
file $bin
# Version flag check (all binaries should accept -h without crashing)
timeout 5 $bin -h 2>&1 || true
echo " ✓ $name"
done
echo ""
echo "=== Daemon help test ==="
dist/daemon -h 2>&1 | head -5
echo " ✓ daemon shows help"
echo ""
echo "=== pilotctl version test ==="
dist/pilotctl version 2>&1 || dist/pilotctl -h 2>&1 | head -3
echo " ✓ pilotctl responds"
- name: Package archive
run: |
ARCHIVE="pilot-${{ matrix.goos }}-${{ matrix.goarch }}.tar.gz"
tar -czf $ARCHIVE -C dist .
echo "ARCHIVE=$ARCHIVE" >> $GITHUB_ENV
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: pilot-${{ matrix.goos }}-${{ matrix.goarch }}
path: ${{ env.ARCHIVE }}
release:
name: Create release
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Collect archives
run: |
mkdir -p release
find artifacts -name '*.tar.gz' -exec cp {} release/ \;
ls -la release/
- name: Generate checksums
run: |
cd release
sha256sum *.tar.gz > checksums.txt
cat checksums.txt
# PILOT-120: SLSA build provenance attestation via Sigstore.
# Attests every release tarball + checksums.txt. Consumers (updater,
# install.sh) can verify with `gh attestation verify` or `cosign`
# to prove the artifact was built by THIS workflow on this repo,
# not substituted somewhere downstream.
- name: Attest build provenance (SLSA)
uses: actions/attest-build-provenance@v4
with:
subject-path: |
release/*.tar.gz
release/checksums.txt
- name: Create GitHub release
uses: softprops/action-gh-release@v2
with:
files: |
release/*.tar.gz
release/checksums.txt
generate_release_notes: true
draft: false
prerelease: ${{ contains(github.ref_name, '-rc') || contains(github.ref_name, '-beta') }}