Skip to content

docs: retire Relay V1 and registryctl from the published docs #1621

docs: retire Relay V1 and registryctl from the published docs

docs: retire Relay V1 and registryctl from the published docs #1621

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 }}
relay_contracts: ${{ steps.filter.outputs.relay_contracts }}
relay_v2_contracts: ${{ steps.filter.outputs.relay_v2_contracts }}
evidence_contracts: ${{ steps.filter.outputs.evidence_contracts }}
project_authoring: ${{ steps.filter.outputs.project_authoring }}
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 }}
evidence_tutorial: ${{ steps.filter.outputs.evidence_tutorial }}
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
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: 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: Test advisory baseline checkers
run: python3 -m unittest crates/registry-relay/tests/advisory_baseline_check_test.py
- 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 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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
persist-credentials: false
submodules: false
- name: Cache Cargo registry and build artifacts
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # 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-config-report -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
permissions:
contents: read
id-token: write
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
fetch-depth: 0
persist-credentials: false
submodules: false
- name: Cache Cargo registry and build artifacts
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
key: platform-coverage
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Install pinned coverage tool
uses: taiki-e/install-action@25435dc8dd3baed7417e0c96d3fe89013a5b2e09 # v2.81.3
with:
tool: cargo-llvm-cov@${{ env.CARGO_LLVM_COV_VERSION }}
- name: Enforce platform line coverage
run: >-
cargo llvm-cov --locked
-p registry-config-report
-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-config-report \
-p 'registry-platform-*' \
--lcov \
--output-path "${coverage_dir}/platform.lcov"
- 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 and config inventory
needs: changes
if: needs.changes.outputs.platform_hygiene == 'true'
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
persist-credentials: false
submodules: false
- name: Check shared Rust hygiene files
run: products/platform/scripts/check-hygiene-alignment.sh
- name: Audit monorepo config roots
run: >-
products/platform/scripts/audit-configs.sh
--check
--format paths
> "${RUNNER_TEMP}/registry-config-inventory.txt"
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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
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@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
key: platform-fuzz-${{ matrix.target }}
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Install pinned cargo-fuzz
uses: taiki-e/install-action@25435dc8dd3baed7417e0c96d3fe89013a5b2e09 # v2.81.3
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@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
fetch-depth: 0
submodules: false
- name: Cache Cargo registry
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # 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@25435dc8dd3baed7417e0c96d3fe89013a5b2e09 # v2.81.3
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: Test stable surface compatibility checker
if: needs.changes.outputs.release_tool != 'true'
run: python3 -m unittest release/scripts/test_check_stable_surface_compatibility.py
- name: Stable surface compatibility
if: needs.changes.outputs.release_tool != 'true'
env:
STABLE_SURFACE_BASE_REF: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || github.event.before }}
run: python3 release/scripts/check-stable-surface-compatibility.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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
persist-credentials: false
submodules: false
- name: Cache Cargo registry
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # 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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
persist-credentials: false
submodules: false
- name: Cache Cargo registry
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # 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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
persist-credentials: false
submodules: false
- name: Cache Cargo registry
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # 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
relay-contracts:
name: Relay API contracts
needs: changes
if: needs.changes.outputs.relay_contracts == 'true'
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
fetch-depth: 0
persist-credentials: false
submodules: false
- name: Cache Cargo registry
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
shared-key: workspace-registry
cache-targets: false
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Install just
uses: taiki-e/install-action@25435dc8dd3baed7417e0c96d3fe89013a5b2e09 # v2.81.3
with:
tool: just@1.51.0
- name: Install pinned oasdiff
shell: bash
run: |
set -euo pipefail
mkdir -p "${RUNNER_TEMP}/bin"
curl --fail --silent --show-error --location \
--output "${RUNNER_TEMP}/oasdiff.tar.gz" \
"https://github.com/oasdiff/oasdiff/releases/download/v${OASDIFF_VERSION}/oasdiff_${OASDIFF_VERSION}_linux_amd64.tar.gz"
echo "${OASDIFF_LINUX_X64_SHA256} ${RUNNER_TEMP}/oasdiff.tar.gz" | sha256sum -c -
tar -xzf "${RUNNER_TEMP}/oasdiff.tar.gz" -C "${RUNNER_TEMP}/bin" oasdiff
chmod +x "${RUNNER_TEMP}/bin/oasdiff"
echo "${RUNNER_TEMP}/bin" >> "${GITHUB_PATH}"
- name: Relay OpenAPI contract
working-directory: crates/registry-relay
env:
OPENAPI_CONTRACT_BASE_REF: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || github.event.before }}
run: just openapi-contract
- name: Relay exposure check
working-directory: crates/registry-relay
run: just exposure-check
- name: Verify disposable local OpenAPI opt-out
run: >-
cargo test --locked -p registry-relay --test api_docs
openapi_json_can_be_moved_to_public_router_for_local_testing -- --exact
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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
persist-credentials: false
submodules: false
- name: Cache Cargo registry
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # 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
rust-result:
name: Rust workspace
if: always()
needs:
- changes
- rust-policy
- rust-quality
- rust-tests
- evidence-contracts
- relay-contracts
- relay-v2-contracts
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
project-authoring-determinism:
name: Project authoring portability and determinism (${{ matrix.arch }})
needs: changes
if: needs.changes.outputs.project_authoring == 'true'
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- runner: ubuntu-24.04
arch: x86_64-linux
expected_uname: x86_64
- runner: macos-14
arch: aarch64-macos
expected_uname: arm64
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
fetch-depth: 0
submodules: false
- name: Assert native architecture
shell: bash
run: |
set -euo pipefail
test "$(uname -m)" = "${{ matrix.expected_uname }}"
- name: Cache Cargo registry and build artifacts
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
key: project-authoring-${{ matrix.arch }}
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Build the Registryctl journey binary
run: cargo build --locked -p registryctl --bin registryctl
- name: Verify cross-machine project inputs
run: >-
cargo test --locked -p registryctl --test project_authoring
check_and_build_produce_deterministic_product_inputs -- --exact
- name: Verify offline Script authoring and compilation
env:
CARGO_NET_OFFLINE: "true"
run: >-
cargo test --locked -p registryctl --test project_authoring
project_authoring_rhai_commands_are_portable_offline -- --exact
- name: Verify every cataloged authoring journey
run: >-
cargo test --locked -p registryctl --test project_authoring
every_cataloged_supported_project_authoring_command_is_automated -- --exact
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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
fetch-depth: 0
submodules: false
- name: Test adopter Compose conformance checker
run: python3 -m unittest release/scripts/test_check_adopter_compose_contract.py
- name: Test PostgreSQL runtime recipe
env:
REGISTRY_POSTGRESQL_DOCKER_PROOF: "1"
run: python3 -m unittest release/scripts/test_postgresql_runtime_recipe.py
- name: Check adopter Compose models
run: bash release/scripts/check_adopter_compose_contract.sh
- name: Test release helper
run: python3 -m unittest release/scripts/test_registry_release.py
- name: Test first-country release-form runner
run: python3 -m unittest release/scripts/test_first_country_release_form.py
- name: Test RegistryReleaseLockV1 tooling
run: python3 -m unittest release/scripts/test_registry_release_lock.py
- name: Check release-lock runtime and Compose parity
run: bash release/scripts/check-runtime-contract-parity.sh
- name: Test release planning commands
run: python3 -m unittest release/scripts/test_registry_release_plans.py
- name: Test release candidate receipt and promotion verifier
run: python3 -m unittest release/scripts/test_release_candidate.py
- name: Test release proof-level selection
run: python3 -m unittest release/scripts/test_select_release_proof_level.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 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: Test release Relay feature checker
run: python3 -m unittest release/scripts/test_check_release_relay_features.py
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5
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: Test OpenID conformance runner
run: python3 -m unittest release/scripts/test_openid_conformance_runner.py
- name: Test conformance candidate binding
run: python3 -m unittest release/scripts/test_conformance_candidate.py
- name: Test Relay OIDC smoke
run: python3 -m unittest release/scripts/test_relay_oidc_smoke.py
- name: Validate Relay OIDC smoke assets
run: python3 release/scripts/relay-oidc-smoke.py validate
- 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: Test stable surface compatibility checker
run: python3 -m unittest release/scripts/test_check_stable_surface_compatibility.py
- name: Test Relay OpenAPI stability filter
run: python3 -m unittest release/scripts/test_filter_relay_openapi_stability.py
- name: Test upgrade exercise validator
run: python3 -m unittest release/scripts/test_validate_upgrade_exercise.py
- name: Test product-input lifecycle validator
run: python3 -m unittest release/scripts/test_validate_product_input_lifecycle.py
- name: Test first-country acceptance validator
run: python3 -m unittest release/scripts/test_validate_first_country_acceptance.py
- name: Validate first-country acceptance source packet
run: python3 release/scripts/validate-first-country-acceptance.py check-packet
- name: Test upgrade exercise asset preparation
run: python3 -m unittest release/scripts/test_prepare_upgrade_exercise_assets.py
- name: Prepare committed candidate assets
id: candidate-assets
env:
GH_TOKEN: ${{ github.token }}
run: >-
python3 release/scripts/prepare-upgrade-exercise-assets.py
--discover release/exercises
--product-input-records release/exercises/product-input-lifecycle
--asset-root target/candidate-release-assets
--github-output "${GITHUB_OUTPUT}"
- name: Install cosign for committed candidate evidence
if: steps.candidate-assets.outputs.has_candidates == 'true'
uses: sigstore/cosign-installer@398d4b0eeef1380460a10c8013a76f728fb906ac # v3
- name: Install SLSA verifier for committed candidate evidence
if: steps.candidate-assets.outputs.has_candidates == 'true'
env:
SLSA_VERIFIER_SHA256: 946dbec729094195e88ef78e1734324a27869f03e2c6bd2f61cbc06bd5350339
SLSA_VERIFIER_VERSION: v2.7.1
shell: bash
run: |
set -euo pipefail
tools_dir="${RUNNER_TEMP}/upgrade-evidence-tools"
mkdir -p "${tools_dir}"
curl --proto '=https' --tlsv1.2 --fail --location --retry 3 \
--output "${tools_dir}/slsa-verifier" \
"https://github.com/slsa-framework/slsa-verifier/releases/download/${SLSA_VERIFIER_VERSION}/slsa-verifier-linux-amd64"
echo "${SLSA_VERIFIER_SHA256} ${tools_dir}/slsa-verifier" | sha256sum --check
chmod 0755 "${tools_dir}/slsa-verifier"
echo "${tools_dir}" >> "${GITHUB_PATH}"
- name: Validate product-input lifecycle records
run: >-
python3 release/scripts/validate-product-input-lifecycle.py
--discover release/exercises
--candidate-asset-root target/candidate-release-assets
- name: Validate committed upgrade exercise records
run: >-
python3 release/scripts/validate-upgrade-exercise.py
--discover release/exercises
--candidate-asset-root target/candidate-release-assets
- name: Stable surface compatibility
env:
STABLE_SURFACE_BASE_REF: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || github.event.before }}
run: python3 release/scripts/check-stable-surface-compatibility.py
- name: Validate release manifest
shell: bash
run: |
set -euo pipefail
for manifest in release/manifests/registry-stack-*.yaml; do
release/scripts/registry-release validate "${manifest}"
done
- 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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
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@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
with:
node-version: 22.12.0
cache: npm
cache-dependency-path: docs/site/package-lock.json
- name: Cache Cargo registry
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # 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
docs:
name: Docs checks
needs: changes
if: needs.changes.outputs.docs == 'true'
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
fetch-depth: 0
submodules: false
- name: Setup Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
with:
node-version: 22.12.0
cache: npm
cache-dependency-path: docs/site/package-lock.json
- name: Cache Registryctl authoring-reference build
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
shared-key: docs-authoring-reference
save-if: ${{ github.ref == 'refs/heads/main' }}
- 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 docs build
working-directory: docs/site
run: npm run check
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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
fetch-depth: 0
submodules: false
- name: Setup Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
fetch-depth: 0
submodules: false
- name: Setup Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
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: Evidence client bindings
needs: changes
if: needs.changes.outputs.client_bindings == 'true'
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
fetch-depth: 0
submodules: false
- name: Setup Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
with:
node-version: 22.12.0
cache: npm
cache-dependency-path: crates/registry-evidence-client-node/package-lock.json
- name: Build and test the Node binding
working-directory: crates/registry-evidence-client-node
run: |
npm ci
npm run build:debug
npm test
npm run check:types
cmp ../../LICENSE LICENSE
- name: Build and test the Python binding
working-directory: crates/registry-evidence-client-py
run: |
cargo build --locked -p registry-evidence-client-py --lib --features registry-evidence-client-py/extension-module
python3 -m unittest discover -s tests/python -v
cmp ../../LICENSE LICENSE
ci-result:
name: CI result
if: always()
needs:
- changes
- secrets
- platform-quality
- platform-coverage
- platform-hygiene
- platform-fuzz
- rust-result
- project-authoring-determinism
- release-tool
- release-source-proof
- evidence-tutorials
- docs
- editor-extensions
- client-bindings
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