Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 16 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Build context for crates/trusted-server-adapter-axum/Dockerfile. Keep the
# workspace sources; drop history, build output, local secrets and docs.
.git
**/target
**/node_modules
**/dist
.env*
!.env.example
trusted-server.toml
.ts-write-*
js-assets.toml
.edgezero
.claude
.wolf
docs
tinybird
2 changes: 1 addition & 1 deletion .github/workflows/format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -256,4 +256,4 @@ jobs:
run: shellcheck scripts/release/phase1-build.sh scripts/release/validate-fastly-package.sh scripts/release/bootstrap.sh scripts/release/build.sh scripts/release/build-js.sh

- name: Test release producer scripts
run: node --test scripts/release/phase1.test.mjs
run: node --test scripts/release/phase1.test.mjs scripts/release/packages.test.mjs
127 changes: 127 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,130 @@ jobs:
# would exit 0 without publishing.
test "$(node --version)" = "v$NODE_VERSION"
node publisher/scripts/release/publish.mjs
# Mirrors the published release into GHCR: one OCI artifact per binary with
# its SPDX SBOM and Sigstore bundles. An existing tag is refused unless it
# already holds exactly the release files; GHCR tags stay mutable.
packages:
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') && vars.PACKAGE_PUBLICATION_ENABLED == 'true'
needs: release
runs-on: ubuntu-24.04
timeout-minutes: 15
permissions:
contents: read
packages: write
steps:
# Run only the package publisher and the asset list it imports.
- uses: actions/checkout@v5
with:
path: publisher
persist-credentials: false
sparse-checkout: |
.tool-versions
scripts/release/publish.mjs
scripts/release/packages.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 and oras
env:
GH_VERSION: 2.102.0
GH_SHA256: bb766f710eef8ede859c18578c72c327597cd4c8a85b06001b1f3843c6019386
ORAS_VERSION: 1.3.4
ORAS_SHA256: f27adb935022d94df8dc77719c322dda592c78a0d57a6f7dcdd8d900b248c454
run: |
set -euo pipefail
gh_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}/${gh_archive}" \
--output "$RUNNER_TEMP/$gh_archive"
printf '%s %s\n' "$GH_SHA256" "$RUNNER_TEMP/$gh_archive" | sha256sum --check
tar -xzf "$RUNNER_TEMP/$gh_archive" -C "$RUNNER_TEMP"
echo "$RUNNER_TEMP/gh_${GH_VERSION}_linux_amd64/bin" >> "$GITHUB_PATH"
oras_archive="oras_${ORAS_VERSION}_linux_amd64.tar.gz"
curl --fail --silent --show-error --location --retry 3 \
"https://github.com/oras-project/oras/releases/download/v${ORAS_VERSION}/${oras_archive}" \
--output "$RUNNER_TEMP/$oras_archive"
printf '%s %s\n' "$ORAS_SHA256" "$RUNNER_TEMP/$oras_archive" | sha256sum --check
mkdir "$RUNNER_TEMP/oras"
tar -xzf "$RUNNER_TEMP/$oras_archive" -C "$RUNNER_TEMP/oras" oras
echo "$RUNNER_TEMP/oras" >> "$GITHUB_PATH"
- name: Check the release, then push and verify each package
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
RELEASE_TAG: ${{ github.ref_name }}
SOURCE_COMMIT: ${{ github.sha }}
PACKAGE_PUBLICATION_ENABLED: ${{ vars.PACKAGE_PUBLICATION_ENABLED }}
NODE_VERSION: ${{ steps.tools.outputs.node }}
run: |
set -euo pipefail
test "$(gh --version | head -1 | cut -d' ' -f3)" = 2.102.0
test "$(oras version | sed -n 's/^Version: *//p')" = 1.3.4
test "$(node --version)" = "v$NODE_VERSION"
printf '%s' "$GH_TOKEN" | oras login ghcr.io --username "$GITHUB_ACTOR" --password-stdin
node publisher/scripts/release/packages.mjs
# Builds the Axum server image from the tagged source and pushes it to GHCR
# with GitHub build provenance. It is an ordinary build, outside the
# reproducible release cohort. If a push or attestation fails, delete the
# package version before re-running; see the maintainer checklist.
axum-image:
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') && vars.PACKAGE_PUBLICATION_ENABLED == 'true'
needs: release
runs-on: ubuntu-24.04
timeout-minutes: 60
permissions:
contents: read
packages: write
id-token: write
attestations: write
steps:
- uses: actions/checkout@v5
with:
persist-credentials: false
- name: Build, push and record the image digest
id: image
env:
GH_TOKEN: ${{ github.token }}
RELEASE_TAG: ${{ github.ref_name }}
SOURCE_COMMIT: ${{ github.sha }}
run: |
set -euo pipefail
image="ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/trusted-server-axum"
printf '%s' "$GH_TOKEN" | docker login ghcr.io --username "$GITHUB_ACTOR" --password-stdin
# GHCR tags are mutable; refuse to replace one at publish time. Only
# the registry's not-found answer counts as absent.
if lookup="$(docker buildx imagetools inspect "$image:$RELEASE_TAG" 2>&1)"; then
echo "Refusing to overwrite $image:$RELEASE_TAG" >&2
exit 1
elif ! grep -qF -- "$image:$RELEASE_TAG: not found" <<< "$lookup"; then
echo "Cannot check whether $image:$RELEASE_TAG exists: $lookup" >&2
exit 1
fi
docker buildx build \
--file crates/trusted-server-adapter-axum/Dockerfile \
--platform linux/amd64 \
--provenance=false --sbom=false \
--build-arg "TRUSTED_SERVER_VERSION=$SOURCE_COMMIT" \
--label "org.opencontainers.image.source=https://github.com/$GITHUB_REPOSITORY" \
--label "org.opencontainers.image.revision=$SOURCE_COMMIT" \
--label "org.opencontainers.image.version=$RELEASE_TAG" \
--label "org.opencontainers.image.description=Trusted Server on Axum $RELEASE_TAG (development status)" \
--tag "$image:$RELEASE_TAG" \
--metadata-file "$RUNNER_TEMP/image.json" \
--push .
digest="$(jq -r '."containerimage.digest"' "$RUNNER_TEMP/image.json")"
[[ "$digest" =~ ^sha256:[0-9a-f]{64}$ ]]
test "$(docker buildx imagetools inspect "$image:$RELEASE_TAG" --format '{{json .Manifest.Digest}}' | tr -d '"')" = "$digest"
echo "name=$image" >> "$GITHUB_OUTPUT"
echo "digest=$digest" >> "$GITHUB_OUTPUT"
- name: Attest the image's build provenance
uses: actions/attest@v4
with:
subject-name: ${{ steps.image.outputs.name }}
subject-digest: ${{ steps.image.outputs.digest }}
push-to-registry: true
33 changes: 33 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,39 @@ jobs:
path: ${{ runner.temp }}/trusted-server-finalize-fastly-*/
if-no-files-found: ignore

axum-image:
name: Axum image smoke
runs-on: ubuntu-24.04
timeout-minutes: 60
steps:
- uses: actions/checkout@v4

- name: Set up Rust toolchain
uses: ./.github/actions/setup-rust
with:
cache-key: cargo-axum-image

- name: Read pinned Node.js version
id: node-version
shell: bash
run: echo "version=$(awk '$1 == "nodejs" { print $2 }' .tool-versions)" >> "$GITHUB_OUTPUT"

# The smoke builds the `ts` CLI, whose core dependency runs the TSJS
# build with the `npm` on PATH, so pin Node before any cargo step.
- name: Use Node.js for the TSJS build
uses: actions/setup-node@v4
with:
node-version: ${{ steps.node-version.outputs.version }}

- name: Build the Axum image
run: |
docker buildx build --load \
--file crates/trusted-server-adapter-axum/Dockerfile \
--tag trusted-server-axum:smoke .

- name: Run the Axum smoke against the image
run: AXUM_SMOKE_IMAGE=trusted-server-axum:smoke ./scripts/smoke-axum.sh

test-axum:
name: cargo test (axum native)
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +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 helpers: `node --test scripts/release/phase1.test.mjs && shellcheck scripts/release/phase1-build.sh scripts/release/validate-fastly-package.sh scripts/release/bootstrap.sh scripts/release/build.sh scripts/release/build-js.sh`
16. Release producer helpers: `node --test scripts/release/phase1.test.mjs scripts/release/packages.test.mjs && shellcheck scripts/release/phase1-build.sh scripts/release/validate-fastly-package.sh scripts/release/bootstrap.sh scripts/release/build.sh scripts/release/build-js.sh`
17. Native release producer tests and lint: `cargo test --package trusted-server-release --target <host-triple> --locked` and `cargo clippy --package trusted-server-release --target <host-triple> --all-targets --all-features --locked -- -D warnings` (CI uses `x86_64-unknown-linux-gnu`).
18. Native checked/ordinary JS release fixtures: `cargo test --package trusted-server-js --target <host-triple> --locked --test release_prebuilt` and `cargo clippy --package trusted-server-js --target <host-triple> --all-targets --all-features --locked -- -D warnings` (CI uses `x86_64-unknown-linux-gnu`).

Expand Down
69 changes: 69 additions & 0 deletions crates/trusted-server-adapter-axum/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Trusted Server on Axum as a container image.
#
# Build from the repository root:
# docker build --file crates/trusted-server-adapter-axum/Dockerfile \
# --build-arg TRUSTED_SERVER_VERSION="$(git rev-parse HEAD)" \
# --tag trusted-server-axum .
#
# The image is an ordinary build with build provenance only. It is not part of
# the reproducible release cohort that the binary release rebuild checks cover.
# Axum is development status; see docs/guide/axum-dev.md.

# The tsjs build script runs npm; this is the `.tool-versions` Node.
FROM docker.io/library/node:24.20.0-bookworm-slim@sha256:ba849c60be29959425b8734d57b8b4b7d56f98edd9504c9af091d5281095a71e AS node

# Debian 12 builder and runtime share glibc 2.36.
FROM docker.io/library/rust:1.98.1-bookworm@sha256:93ce27a88655056a51dbdd8f5f2d7ddc071c7b0070fb288a37b5a285fc83971e AS build

COPY --from=node /usr/local/bin/node /usr/local/bin/node
COPY --from=node /usr/local/lib/node_modules/npm /usr/local/lib/node_modules/npm
RUN set -eu; \
ln -s ../lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm; \
ln -s ../lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx; \
test "$(node --version)" = v24.20.0; \
npm --version

# Use the installed toolchain as is: rust-toolchain.toml would otherwise make
# rustup download its extra wasm targets, an unpinned network input.
ENV RUSTUP_TOOLCHAIN=1.98.1

WORKDIR /src
COPY . .

# The checkout has no `.git`, so pass the source commit as the embedded
# version, as the release binaries do.
ARG TRUSTED_SERVER_VERSION
RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/src/target \
set -eu; \
if [ -n "${TRUSTED_SERVER_VERSION:-}" ]; then \
export TRUSTED_SERVER__GIT_VERSION="$TRUSTED_SERVER_VERSION"; \
fi; \
host="$(rustc -vV | sed -n 's/^host: //p')"; \
cargo build --release --locked --package trusted-server-adapter-axum \
--bin trusted-server-axum --target "$host"; \
install -D -m 0755 "target/$host/release/trusted-server-axum" \
/out/trusted-server-axum

# Debian slim with CA certificates only: no Node, compiler, config or secrets.
# Trusted Server's origin fetches use compiled-in webpki roots; only EdgeZero's
# own client reads this system store.
FROM docker.io/library/debian:bookworm-slim@sha256:734a72b3d6142a71993b4bc580ca01d8ca687f77a2c422d96a961d3376b179bc

RUN set -eu; \
apt-get update; \
apt-get install --yes --no-install-recommends ca-certificates; \
rm -rf /var/lib/apt/lists/*

COPY --from=build /out/trusted-server-axum /usr/local/bin/trusted-server-axum

# Containers must accept connections from outside their own loopback. The
# process writes nothing, so it runs with a read-only root filesystem.
ENV EDGEZERO__ADAPTER__HOST=0.0.0.0 \
EDGEZERO__ADAPTER__PORT=8080
EXPOSE 8080
# The server shuts down on SIGINT only, and a PID 1 without a SIGTERM handler
# would ignore `docker stop` until the kill timeout.
STOPSIGNAL SIGINT
USER 10001:10001
ENTRYPOINT ["/usr/local/bin/trusted-server-axum"]
Loading
Loading