Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
b772cd3
Phase the reviewed binary attestation contract
prk-Jr Oct 22, 2026
be81ca8
Map binary attestation phases to review boundaries
prk-Jr Oct 22, 2026
ca06217
Build and attest phased release binaries
prk-Jr Oct 22, 2026
4dd2171
Document binary verification and release deployment
prk-Jr Oct 22, 2026
3c41de5
Align Phase 1 signing and publication with the reviewed contract
prk-Jr Oct 22, 2026
cb82e4b
Allow the exact GitHub Actions build type reference host
prk-Jr Oct 22, 2026
41896cb
Document Phase 1 compatibility and verification boundaries
prk-Jr Oct 22, 2026
ca902b6
Avoid stale API connections during release verification
prk-Jr Oct 22, 2026
f3a8696
Clarify rehearsed release status and CLI verification
prk-Jr Oct 22, 2026
922c221
Retry transient post-publication verification reads
prk-Jr Oct 22, 2026
ff9f9c4
Document offline verification and completed release rehearsal
prk-Jr Oct 22, 2026
7c7f4b0
Add production Axum assets and release startup checks
prk-Jr Oct 22, 2026
b818b59
Disable rustup self-updates in temporary build homes
prk-Jr Oct 22, 2026
16d6690
Expose pinned compiler binaries in the GNU builder
prk-Jr Oct 22, 2026
937214a
Supply runtime trust data to Axum startup checks
prk-Jr Oct 23, 2026
6824226
Record the seven-binary release rehearsal
prk-Jr Oct 23, 2026
e907e26
Derive immutable release build facts
prk-Jr Oct 23, 2026
72b7e1e
Allow runtime Axum bind address overrides
prk-Jr Oct 23, 2026
81a5a72
Harden release eligibility and artifact validation
prk-Jr Oct 23, 2026
39a769c
Align release documentation and reference-host policy
prk-Jr Oct 23, 2026
e22d700
Reduce startup logging and align runtime port aliases
prk-Jr Oct 23, 2026
2cc39ec
Harden release verification and preflight boundaries
prk-Jr Oct 23, 2026
7a05940
Record rehearsal failure and release recovery checks
prk-Jr Oct 23, 2026
f84ab21
Record the successful binary attestation rehearsal
prk-Jr Oct 23, 2026
149754d
Handle attestation availability and verify published bytes
prk-Jr Oct 23, 2026
f66da48
Record the successful ninth attestation rehearsal
prk-Jr Oct 23, 2026
a501d1b
Clarify final release verification notes (docs-only)
prk-Jr Oct 23, 2026
afdc928
Merge current main and clarify bind diagnostics
prk-Jr Oct 26, 2026
34e7e9e
Address self-review findings in release attestations
prk-Jr Oct 27, 2026
ab6e549
Strengthen release build-fact and gate tests
prk-Jr Oct 27, 2026
68eef90
Merge remote-tracking branch 'origin/main' into feature/binary-attest…
prk-Jr Oct 27, 2026
2015231
Record the main-merge Phase 1 rehearsal
prk-Jr Oct 28, 2026
c9a6117
Record two independent Phase 1 spec review rounds
prk-Jr Oct 28, 2026
4940928
Merge branch 'main' into feature/binary-attestations-phase1
prk-Jr Oct 28, 2026
79b1188
Address attested release review feedback
prk-Jr Oct 29, 2026
990509b
Merge branch 'main' into feature/binary-attestations-phase1
prk-Jr Oct 29, 2026
c827eb2
Address maintainer review of Phase 1 attested releases
prk-Jr Nov 2, 2026
5f0139b
Merge main into feature/binary-attestations-phase1
prk-Jr Nov 2, 2026
890acd2
Record Phase 1 fork rehearsal .22 at the current head
prk-Jr Nov 2, 2026
029f204
Merge main into feature/binary-attestations-phase1
prk-Jr Nov 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,10 @@ jobs:
node-version: ${{ steps.node-version.outputs.node-version }}

- name: Run shellcheck
run: shellcheck scripts/docs-proposal/*.sh
run: shellcheck scripts/docs-proposal/*.sh scripts/release/phase1-build.sh

- name: Test release producer scripts
run: node --test scripts/release/phase1.test.mjs

- name: Test hunk review builder
run: node --test scripts/docs-proposal/hunks.test.mjs
Expand Down
183 changes: 183 additions & 0 deletions .github/workflows/release-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
name: Release build and signing
on:
workflow_call:
permissions:
contents: read
jobs:
checks:
runs-on: ubuntu-24.04
permissions:
contents: read
steps:
- uses: actions/checkout@v5
with:
persist-credentials: false
- name: Read pinned Node version
id: tools
run: echo "node=$(awk '$1 == "nodejs" { print $2 }' .tool-versions)" >> "$GITHUB_OUTPUT"
- uses: actions/setup-node@v5
with:
node-version: ${{ steps.tools.outputs.node }}
- run: node --test scripts/release/phase1.test.mjs
# Refuse a tag the publisher would reject before building and signing.
- name: Refuse non-SemVer release tags
if: startsWith(github.ref, 'refs/tags/')
env:
RELEASE_TAG: ${{ github.ref_name }}
run: |
node --input-type=module -e "
import { isReleaseTag } from './scripts/release/publish.mjs'
if (!isReleaseTag(process.env.RELEASE_TAG)) throw Error('Release tags must be vMAJOR.MINOR.PATCH[-PRERELEASE]')
"
build:
needs: checks
name: Build ${{ matrix.asset }}
runs-on: ${{ matrix.os }}
timeout-minutes: 90
permissions:
contents: read
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04
package: trusted-server-adapter-fastly
target: wasm32-wasip1
asset: trusted-server-fastly.wasm
- os: ubuntu-24.04
package: trusted-server-cli
target: x86_64-unknown-linux-gnu
asset: ts-x86_64-unknown-linux-gnu
- os: macos-15
package: trusted-server-cli
target: aarch64-apple-darwin
asset: ts-aarch64-apple-darwin
- os: macos-15-intel
package: trusted-server-cli
target: x86_64-apple-darwin
asset: ts-x86_64-apple-darwin
- os: ubuntu-24.04
package: trusted-server-adapter-axum
target: x86_64-unknown-linux-gnu
asset: trusted-server-axum-x86_64-unknown-linux-gnu
- os: ubuntu-24.04
package: trusted-server-adapter-axum
target: x86_64-unknown-linux-musl
asset: trusted-server-axum-x86_64-unknown-linux-musl
- os: ubuntu-24.04-arm
package: trusted-server-adapter-axum
target: aarch64-unknown-linux-gnu
asset: trusted-server-axum-aarch64-unknown-linux-gnu
steps:
- uses: actions/checkout@v5
with:
persist-credentials: false
- name: Read pinned toolchains
id: tools
shell: bash
run: |
set -euo pipefail
echo "node=$(awk '$1 == "nodejs" { print $2 }' .tool-versions)" >> "$GITHUB_OUTPUT"
echo "rust=$(sed -n 's/^channel = "\([^"]*\)"/\1/p' rust-toolchain.toml)" >> "$GITHUB_OUTPUT"
- uses: actions/setup-node@v5
with:
node-version: ${{ steps.tools.outputs.node }}
- name: Install the pinned Rust toolchain without build caches
env:
RUST_VERSION: ${{ steps.tools.outputs.rust }}
BUILD_TARGET: ${{ matrix.target }}
run: rustup toolchain install "$RUST_VERSION" --profile minimal --target "$BUILD_TARGET"
- name: Build and generate the build inventory in a clean environment
shell: bash
env:
BUILD_PACKAGE: ${{ matrix.package }}
BUILD_TARGET: ${{ matrix.target }}
RELEASE_ASSET: ${{ matrix.asset }}
SOURCE_COMMIT: ${{ github.sha }}
RELEASE_VERSION: ${{ github.ref_name }}
run: |
set -euo pipefail
env -i PATH="$PATH" HOME="$HOME" \
CARGO_HOME="${CARGO_HOME:-$HOME/.cargo}" \
RUSTUP_HOME="${RUSTUP_HOME:-$HOME/.rustup}" \
TMPDIR="${TMPDIR:-/tmp}" RUNNER_TEMP="$RUNNER_TEMP" \
SOURCE_COMMIT="$SOURCE_COMMIT" RELEASE_VERSION="$RELEASE_VERSION" \
bash scripts/release/phase1-build.sh "$BUILD_PACKAGE" "$BUILD_TARGET" "$RELEASE_ASSET"
- uses: actions/upload-artifact@v6
with:
name: release-${{ matrix.asset }}
path: release-assets/*
if-no-files-found: error
retention-days: 7

sign:
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') && vars.RELEASE_PUBLICATION_ENABLED == 'true'
needs: build
runs-on: ubuntu-24.04
timeout-minutes: 15
permissions:
contents: read
id-token: write
attestations: write
strategy:
fail-fast: false
matrix:
asset:
[
trusted-server-axum-x86_64-unknown-linux-gnu,
trusted-server-axum-x86_64-unknown-linux-musl,
trusted-server-axum-aarch64-unknown-linux-gnu,
trusted-server-fastly.wasm,
ts-aarch64-apple-darwin,
ts-x86_64-apple-darwin,
ts-x86_64-unknown-linux-gnu,
]
steps:
# Only fixed inline checks execute here; never checkout or execute build inputs.
- uses: actions/download-artifact@v7
with:
name: release-${{ matrix.asset }}
path: release-assets
- name: Validate signing inputs and retain their digests
env:
ASSET: ${{ matrix.asset }}
run: |
set -euo pipefail
cd release-assets
test "$(find . -mindepth 1 -maxdepth 1 | wc -l)" -eq 2
for file in "$ASSET" "$ASSET.spdx.json"; do test -f "$file" && test ! -L "$file" && test -s "$file" || exit 1; done
sha256sum "$ASSET" "$ASSET.spdx.json" > ../inputs.sha256
- name: Attest SLSA build provenance
id: provenance
uses: actions/attest@v4
with:
subject-path: |
release-assets/${{ matrix.asset }}
release-assets/${{ matrix.asset }}.spdx.json
- name: Attest the binary's SPDX SBOM
id: sbom
uses: actions/attest@v4
with:
subject-path: release-assets/${{ matrix.asset }}
sbom-path: release-assets/${{ matrix.asset }}.spdx.json
- name: Retain only this run's real bundles and signed-input digests
env:
ASSET: ${{ matrix.asset }}
PROVENANCE: ${{ steps.provenance.outputs.bundle-path }}
SBOM: ${{ steps.sbom.outputs.bundle-path }}
run: |
set -euo pipefail
(cd release-assets && sha256sum --check ../inputs.sha256)
test -s "$PROVENANCE"
test -s "$SBOM"
mkdir signed-assets
cp "$PROVENANCE" "signed-assets/$ASSET.provenance.sigstore.json"
cp "$SBOM" "signed-assets/$ASSET.sbom.sigstore.json"
cp inputs.sha256 signed-assets/SHA256SUMS
(cd signed-assets && sha256sum "$ASSET.provenance.sigstore.json" "$ASSET.sbom.sigstore.json" >> SHA256SUMS)
- uses: actions/upload-artifact@v6
with:
name: signed-${{ matrix.asset }}
path: signed-assets/*
if-no-files-found: error
retention-days: 7
125 changes: 125 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
name: Binary attestations
# Pull requests run the release Node suite in format.yml. The release builds
# run on every push to main, so they need no input path list, and on tags.
on:
push:
branches: [main]
tags: ['v*']
permissions:
contents: read
concurrency:
group: binary-attestations-${{ github.ref }}
cancel-in-progress: false
jobs:
build:
uses: ./.github/workflows/release-build.yml
permissions:
contents: read
id-token: write
attestations: write
release:
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') && vars.RELEASE_PUBLICATION_ENABLED == 'true'
needs: build
runs-on: ubuntu-24.04
timeout-minutes: 15
permissions:
contents: write
steps:
- uses: actions/download-artifact@v7
with:
name: release-trusted-server-fastly.wasm
path: build/trusted-server-fastly.wasm
- uses: actions/download-artifact@v7
with:
name: signed-trusted-server-fastly.wasm
path: signed/trusted-server-fastly.wasm
- uses: actions/download-artifact@v7
with:
name: release-ts-aarch64-apple-darwin
path: build/ts-aarch64-apple-darwin
- uses: actions/download-artifact@v7
with:
name: signed-ts-aarch64-apple-darwin
path: signed/ts-aarch64-apple-darwin
- uses: actions/download-artifact@v7
with:
name: release-ts-x86_64-apple-darwin
path: build/ts-x86_64-apple-darwin
- uses: actions/download-artifact@v7
with:
name: signed-ts-x86_64-apple-darwin
path: signed/ts-x86_64-apple-darwin
- uses: actions/download-artifact@v7
with:
name: release-ts-x86_64-unknown-linux-gnu
path: build/ts-x86_64-unknown-linux-gnu
- uses: actions/download-artifact@v7
with:
name: signed-ts-x86_64-unknown-linux-gnu
path: signed/ts-x86_64-unknown-linux-gnu
- uses: actions/download-artifact@v7
with:
name: release-trusted-server-axum-x86_64-unknown-linux-gnu
path: build/trusted-server-axum-x86_64-unknown-linux-gnu
- uses: actions/download-artifact@v7
with:
name: signed-trusted-server-axum-x86_64-unknown-linux-gnu
path: signed/trusted-server-axum-x86_64-unknown-linux-gnu
- uses: actions/download-artifact@v7
with:
name: release-trusted-server-axum-x86_64-unknown-linux-musl
path: build/trusted-server-axum-x86_64-unknown-linux-musl
- uses: actions/download-artifact@v7
with:
name: signed-trusted-server-axum-x86_64-unknown-linux-musl
path: signed/trusted-server-axum-x86_64-unknown-linux-musl
- uses: actions/download-artifact@v7
with:
name: release-trusted-server-axum-aarch64-unknown-linux-gnu
path: build/trusted-server-axum-aarch64-unknown-linux-gnu
- uses: actions/download-artifact@v7
with:
name: signed-trusted-server-axum-aarch64-unknown-linux-gnu
path: signed/trusted-server-axum-aarch64-unknown-linux-gnu
# Run only the publisher and its notes template from the tagged commit;
# never check out build inputs here.
- uses: actions/checkout@v5
with:
path: publisher
persist-credentials: false
sparse-checkout: |
.tool-versions
scripts/release/publish.mjs
scripts/release/release-notes.md
sparse-checkout-cone-mode: false
- name: Read pinned Node version
id: tools
run: echo "node=$(awk '$1 == "nodejs" { print $2 }' publisher/.tool-versions)" >> "$GITHUB_OUTPUT"
- uses: actions/setup-node@v5
with:
node-version: ${{ steps.tools.outputs.node }}
- name: Install the pinned GitHub CLI
env:
GH_VERSION: 2.102.0
GH_SHA256: bb766f710eef8ede859c18578c72c327597cd4c8a85b06001b1f3843c6019386
run: |
set -euo pipefail
archive="gh_${GH_VERSION}_linux_amd64.tar.gz"
curl --fail --silent --show-error --location --retry 3 \
"https://github.com/cli/cli/releases/download/v${GH_VERSION}/${archive}" \
--output "$RUNNER_TEMP/$archive"
printf '%s %s\n' "$GH_SHA256" "$RUNNER_TEMP/$archive" | sha256sum --check
tar -xzf "$RUNNER_TEMP/$archive" -C "$RUNNER_TEMP"
echo "$RUNNER_TEMP/gh_${GH_VERSION}_linux_amd64/bin" >> "$GITHUB_PATH"
- name: Verify handoff, create once, publish by release ID and verify
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
RELEASE_TAG: ${{ github.ref_name }}
SOURCE_COMMIT: ${{ github.sha }}
RELEASE_PUBLICATION_ENABLED: ${{ vars.RELEASE_PUBLICATION_ENABLED }}
run: |
set -euo pipefail
test "$(gh --version | head -1 | cut -d' ' -f3)" = 2.102.0
node --version
node publisher/scripts/release/publish.mjs
11 changes: 11 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,17 @@ jobs:
run: |
cargo test --manifest-path crates/trusted-server-cli/Cargo.toml --target "$(rustc -vV | sed -n 's/host: //p')"

# Release builds take their facts from these inputs; check that the
# actual CLI binary embeds them unchanged. The fictional commit differs
# from the checkout, so a fallback to local git cannot pass.
- name: cargo test (release build facts)
if: runner.os == 'Linux'
env:
TRUSTED_SERVER__RELEASE_BUILD: "1"
TRUSTED_SERVER__GIT_VERSION: abcdef0123456789abcdef0123456789abcdef01
run: |
cargo test --manifest-path crates/trusted-server-cli/Cargo.toml --target "$(rustc -vV | sed -n 's/host: //p')" --test release_build_facts

- name: cargo test (browser fixtures)
if: runner.os == 'macOS'
run: ./scripts/test-cli.sh
Expand Down
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ Every PR must pass:
13. CI Node pin guard: `node --test scripts/check-ci-node-pin.test.mjs && node scripts/check-ci-node-pin.mjs` with the `.tool-versions` Node (every CI job that compiles Rust sets up the `.tool-versions` Node before its first cargo step)
14. Fastly absolute-deadline network fixtures under Viceroy (the harness builds the adapter test binary itself): `node crates/trusted-server-adapter-fastly/tests/deadline-origin.mjs "$(command -v viceroy)"`
15. Worker auction-deadline runtime fixtures (`worker-auction-deadlines.yml`): build and lint the runtime fixture, then run it under the local runtime. For Cloudflare, `cargo build --locked -p trusted-server-adapter-cloudflare --example deadline-runtime --target wasm32-unknown-unknown --features cloudflare` and `node scripts/test-worker-auction-deadlines.mjs cloudflare --runtime "$(command -v wrangler)"` (requires wrangler and the `Cargo.lock` wasm-bindgen CLI). For Spin, `cargo build --locked -p trusted-server-adapter-spin --example deadline-runtime --target wasm32-wasip1 --features spin` and `node scripts/test-worker-auction-deadlines.mjs spin --runtime "$(command -v spin)"`. CI lints each fixture with the same `cargo clippy` arguments plus `-- -D warnings`
16. Release producer checks: `node --test scripts/release/phase1.test.mjs && shellcheck scripts/release/phase1-build.sh`

CI also runs these HTML EOF checks. Run them locally only when changing EOF
finalization, publisher or HTML-processor code:
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Add Phase 1 attested Fastly wasm, three Linux/macOS CLI and three Axum development/evaluation binaries (Axum remains a non-production adapter), with SPDX 2.3 inventories, provenance/SBOM bundles, immutable verification, GNU glibc 2.34 and static musl startup checks. Reproducibility and the custom verifier remain later work; production publication requires maintainer settings.

### Changed

- Attested release binaries report `x-ts-version` as the full 40-character source commit; deploy-pipeline builds keep the tag, branch or short-commit value described below. Axum supports runtime `EDGEZERO__ADAPTER__HOST` and primary `EDGEZERO__ADAPTER__PORT` (legacy `PORT` must agree when both are set) binding with a loopback default, and refuses to start on port `0` or an invalid value instead of falling back.
- **Breaking:** `ts --version` now prints `ts package=<version> source=<commit> target=<triple> variant=default` instead of `ts <version>`. Update scripts that parse the old output.
- Auction response collection now bounds network waiting by `[auction].timeout_ms`
measured from dispatch, including delayed headers and trickling bodies on all
adapters. Complete available responses survive a slow publisher origin;
Expand Down
Loading
Loading