Skip to content

test(docs): check the evidence anchors against source #1993

test(docs): check the evidence anchors against source

test(docs): check the evidence anchors against source #1993

Workflow file for this run

name: RegistryStack CI
on:
pull_request:
branches:
- main
- release/1.0
merge_group:
types:
- checks_requested
push:
branches:
- main
concurrency:
group: ci-${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || format('run-{0}', github.run_id) }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: "0"
CARGO_PROFILE_DEV_DEBUG: "0"
CARGO_PROFILE_TEST_DEBUG: "0"
CARGO_FUZZ_VERSION: "0.13.2"
CARGO_LLVM_COV_VERSION: "0.8.7"
GITLEAKS_VERSION: "8.30.1"
GITLEAKS_LINUX_X64_SHA256: "551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb"
ACTIONLINT_VERSION: "1.7.7"
ACTIONLINT_LINUX_X64_SHA256: "023070a287cd8cccd71515fedc843f1985bf96c436b7effaecce67290e7e0757"
OASDIFF_VERSION: "1.23.0"
OASDIFF_LINUX_X64_SHA256: "972b10535c3db4366b9dc3ebc11ca021279af3095267c3cffdca854a3a3c4f89"
jobs:
changes:
name: Changed paths
runs-on: ubuntu-24.04
outputs:
rust: ${{ steps.filter.outputs.rust }}
rust_matrix: ${{ steps.filter.outputs.rust_matrix }}
rust_packages: ${{ steps.filter.outputs.rust_packages }}
platform: ${{ steps.filter.outputs.platform }}
platform_hygiene: ${{ steps.filter.outputs.platform_hygiene }}
discovery_contracts: ${{ steps.filter.outputs.discovery_contracts }}
relay_v2_contracts: ${{ steps.filter.outputs.relay_v2_contracts }}
relay_client_contracts: ${{ steps.filter.outputs.relay_client_contracts }}
evidence_contracts: ${{ steps.filter.outputs.evidence_contracts }}
release_tool: ${{ steps.filter.outputs.release_tool }}
release_source_proof: ${{ steps.filter.outputs.release_source_proof }}
docs: ${{ steps.filter.outputs.docs }}
docs_archives: ${{ steps.filter.outputs.docs_archives }}
editors: ${{ steps.filter.outputs.editors }}
client_bindings: ${{ steps.filter.outputs.client_bindings }}
release_linux_node_clients: ${{ steps.filter.outputs.release_linux_node_clients }}
evidence_tutorial: ${{ steps.filter.outputs.evidence_tutorial }}
identifiers: ${{ steps.filter.outputs.identifiers }}
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
fetch-depth: 0
submodules: false
- name: Classify changed paths
id: filter
env:
BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || github.event.before }}
HEAD_SHA: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha || github.sha }}
shell: bash
run: |
set -euo pipefail
metadata="${RUNNER_TEMP}/registry-stack-cargo-metadata.json"
changed_files="${RUNNER_TEMP}/registry-stack-changed-files"
cargo metadata --locked --format-version 1 > "${metadata}"
classifier=(
python3 .github/scripts/ci_changes.py
--metadata "${metadata}"
--github-output "${GITHUB_OUTPUT}"
)
if [[ "${GITHUB_EVENT_NAME}" == "pull_request" ]]; then
if git cat-file -e "${BASE_SHA}^{commit}" 2>/dev/null &&
git cat-file -e "${HEAD_SHA}^{commit}" 2>/dev/null; then
git diff --name-only "${BASE_SHA}" "${HEAD_SHA}" > "${changed_files}"
classifier+=(--changed-files "${changed_files}")
else
classifier+=(--all)
fi
elif git cat-file -e "${BASE_SHA}^{commit}" 2>/dev/null &&
git cat-file -e "${HEAD_SHA}^{commit}" 2>/dev/null; then
# Keep push and merge-queue complete matrices while preserving
# paths for gates that intentionally do not run on every change.
git diff --name-only "${BASE_SHA}" "${HEAD_SHA}" > "${changed_files}"
classifier+=(--all --changed-files "${changed_files}")
else
# Runs without resolvable comparison commits use the complete
# matrix and leave opt-in immutable archive verification skipped.
classifier+=(--all)
fi
"${classifier[@]}"
- name: Check repository identifier reference closure
run: products/identifiers/scripts/generate.py --check-references
- name: Test CI classifier
run: python3 .github/scripts/test_ci_changes.py
- name: Install pinned actionlint
shell: bash
run: |
set -euo pipefail
mkdir -p "${RUNNER_TEMP}/bin"
curl --proto '=https' --tlsv1.2 --fail --silent --show-error --location \
--output "${RUNNER_TEMP}/actionlint.tar.gz" \
"https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz"
echo "${ACTIONLINT_LINUX_X64_SHA256} ${RUNNER_TEMP}/actionlint.tar.gz" | \
sha256sum --check --strict
tar -xzf "${RUNNER_TEMP}/actionlint.tar.gz" -C "${RUNNER_TEMP}/bin" actionlint
- name: Lint GitHub Actions workflows
run: |
set -euo pipefail
"${RUNNER_TEMP}/bin/actionlint"
- name: Check Debian 13 image contract
run: python3 release/scripts/check-debian13-images.py
- name: Test Debian 13 image contract
run: python3 -m unittest release/scripts/test_check_debian13_images.py
- name: Test container runtime preflight
run: python3 -m unittest docker/test_runtime_preflight.py
- name: Test advisory baseline exposure policy
run: python3 -m unittest release/scripts/test_check_advisory_baselines.py
- name: Test Mint demonstration support scripts
run: |
python3 -m unittest discover \
--start-directory crates/registry-mint/demo/support
secrets:
name: Secret scan
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
fetch-depth: 0
persist-credentials: false
submodules: false
- name: Install pinned Gitleaks
shell: bash
run: |
set -euo pipefail
mkdir -p "${RUNNER_TEMP}/bin"
curl --fail --silent --show-error --location \
--output "${RUNNER_TEMP}/gitleaks.tar.gz" \
"https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz"
echo "${GITLEAKS_LINUX_X64_SHA256} ${RUNNER_TEMP}/gitleaks.tar.gz" | sha256sum -c -
tar -xzf "${RUNNER_TEMP}/gitleaks.tar.gz" -C "${RUNNER_TEMP}/bin" gitleaks
chmod +x "${RUNNER_TEMP}/bin/gitleaks"
- name: Scan tracked source for secrets
run: >-
"${RUNNER_TEMP}/bin/gitleaks" dir
--config .gitleaks.toml
--no-banner
--redact
--timeout 120
.
platform-quality:
name: Platform all-features
needs: changes
if: needs.changes.outputs.platform == 'true'
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
persist-credentials: false
submodules: false
- name: Cache Cargo registry and build artifacts
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
with:
key: platform-all-features
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Lint platform crates with all features
run: cargo clippy --locked -p 'registry-platform-*' --all-targets --all-features -- -D warnings
platform-coverage:
name: Platform line coverage
needs: changes
if: needs.changes.outputs.platform == 'true'
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
fetch-depth: 0
persist-credentials: false
submodules: false
- name: Cache Cargo registry and build artifacts
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
with:
key: platform-coverage
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Install pinned coverage tool
uses: taiki-e/install-action@288e746965032cfcc232e09af2daf5f23c14d780 # v2.86.1
with:
tool: cargo-llvm-cov@${{ env.CARGO_LLVM_COV_VERSION }}
- name: Enforce platform line coverage
run: >-
cargo llvm-cov --locked
-p 'registry-platform-*'
--all-features
--fail-under-lines 80
- name: Export platform coverage
run: |
set -euo pipefail
coverage_dir="target/platform-coverage"
mkdir -p "${coverage_dir}"
cargo llvm-cov report --locked \
-p 'registry-platform-*' \
--lcov \
--output-path "${coverage_dir}/platform.lcov"
- name: Stage platform coverage for trusted upload
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: platform-coverage
path: target/platform-coverage/platform.lcov
if-no-files-found: error
retention-days: 1
platform-coverage-upload:
name: Upload platform coverage
needs:
- changes
- platform-coverage
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && needs.changes.outputs.platform == 'true'
runs-on: ubuntu-24.04
permissions:
actions: read
contents: read
id-token: write
steps:
- name: Download platform coverage
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: platform-coverage
path: target/platform-coverage
- name: Upload platform coverage to Codecov
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with:
disable_search: true
fail_ci_if_error: false
files: target/platform-coverage/platform.lcov
flags: platform
name: platform
use_oidc: true
version: v11.3.1
platform-hygiene:
name: Platform hygiene
needs: changes
if: needs.changes.outputs.platform_hygiene == 'true'
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
persist-credentials: false
submodules: false
- name: Check shared Rust hygiene files
run: products/platform/scripts/check-hygiene-alignment.sh
platform-fuzz:
name: Platform fuzz smoke (${{ matrix.target }})
needs: changes
if: needs.changes.outputs.platform == 'true'
runs-on: ubuntu-24.04
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
target:
- authcommon_parsers
- sdjwt_holder_proof
- sdjwt_issuance
- sqlite_statement
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
persist-credentials: false
submodules: false
- name: Install Rust nightly
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # nightly
with:
toolchain: nightly
- name: Cache Cargo registry and build artifacts
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
with:
key: platform-fuzz-${{ matrix.target }}
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Install pinned cargo-fuzz
uses: taiki-e/install-action@288e746965032cfcc232e09af2daf5f23c14d780 # v2.86.1
with:
tool: cargo-fuzz@${{ env.CARGO_FUZZ_VERSION }}
- name: Smoke fuzz target
working-directory: products/platform
run: |
set -euo pipefail
mkdir -p "fuzz/artifacts/${{ matrix.target }}"
cargo +nightly fuzz run --fuzz-dir fuzz --target x86_64-unknown-linux-gnu "${{ matrix.target }}" -- \
-max_total_time=60 \
-rss_limit_mb=1024 \
-artifact_prefix="fuzz/artifacts/${{ matrix.target }}/" \
-print_final_stats=1
- name: Upload fuzz failures
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: platform-fuzz-${{ matrix.target }}
path: products/platform/fuzz/artifacts/${{ matrix.target }}/
if-no-files-found: ignore
rust-policy:
name: Rust policy
needs: changes
if: needs.changes.outputs.rust == 'true'
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
fetch-depth: 0
submodules: false
- name: Cache Cargo registry
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
with:
shared-key: workspace-registry
cache-targets: false
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Install cargo-deny
uses: taiki-e/install-action@288e746965032cfcc232e09af2daf5f23c14d780 # v2.86.1
with:
tool: cargo-deny@0.19.8
- name: Gate inventory
if: needs.changes.outputs.release_tool != 'true'
run: python3 release/scripts/check-gates-inventory.py
- name: Test gate inventory
if: needs.changes.outputs.release_tool != 'true'
run: python3 -m unittest release/scripts/test_check_gates_inventory.py
- name: Cargo deny
run: cargo deny check
rust-quality:
name: Rust format and clippy
needs: changes
if: needs.changes.outputs.rust == 'true'
runs-on: ubuntu-24.04
timeout-minutes: 15
env:
CI_RUST_PACKAGES: ${{ needs.changes.outputs.rust_packages }}
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
persist-credentials: false
submodules: false
- name: Cache Cargo registry
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
with:
shared-key: workspace-registry
cache-targets: false
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Format
run: cargo fmt --check
- name: Clippy affected packages
run: python3 .github/scripts/run_cargo_packages.py clippy
- name: Report disk usage
if: always()
run: |
df -h /
du -sh target 2>/dev/null || true
rust-tests:
name: Rust tests (${{ matrix.name }})
needs: changes
if: needs.changes.outputs.rust == 'true'
runs-on: ubuntu-24.04
timeout-minutes: 15
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.changes.outputs.rust_matrix) }}
env:
CI_RUST_ALL_FEATURES: ${{ matrix.all_features }}
CI_RUST_PACKAGES: ${{ toJSON(matrix.packages) }}
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
persist-credentials: false
submodules: false
- name: Cache Cargo registry
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
with:
shared-key: workspace-registry
cache-targets: false
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Test affected packages
run: python3 .github/scripts/run_cargo_packages.py test
- name: Validate Manifest profiles
if: matrix.name == 'manifest'
working-directory: products/manifest
run: cargo run --locked --profile ci -p registry-manifest-cli -- validate-profiles profiles
- name: Report disk usage
if: always()
run: |
df -h /
du -sh target 2>/dev/null || true
evidence-contracts:
name: Evidence contracts and source neutrality
needs: changes
if: needs.changes.outputs.evidence_contracts == 'true'
runs-on: ubuntu-24.04
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
persist-credentials: false
submodules: false
- name: Cache Cargo registry
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
with:
shared-key: workspace-registry
cache-targets: false
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Reproduce Evidence generated contracts
run: products/evidence/scripts/check-contracts.sh
- name: Reproduce the Evidence authoring schemas
run: products/evidence/scripts/check-authoring-schema.sh
- name: Enforce the authoring library's no-input-output invariant
run: products/evidence/scripts/check-authoring-no-io.sh
- name: Self-test the Evidence neutrality gate
run: products/evidence/scripts/test-check-source-neutrality.sh
- name: Enforce Evidence source-product neutrality
run: products/evidence/scripts/check-source-neutrality.sh
- name: Enforce Evidence verifier portability
run: products/evidence/scripts/check-verifier-portability.sh
- name: Self-test the Evidence configuration key-path gate
run: python3 products/evidence/scripts/test_evidence_config_key_paths.py
- name: Enforce Evidence configuration reference parity
run: products/evidence/scripts/check-config-key-paths.sh
discovery-contracts:
name: Registry Discovery product contracts
needs: changes
if: needs.changes.outputs.discovery_contracts == 'true'
runs-on: ubuntu-24.04
timeout-minutes: 40
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
persist-credentials: false
submodules: false
- name: Cache Cargo registry
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
with:
shared-key: workspace-registry
cache-targets: false
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Install uv
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
with:
version: "0.11.16"
- name: Registry Discovery contract consistency
run: products/discovery/scripts/check-contracts.sh
- name: Registry Discovery HTTP journeys
run: products/discovery/scripts/test-http.sh
- name: Registry Discovery clean-checkout adopter tutorial
run: products/discovery/scripts/test-adopter-tutorial.sh
relay-v2-contracts:
name: Relay V2 product contracts
needs: changes
if: needs.changes.outputs.relay_v2_contracts == 'true'
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
persist-credentials: false
submodules: false
- name: Cache Cargo registry
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
with:
shared-key: workspace-registry
cache-targets: false
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Relay V2 contract consistency
run: products/relay-v2/scripts/check-contracts.sh
- name: Reproduce Relay V2 authoring schemas
run: products/relay-v2/scripts/check-authoring-schema.sh
- name: Relay V2 coequal HTTP journeys
run: products/relay-v2/scripts/test-http.sh
relay-client-contracts:
name: Relay client contract and source neutrality
needs: changes
if: needs.changes.outputs.relay_client_contracts == 'true'
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
persist-credentials: false
submodules: false
- name: Cache Cargo registry
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
with:
shared-key: workspace-registry
cache-targets: false
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Relay client contract consistency
run: products/relay-v2/scripts/check-client-contract.sh
- name: Relay client source neutrality
run: products/relay-v2/scripts/check-source-neutrality.sh
identifiers:
name: Public identifier catalog
needs: changes
if: needs.changes.outputs.identifiers == 'true'
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
persist-credentials: false
submodules: false
- name: Cache Cargo registry
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
with:
shared-key: workspace-registry
cache-targets: false
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Check public identifier catalog
run: products/identifiers/scripts/check.sh
rust-result:
name: Rust workspace
if: always()
needs:
- changes
- rust-policy
- rust-quality
- rust-tests
- discovery-contracts
- evidence-contracts
- relay-v2-contracts
- relay-client-contracts
- identifiers
runs-on: ubuntu-24.04
env:
RUST_JOB_RESULTS: ${{ toJSON(needs) }}
steps:
- name: Require every selected Rust job
run: |
python3 - <<'PY'
import json
import os
import sys
jobs = json.loads(os.environ["RUST_JOB_RESULTS"])
failed = {
name: details["result"]
for name, details in jobs.items()
if details["result"] not in {"success", "skipped"}
}
if failed:
print(f"Rust jobs did not pass: {failed}", file=sys.stderr)
raise SystemExit(1)
print("Every selected Rust job passed; unselected jobs were skipped.")
PY
release-tool:
name: Release tooling checks
needs: changes
if: needs.changes.outputs.release_tool == 'true'
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
fetch-depth: 0
submodules: false
- name: Test release helper
run: python3 -m unittest release/scripts/test_registry_release.py
- name: Test release planning commands
run: python3 -m unittest release/scripts/test_registry_release_plans.py
- name: Test release candidate manifest and promotion verifier
run: python3 -m unittest release/scripts/test_release_candidate.py
- name: Test public release verifier
run: python3 -m unittest release/scripts/test_verify_public_release.py
- name: Test client registry reconciliation
run: python3 -m unittest release/scripts/test_client_registry.py
- name: Test release storage preflight
run: python3 -m unittest release/scripts/test_check_release_storage.py
- name: Test release candidate cleanup
run: python3 -m unittest release/scripts/test_cleanup_release_candidates.py
- name: Test release repeatability workflow
run: python3 -m unittest release/scripts/test_release_repeatability_workflow.py
- name: Test release rehearsal workflow
run: python3 -m unittest release/scripts/test_release_rehearsal.py
- name: Test Linux Node client release build helper
run: python3 -m unittest release/scripts/test_build_linux_node_client.py
- name: Test Zig glibc compiler wrapper
run: python3 -m unittest release/scripts/test_zig_glibc_compiler.py
- name: Test release workflow structure
run: python3 -m unittest release/scripts/test_release_workflow_structure.py
- name: Test release workflow guard
run: python3 -m unittest release/scripts/test_release_workflow_guard.py
- name: Test release image OCI label checker
run: python3 -m unittest release/scripts/test_check_release_image_oci_labels.py
- name: Test release image layout comparator
run: python3 -m unittest release/scripts/test_compare_release_image_layouts.py
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c
with:
version: v0.33.0
driver-opts: image=moby/buildkit:v0.31.2@sha256:2f5adac4ecd194d9f8c10b7b5d7bceb5186853db1b26e5abd3a657af0b7e26ec
- name: Smoke release image OCI labels
run: release/scripts/smoke-release-image-oci-labels.sh
- name: Gate inventory
run: python3 release/scripts/check-gates-inventory.py
- name: Test gate inventory
run: python3 -m unittest release/scripts/test_check_gates_inventory.py
- name: Validate release manifest
run: release/scripts/registry-release validate-current
- name: Validate release docsets
run: release/scripts/registry-release validate-docsets
- name: Audit import map
run: release/scripts/registry-release audit release/manifests/import-map-2026-06-24.yaml
release-tool-required:
# Branch protection requires this exact context. Keep it successful for
# irrelevant changes without running the release-tooling suite.
name: Release tooling
needs:
- changes
- release-tool
if: ${{ always() }}
runs-on: ubuntu-24.04
steps:
- name: Report path-gated result
env:
CHANGES_RESULT: ${{ needs.changes.result }}
REQUIRED: ${{ needs.changes.outputs.release_tool }}
RESULT: ${{ needs.release-tool.result }}
shell: bash
run: |
set -euo pipefail
case "${CHANGES_RESULT}:${REQUIRED}:${RESULT}" in
success:true:success|success:false:skipped)
;;
*)
echo "Release tooling path gate did not complete safely: changes=${CHANGES_RESULT} required=${REQUIRED} result=${RESULT}" >&2
exit 1
;;
esac
release-source-proof:
name: Release source proof checks
needs: changes
if: needs.changes.outputs.release_source_proof == 'true'
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
fetch-depth: 0
submodules: false
- name: Check monorepo source model
run: REGISTRY_RELEASE_SOURCE_MODE=monorepo release/scripts/check-release-source-model.sh
- name: Test source model checker
run: python3 -m unittest release/scripts/test_check_release_source_model.py
release-source-proof-required:
# Branch protection requires this exact context. Keep it successful for
# irrelevant changes without running source proof.
name: Release source proof
needs:
- changes
- release-source-proof
if: ${{ always() }}
runs-on: ubuntu-24.04
steps:
- name: Report path-gated result
env:
CHANGES_RESULT: ${{ needs.changes.result }}
REQUIRED: ${{ needs.changes.outputs.release_source_proof }}
RESULT: ${{ needs.release-source-proof.result }}
shell: bash
run: |
set -euo pipefail
case "${CHANGES_RESULT}:${REQUIRED}:${RESULT}" in
success:true:success|success:false:skipped)
;;
*)
echo "Release source proof path gate did not complete safely: changes=${CHANGES_RESULT} required=${REQUIRED} result=${RESULT}" >&2
exit 1
;;
esac
evidence-tutorials:
name: Evidence tutorials from source
needs: changes
if: needs.changes.outputs.evidence_tutorial == 'true'
runs-on: ubuntu-24.04
timeout-minutes: 40
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
fetch-depth: 0
submodules: false
- name: Assert amd64 runner
shell: bash
run: |
set -euo pipefail
[[ "$(uname -m)" == "x86_64" ]]
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
with:
node-version: 22.12.0
cache: npm
cache-dependency-path: docs/site/package-lock.json
- name: Cache Cargo registry
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
with:
shared-key: workspace-registry
cache-targets: false
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Test the tutorial gate helpers
working-directory: docs/site
run: npm run test:tutorial:evidence
- name: Check tutorial command drift
working-directory: docs/site
run: npm run check:tutorial:evidence:dry-run
- name: Build the Evidence toolset under test
shell: bash
run: |
set -euo pipefail
CARGO_TARGET_DIR="target/evidence-tutorial-source" \
cargo build --locked --profile ci \
-p registry-evidence -p registry-evidencectl \
-p registry-evidence-oid4vci -p registry-mint
CARGO_TARGET_DIR="target/evidence-tutorial-source" \
cargo test --locked --profile ci \
-p registry-evidence-oid4vci --test inji_interoperability --no-run
test_binary=$(find target/evidence-tutorial-source/ci/deps \
-maxdepth 1 -type f -perm -111 -name 'inji_interoperability-*' \
-printf '%T@ %p\n' | sort -nr | sed -n '1s/^[^ ]* //p')
[[ -n "$test_binary" ]]
cp "$test_binary" \
target/evidence-tutorial-source/ci/inji-oid4vci-interop-test
# The application tutorial imports the Python client. It is built for
# the stable ABI, so the container step below imports this same file
# rather than building inside a read-only mount.
CARGO_TARGET_DIR="target/evidence-tutorial-source" \
cargo build --locked --profile ci \
-p registry-evidence-client-py --lib \
--features registry-evidence-client-py/extension-module
- name: Test the exact local Evidence lifecycle
shell: bash
env:
EVIDENCE_BIN: ${{ github.workspace }}/target/evidence-tutorial-source/ci/evidence
MINT_BIN: ${{ github.workspace }}/target/evidence-tutorial-source/ci/mint
run: |
set -euo pipefail
CARGO_TARGET_DIR="target/evidence-tutorial-source" \
cargo test --locked --profile ci \
-p registry-evidencectl --test dev_lifecycle -- \
--ignored --test-threads=1
- name: Execute the Evidence tutorials in a clean container
shell: bash
run: |
set -euo pipefail
# The image is the repository's pinned release-builder digest, used
# here only as a clean Debian userland: the gate exercises a shell
# and coreutils, and the toolset binaries are mounted in prebuilt.
docker run --rm \
--mount "type=bind,src=${PWD},dst=/work,readonly" \
--env EVIDENCE_BIN=/work/target/evidence-tutorial-source/ci/evidence \
--env EVIDENCECTL_BIN=/work/target/evidence-tutorial-source/ci/evidencectl \
--env EVIDENCE_OID4VCI_BIN=/work/target/evidence-tutorial-source/ci/evidence-oid4vci \
--env EVIDENCE_OID4VCI_INTEROP_TEST_BIN=/work/target/evidence-tutorial-source/ci/inji-oid4vci-interop-test \
--env MINT_BIN=/work/target/evidence-tutorial-source/ci/mint \
--env EVIDENCE_CLIENT_PY_LIB=/work/target/evidence-tutorial-source/ci/libregistry_evidence_client.so \
rust:1.95-trixie@sha256:f49565f188ee00bc2a18dd418183f2c5f23ef7d6e691890517ed341a598f67c3 \
bash /work/docs/site/scripts/check-evidence-tutorials.sh
evidence-anchors:
# The documentation anchors cite source across the whole workspace, so this check
# runs on every pull request rather than behind the changed-path classifier: a
# rename outside the docs job's allow-list is exactly the drift it exists to catch.
# The checker imports only node:fs, node:path, and node:url, so a checkout and a
# Node runtime are all it needs; the docs job runs it again inside check:source.
name: Evidence anchors
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
persist-credentials: false
submodules: false
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
with:
node-version: 22.12.0
- name: Check documentation anchors against the source tree
run: node docs/site/scripts/check-evidence-anchors.mjs
docs:
name: Docs checks
needs: changes
if: needs.changes.outputs.docs == 'true'
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
fetch-depth: 0
submodules: false
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
with:
node-version: 22.12.0
cache: npm
cache-dependency-path: docs/site/package-lock.json
- name: Install docs shell dependency
run: |
sudo apt-get update
sudo apt-get install --yes zsh
- name: Assert docs shell dependencies
shell: bash
run: |
set -euo pipefail
command -v sh
command -v bash
command -v zsh
- name: Install docs dependencies
working-directory: docs/site
run: npm ci
- name: Fetch pinned OpenAPI inputs
working-directory: docs/site
run: node scripts/fetch-openapi.mjs
- name: Test docs scripts
working-directory: docs/site
run: npm test
- name: Check production-shaped docs build
working-directory: docs/site
run: npm run check:production
docs-required:
# Branch protection requires this exact context. Keep it successful for
# irrelevant changes without installing or building the docs site.
name: Docs
needs:
- changes
- docs
- docs-archives
if: ${{ always() }}
runs-on: ubuntu-24.04
steps:
- name: Report path-gated result
env:
CHANGES_RESULT: ${{ needs.changes.result }}
REQUIRED: ${{ needs.changes.outputs.docs }}
RESULT: ${{ needs.docs.result }}
ARCHIVES_REQUIRED: ${{ needs.changes.outputs.docs_archives }}
ARCHIVES_RESULT: ${{ needs.docs-archives.result }}
shell: bash
run: |
set -euo pipefail
case "${CHANGES_RESULT}:${REQUIRED}:${RESULT}" in
success:true:success|success:false:skipped)
;;
*)
echo "Docs path gate did not complete safely: changes=${CHANGES_RESULT} required=${REQUIRED} result=${RESULT}" >&2
exit 1
;;
esac
case "${CHANGES_RESULT}:${ARCHIVES_REQUIRED}:${ARCHIVES_RESULT}" in
success:true:success|success:false:skipped)
;;
*)
echo "Docs archive path gate did not complete safely: changes=${CHANGES_RESULT} required=${ARCHIVES_REQUIRED} result=${ARCHIVES_RESULT}" >&2
exit 1
;;
esac
docs-archives:
name: Immutable docs archives
needs: changes
if: needs.changes.outputs.docs_archives == 'true'
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
fetch-depth: 0
submodules: false
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
with:
node-version: 22.12.0
cache: npm
cache-dependency-path: docs/site/package-lock.json
- name: Install docs dependencies
working-directory: docs/site
run: npm ci
- name: Reject changes to locked archive digests
working-directory: docs/site
env:
ARCHIVE_LOCK_BASE_REF: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || github.event.before || 'origin/main' }}
run: npm run check:archive-lock -- --base-ref "${ARCHIVE_LOCK_BASE_REF}"
- name: Assemble and verify the published archive window
working-directory: docs/site
run: npm run check:archives
editor-extensions:
name: Editor extensions
needs: changes
if: needs.changes.outputs.editors == 'true'
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
fetch-depth: 0
submodules: false
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
with:
node-version: 22.12.0
cache: npm
cache-dependency-path: editors/vscode/package-lock.json
- name: Test editor installer
run: bash editors/tests/install_test.sh
- name: Package and test VS Code integration
working-directory: editors/vscode
run: |
npm ci
npm run package:dev
cargo build --locked -p registry-language-server
xvfb-run -a npm test
cmp ../../LICENSE LICENSE
- name: Install Zed extension target
run: rustup target add wasm32-wasip2
- name: Check Zed extension
run: |
cargo check --locked --target wasm32-wasip2 --manifest-path editors/zed/Cargo.toml
cmp LICENSE editors/zed/LICENSE
client-bindings:
name: Native client bindings
needs: changes
if: needs.changes.outputs.client_bindings == 'true'
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
fetch-depth: 0
submodules: false
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
with:
node-version: 22.12.0
cache: npm
cache-dependency-path: |
crates/registry-discovery-client-node/package-lock.json
crates/registry-evidence-client-node/package-lock.json
crates/registry-relay-client-node/package-lock.json
- name: Build and test Node bindings
shell: bash
run: |
set -euo pipefail
for client in registry-discovery-client-node registry-evidence-client-node registry-relay-client-node; do
(
cd "crates/${client}"
npm ci
npm run build:debug
npm test
npm run check:types
cmp ../../LICENSE LICENSE
)
done
- name: Build and test Python bindings
shell: bash
run: |
set -euo pipefail
for client in registry-discovery-client-py registry-evidence-client-py registry-relay-client-py; do
cargo build --locked -p "${client}" --lib --features "${client}/extension-module"
(
cd "crates/${client}"
python3 -m unittest discover -s tests/python -v
cmp ../../LICENSE LICENSE
)
done
release-linux-node-clients:
name: Release Linux Node clients (${{ matrix.asset }})
needs: changes
if: needs.changes.outputs.release_linux_node_clients == 'true'
runs-on: ${{ matrix.runner }}
timeout-minutes: 40
permissions:
contents: read
env:
RUSTUP_TOOLCHAIN: "1.95.0"
strategy:
fail-fast: false
matrix:
include:
- runner: ubuntu-24.04
asset: linux-amd64-glibc
target: x86_64-unknown-linux-gnu
napi_platform: linux-x64-gnu
- runner: ubuntu-24.04-arm
asset: linux-arm64-glibc
target: aarch64-unknown-linux-gnu
napi_platform: linux-arm64-gnu
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
fetch-depth: 0
submodules: false
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
with:
node-version: 22.20.0
cache: npm
cache-dependency-path: |
crates/registry-discovery-client-node/package-lock.json
crates/registry-evidence-client-node/package-lock.json
crates/registry-relay-client-node/package-lock.json
- name: Install pinned Linux client build tools
shell: bash
run: |
set -euo pipefail
rustup toolchain install 1.95.0 --profile minimal
python3 -m venv "${RUNNER_TEMP}/maturin"
"${RUNNER_TEMP}/maturin/bin/pip" install --quiet \
--require-hashes --only-binary=:all: \
--requirement "${GITHUB_WORKSPACE}/release/requirements/maturin-1.9.6.txt"
- name: Prove production Linux Node client recipe
shell: bash
run: |
set -euo pipefail
for client in discovery evidence relay; do
client_dir="${GITHUB_WORKSPACE}/crates/registry-${client}-client-node"
(cd "${client_dir}" && npm ci)
release/scripts/build-linux-node-client \
--client "${client}" \
--target "${{ matrix.target }}" \
--napi-platform "${{ matrix.napi_platform }}" \
--zig-python "${RUNNER_TEMP}/maturin/bin/python"
smoke="${RUNNER_TEMP}/node-smoke-${client}"
mkdir -p "${smoke}/node_modules/@registrystack"
ln -s "${client_dir}" \
"${smoke}/node_modules/@registrystack/${client}-client"
cp "${GITHUB_WORKSPACE}/release/scripts/smoke-${client}-client-package.js" \
"${smoke}/"
(cd "${smoke}" && node "smoke-${client}-client-package.js")
done
ci-result:
name: CI result
if: always()
needs:
- changes
- secrets
- platform-quality
- platform-coverage
- platform-coverage-upload
- platform-hygiene
- platform-fuzz
- rust-result
- release-tool
- release-source-proof
- evidence-tutorials
- evidence-anchors
- docs
- editor-extensions
- client-bindings
- release-linux-node-clients
runs-on: ubuntu-24.04
env:
CI_JOB_RESULTS: ${{ toJSON(needs) }}
steps:
- name: Require every selected CI job
run: |
python3 - <<'PY'
import json
import os
import sys
jobs = json.loads(os.environ["CI_JOB_RESULTS"])
failed = {
name: details["result"]
for name, details in jobs.items()
if details["result"] not in {"success", "skipped"}
}
if failed:
print(f"CI jobs did not pass: {failed}", file=sys.stderr)
raise SystemExit(1)
print("Every selected CI job passed; unselected jobs were skipped.")
PY