Repository navigation
feat: expose applicant review progress #5771
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: RegistryStack CI | |
| on: | |
| schedule: | |
| - cron: "37 22 * * *" | |
| workflow_dispatch: | |
| inputs: | |
| full: | |
| description: Run every CI gate, including archive and release recipe sweeps | |
| type: boolean | |
| default: true | |
| pull_request: | |
| # `labeled` lets the ci:full label start a run with the heavy tier. | |
| types: [opened, synchronize, reopened, labeled] | |
| 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.12" | |
| ACTIONLINT_LINUX_X64_SHA256: "8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8" | |
| OASDIFF_VERSION: "1.23.0" | |
| OASDIFF_LINUX_X64_SHA256: "972b10535c3db4366b9dc3ebc11ca021279af3095267c3cffdca854a3a3c4f89" | |
| # Matches the Vale version docs/site's @vvago/vale package pins; the docs | |
| # style checks refuse a VALE_BIN that reports any other version. | |
| VALE_VERSION: "3.24.0" | |
| VALE_LINUX_X64_SHA256: "867534ddb678abca7f214bc4706ead0922bd5252ffe8035fc227013f66c8b214" | |
| jobs: | |
| changes: | |
| name: Changed paths | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 5 | |
| outputs: | |
| archive_base_ref: ${{ steps.filter.outputs.archive_base_ref }} | |
| archive_comparison_required: ${{ steps.filter.outputs.archive_comparison_required }} | |
| full_sweep: ${{ steps.filter.outputs.full_sweep }} | |
| 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_assurance: ${{ steps.filter.outputs.platform_assurance }} | |
| platform_coverage: ${{ steps.filter.outputs.platform_coverage }} | |
| platform_hygiene: ${{ steps.filter.outputs.platform_hygiene }} | |
| config_conformance: ${{ steps.filter.outputs.config_conformance }} | |
| discovery_contracts: ${{ steps.filter.outputs.discovery_contracts }} | |
| breg_contracts: ${{ steps.filter.outputs.breg_contracts }} | |
| breg_integration: ${{ steps.filter.outputs.breg_integration }} | |
| breg_contracts_lanes: ${{ steps.filter.outputs.breg_contracts_lanes }} | |
| casework_postgres: ${{ steps.filter.outputs.casework_postgres }} | |
| scheduling_postgres: ${{ steps.filter.outputs.scheduling_postgres }} | |
| evidence_contracts: ${{ steps.filter.outputs.evidence_contracts }} | |
| evidence_assurance: ${{ steps.filter.outputs.evidence_assurance }} | |
| evidence_postgres: ${{ steps.filter.outputs.evidence_postgres }} | |
| scheduling_contracts: ${{ steps.filter.outputs.scheduling_contracts }} | |
| messaging_contracts: ${{ steps.filter.outputs.messaging_contracts }} | |
| messaging_postgres: ${{ steps.filter.outputs.messaging_postgres }} | |
| documents_contracts: ${{ steps.filter.outputs.documents_contracts }} | |
| documents_postgres: ${{ steps.filter.outputs.documents_postgres }} | |
| adapter_contracts: ${{ steps.filter.outputs.adapter_contracts }} | |
| coordinator: ${{ steps.filter.outputs.coordinator }} | |
| 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 }} | |
| breg_tutorial: ${{ steps.filter.outputs.breg_tutorial }} | |
| casework_tutorial: ${{ steps.filter.outputs.casework_tutorial }} | |
| messaging_tutorial: ${{ steps.filter.outputs.messaging_tutorial }} | |
| documents_tutorial: ${{ steps.filter.outputs.documents_tutorial }} | |
| render_tutorial: ${{ steps.filter.outputs.render_tutorial }} | |
| scheduling_tutorial: ${{ steps.filter.outputs.scheduling_tutorial }} | |
| breg_evidence_composition: ${{ steps.filter.outputs.breg_evidence_composition }} | |
| identifiers: ${{ steps.filter.outputs.identifiers }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| fetch-depth: 0 | |
| submodules: false | |
| - name: Classify changed paths | |
| id: filter | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| metadata="${RUNNER_TEMP}/registry-stack-cargo-metadata.json" | |
| # Routing uses declared workspace dependencies without registry downloads. | |
| cargo metadata --locked --no-deps --format-version 1 > "${metadata}" | |
| python3 .github/scripts/ci_event_routing.py \ | |
| --metadata "${metadata}" \ | |
| --github-output "${GITHUB_OUTPUT}" | |
| - name: Check repository identifier reference closure | |
| run: products/identifiers/scripts/generate.py --check-references | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 | |
| with: | |
| version: "0.11.16" | |
| - name: Test CI classifier | |
| run: uv run --no-project --with PyYAML==6.0.2 python .github/scripts/test_ci_changes.py | |
| - name: Test CI event routing | |
| run: python3 .github/scripts/test_ci_event_routing.py | |
| - name: Test Cargo runtime-library resolution | |
| run: >- | |
| python3 -m unittest | |
| scripts/test_cargo_runtime_library_path.py | |
| scripts/test_cargo_runtime_script_contracts.py | |
| - name: Test load-test harness tooling | |
| run: >- | |
| python3 -m unittest | |
| scripts/loadtest/test_evidence.py | |
| products/breg/loadtest/support/test_harness.py | |
| products/evidence/loadtest/support/test_harness.py | |
| products/casework/loadtest/support/test_harness.py | |
| - name: Test ThunderID branding packager | |
| run: python3 -m unittest products/identity/thunderid/branding/test_build.py | |
| - name: Test nightly coverage planning | |
| run: python3 .github/scripts/test_nightly_rust_coverage.py | |
| - name: Test Base Registry Engine gated test selection gate | |
| run: python3 .github/scripts/test_check_breg_gated_tests.py | |
| - name: Check feature-gated Base Registry Engine tests are selected | |
| run: python3 .github/scripts/check_breg_gated_tests.py | |
| - name: Test platform fuzz runner | |
| run: uv run --no-project --with PyYAML==6.0.2 python -m unittest products/platform/scripts/test_run_fuzz_smoke.py | |
| - name: Test evidence fuzz runner | |
| run: uv run --no-project --with PyYAML==6.0.2 python -m unittest products/evidence/scripts/test_run_fuzz_smoke.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 GNU libc floor | |
| run: python3 -m unittest release/scripts/test_glibc_floor.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 | |
| secrets: | |
| name: Secret scan | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 5 | |
| 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 | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Cache Cargo registry and build artifacts | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # 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 | |
| - rust-policy | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.platform_coverage == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 15 | |
| # --all-features enables the dispatch and activation PostgreSQL tests, | |
| # which fail rather than skip without their disposable database. | |
| services: | |
| postgres: | |
| image: docker.io/library/postgres:17.11@sha256:67f41722b7a8cbdb868a44a4995c846eddfdc2973bccb291ce937dce88ad5675 | |
| env: | |
| POSTGRES_DB: dispatch | |
| POSTGRES_USER: dispatch | |
| POSTGRES_PASSWORD: dispatch_test | |
| options: >- | |
| --health-cmd "pg_isready -U dispatch -d dispatch" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| ports: | |
| - 5432/tcp | |
| 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@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| key: platform-coverage | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Install pinned coverage tool | |
| uses: taiki-e/install-action@1e29709c0ec63babbe8f266397a465f29a825f91 # v2.87.31 | |
| with: | |
| tool: cargo-llvm-cov@${{ env.CARGO_LLVM_COV_VERSION }} | |
| - name: Enforce platform line coverage | |
| env: | |
| DISPATCH_TEST_DATABASE_URL: postgresql://dispatch:dispatch_test@localhost:${{ job.services.postgres.ports['5432'] }}/dispatch | |
| ACTIVATION_TEST_DATABASE_URL: postgresql://dispatch:dispatch_test@localhost:${{ job.services.postgres.ports['5432'] }}/dispatch | |
| 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@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 | |
| 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_coverage == 'true' | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 5 | |
| permissions: | |
| actions: read | |
| contents: read | |
| id-token: write | |
| steps: | |
| - name: Download platform coverage | |
| uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 | |
| with: | |
| name: platform-coverage | |
| path: target/platform-coverage | |
| - name: Upload platform coverage to Codecov | |
| uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1 | |
| 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 | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Cache Cargo registry | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Check shared Rust hygiene files | |
| run: products/platform/scripts/check-hygiene-alignment.sh | |
| - name: Test the YAML reader boundary checks | |
| run: python3 -m unittest products/platform/scripts/test_check_yaml_reader_boundary.py | |
| - name: Enforce the YAML reader boundary | |
| run: products/platform/scripts/check-yaml-reader-boundary.sh | |
| - name: Test the rstack dependency boundary check | |
| run: python3 -m unittest products/platform/scripts/test_check_rstack_dependencies.py | |
| - name: Keep rstack a plain bootstrap launcher | |
| run: python3 products/platform/scripts/check-rstack-dependencies.py | |
| platform-fuzz: | |
| name: Platform fuzz smoke (${{ matrix.group }}) | |
| needs: | |
| - changes | |
| - rust-policy | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.platform_assurance == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 15 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - group: authcommon-sqlite | |
| target_a: authcommon_parsers | |
| target_b: sqlite_statement | |
| - group: sd-jwt | |
| target_a: sdjwt_issuance | |
| target_b: sdjwt_presentation_parse | |
| - group: jose | |
| target_a: crypto_jws_parse | |
| target_b: crypto_jwe_decrypt | |
| - group: yaml | |
| target_a: yaml_reader | |
| target_b: yaml_decode | |
| 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@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| key: platform-fuzz-${{ matrix.group }} | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| workspaces: products/platform/fuzz -> target | |
| - name: Install pinned cargo-fuzz | |
| uses: taiki-e/install-action@1e29709c0ec63babbe8f266397a465f29a825f91 # v2.87.31 | |
| with: | |
| tool: cargo-fuzz@${{ env.CARGO_FUZZ_VERSION }} | |
| - name: Smoke fuzz target pair | |
| env: | |
| FUZZ_TARGET_A: ${{ matrix.target_a }} | |
| FUZZ_TARGET_B: ${{ matrix.target_b }} | |
| run: products/platform/scripts/run-fuzz-smoke.sh "$FUZZ_TARGET_A" "$FUZZ_TARGET_B" | |
| - name: Upload fuzz failures | |
| if: failure() | |
| uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 | |
| with: | |
| name: platform-fuzz-${{ matrix.group }} | |
| path: | | |
| products/platform/fuzz/artifacts/${{ matrix.target_a }}/ | |
| products/platform/fuzz/artifacts/${{ matrix.target_b }}/ | |
| if-no-files-found: ignore | |
| evidence-fuzz: | |
| name: Evidence fuzz smoke (${{ matrix.group }}) | |
| needs: | |
| - changes | |
| - rust-policy | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.evidence_assurance == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 15 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - group: verifier | |
| target_a: verifier_flattened_jws | |
| target_b: verifier_sd_jwt_vc | |
| target_c: verifier_holder_proof | |
| - group: authoring | |
| target_a: authoring_openapi | |
| target_b: authoring_project | |
| 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@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| key: evidence-fuzz-${{ matrix.group }} | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| workspaces: products/evidence/fuzz -> target | |
| - name: Install pinned cargo-fuzz | |
| uses: taiki-e/install-action@1e29709c0ec63babbe8f266397a465f29a825f91 # v2.87.31 | |
| with: | |
| tool: cargo-fuzz@${{ env.CARGO_FUZZ_VERSION }} | |
| - name: Smoke fuzz target pair | |
| env: | |
| FUZZ_TARGET_A: ${{ matrix.target_a }} | |
| FUZZ_TARGET_B: ${{ matrix.target_b }} | |
| FUZZ_TARGET_C: ${{ matrix.target_c }} | |
| run: products/evidence/scripts/run-fuzz-smoke.sh "$FUZZ_TARGET_A" "$FUZZ_TARGET_B" ${FUZZ_TARGET_C:+"$FUZZ_TARGET_C"} | |
| - name: Upload fuzz failures | |
| if: failure() | |
| uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 | |
| with: | |
| name: evidence-fuzz-${{ matrix.group }} | |
| path: | | |
| products/evidence/fuzz/artifacts/${{ matrix.target_a }}/ | |
| products/evidence/fuzz/artifacts/${{ matrix.target_b }}/ | |
| products/evidence/fuzz/artifacts/${{ matrix.target_c || matrix.target_a }}/ | |
| if-no-files-found: ignore | |
| rust-policy: | |
| name: Rust policy | |
| needs: changes | |
| if: needs.changes.outputs.rust == 'true' | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| fetch-depth: 0 | |
| submodules: false | |
| - name: Cache Cargo registry | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # 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@1e29709c0ec63babbe8f266397a465f29a825f91 # v2.87.31 | |
| with: | |
| tool: cargo-deny@0.19.8 | |
| - name: Install uv | |
| if: needs.changes.outputs.release_tool != 'true' | |
| uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 | |
| with: | |
| version: "0.11.16" | |
| - 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: uv run --no-project --with PyYAML==6.0.2 python3 -m unittest release/scripts/test_check_gates_inventory.py | |
| - name: Test Coordinator dependency gate | |
| run: python3 -m unittest discover -s products/coordinator/scripts -p 'test_*.py' | |
| - name: Test MCP dependency boundaries | |
| run: | | |
| python3 -m unittest discover -s products/platform/scripts -p 'test_check_mcp_dependencies.py' | |
| python3 -m unittest discover -s products/casework/scripts -p 'test_dependency_direction.py' | |
| - name: MCP dependency direction | |
| run: | | |
| python3 products/platform/scripts/check-mcp-dependencies.py | |
| python3 products/casework/scripts/check_dependency_direction.py | |
| - name: Test Scheduling integrations | |
| if: needs.changes.outputs.release_tool != 'true' | |
| run: | | |
| uv run --locked --directory products/scheduling/integrations/calendar-busy \ | |
| python -m unittest -v test_calendar_busy.py | |
| python3 -m unittest discover -s products/scheduling/integrations/finite-series -p 'test_*.py' | |
| python3 -m unittest discover -s products/scheduling/integrations/operational-reporting -p 'test_*.py' | |
| - name: Coordinator dependency direction | |
| # Runs on every Rust change, so a crate that starts depending on a | |
| # Coordinator crate is refused wherever it lives. | |
| run: python3 products/coordinator/scripts/check_dependency_direction.py | |
| - name: Cargo deny | |
| run: cargo deny check | |
| - name: Standalone Cargo lockfiles | |
| # Fuzz, SDK and editor workspaces keep their own Cargo.lock, and most | |
| # build root crates by path, so a root change can leave one stale. | |
| # Resolving with --locked fails on a stale lock and reads only the | |
| # registry index, not crate sources. | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| mapfile -t locks < <(git ls-files '*/Cargo.lock') | |
| (( ${#locks[@]} > 0 )) | |
| for lock in "${locks[@]}"; do | |
| echo "Checking ${lock}" | |
| cargo update --workspace --locked \ | |
| --manifest-path "$(dirname "${lock}")/Cargo.toml" | |
| done | |
| rust-quality: | |
| name: Rust format and clippy | |
| needs: | |
| - changes | |
| - rust-policy | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && 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@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # 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 | |
| - rust-policy | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.rust == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| # The Casework and BReg shards take 11 to 13 minutes on a typical runner; | |
| # this limit only stops a hung shard, so it leaves room for a slow one. | |
| timeout-minutes: 25 | |
| strategy: | |
| fail-fast: false | |
| # Avoid filling the runner pool with short shards while the longer | |
| # product integration jobs wait. Every selected shard still runs. | |
| max-parallel: 6 | |
| 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@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # 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: Test the synthetic authorization server | |
| if: matrix.name == 'platform' && contains(matrix.packages, 'registry-platform-testing') | |
| run: cargo test --locked -p registry-platform-testing --features test-authorization-server --test test_authorization_server | |
| - name: Check Casework schemas against their generators | |
| if: matrix.name == 'casework' | |
| run: products/casework/scripts/check-schemas.sh | |
| - name: Validate Manifest profiles | |
| if: matrix.name == 'manifest' | |
| working-directory: products/manifest | |
| run: cargo run --locked -p registry-manifest-cli -- validate-profiles profiles | |
| - name: Reproduce the Manifest schemas | |
| if: matrix.name == 'manifest' | |
| run: cargo test --locked -p registry-manifest-cli --features schema --lib schema::tests | |
| - name: Reproduce the configurable MCP schema | |
| if: matrix.name == 'mcp' && contains(matrix.packages, 'registry-mcp') | |
| run: cargo test --locked -p registry-mcp --features schema --lib schema::tests | |
| - name: Reproduce the Render schemas | |
| if: matrix.name == 'render' | |
| run: cargo test --locked -p registry-render --features schema --lib schema::tests | |
| - name: Reproduce the task connection schema | |
| if: matrix.name == 'developer-tools' && contains(matrix.packages, 'registry-thunderid-tooling') | |
| run: cargo test --locked -p registry-thunderid-tooling --features schema --lib schema::tests | |
| - name: Reproduce the saved API connections schema | |
| if: matrix.name == 'developer-tools' && contains(matrix.packages, 'registry-cli-api') | |
| run: cargo test --locked -p registry-cli-api --features schema --lib schema::tests | |
| - 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@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Test bounded FHIR example transport | |
| run: python3 products/evidence/examples/fhir/test_source.py | |
| - 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 | |
| # A deployment without wallet sources links none of the presentation | |
| # verification dependencies, so the runtime must build without the | |
| # default `wallet-presentation` feature and must not reach that crate. | |
| - name: Build Evidence without wallet presentation | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| cargo check --locked -p registry-evidence --no-default-features --all-targets | |
| cargo test --locked -p registry-evidence --no-default-features --test host_protocols | |
| if cargo tree --locked -p registry-evidence --no-default-features -e normal --prefix none \ | |
| | grep -q '^registry-evidence-presentation '; then | |
| echo "::error::registry-evidence reaches registry-evidence-presentation without the wallet-presentation feature" | |
| exit 1 | |
| fi | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 | |
| with: | |
| version: "0.11.16" | |
| - name: Self-test the Evidence configuration key-path gate | |
| run: uv run --no-project --with PyYAML==6.0.2 python3 products/evidence/scripts/test_evidence_config_key_paths.py | |
| - name: Enforce Evidence configuration reference parity | |
| run: uv run --no-project --with PyYAML==6.0.2 products/evidence/scripts/check-config-key-paths.sh | |
| evidence-postgres: | |
| name: Evidence PostgreSQL status ledger and store | |
| needs: [changes, rust-policy] | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.evidence_postgres == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 30 | |
| services: | |
| postgres: | |
| image: docker.io/library/postgres:17.11@sha256:67f41722b7a8cbdb868a44a4995c846eddfdc2973bccb291ce937dce88ad5675 | |
| env: | |
| POSTGRES_DB: evidence | |
| POSTGRES_USER: evidence | |
| POSTGRES_PASSWORD: evidence_test | |
| options: >- | |
| --health-cmd "pg_isready -U evidence -d evidence" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| ports: | |
| - 5432/tcp | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Rust cache | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Verify the credential status ledger against PostgreSQL | |
| env: | |
| EVIDENCE_STATUS_TEST_DATABASE_URL: postgresql://evidence:evidence_test@localhost:${{ job.services.postgres.ports['5432'] }}/evidence | |
| run: cargo test --locked -p registry-evidence --features postgres-test --test status_ledger --test status_transitions --test status_privacy | |
| - name: Verify the OID4VCI store contract on both backends | |
| env: | |
| EVIDENCE_OID4VCI_TEST_DATABASE_URL: postgresql://evidence:evidence_test@localhost:${{ job.services.postgres.ports['5432'] }}/evidence | |
| run: cargo test --locked -p registry-evidence-oid4vci --features postgres-test --test store_contract | |
| 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: Setup Node | |
| uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 | |
| with: | |
| node-version: 24.11.0 | |
| cache: npm | |
| cache-dependency-path: docs/site/package-lock.json | |
| - name: Cache Cargo registry | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 | |
| 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: Install docs dependencies | |
| working-directory: docs/site | |
| # The tutorial runner needs only pure-JS packages. Skipping install | |
| # scripts keeps the Vale postinstall's unauthenticated GitHub | |
| # download, which shared runner addresses get refused on, out of | |
| # this job. | |
| run: npm ci --ignore-scripts | |
| - name: Test the tutorial runner | |
| working-directory: docs/site | |
| run: npm run test:tutorial:runner | |
| - name: Check tutorial command drift | |
| working-directory: docs/site | |
| run: npm run check:tutorial:discovery:dry-run | |
| - name: Build the Registry Discovery binaries the tutorial runs | |
| run: cargo build --locked -p registry-discovery -p registry-discoveryctl -p registry-rstack --bins | |
| - name: Execute the Registry Discovery tutorial from a copy of the checkout | |
| env: | |
| DISCOVERY_BIN: ${{ github.workspace }}/target/debug/discovery | |
| DISCOVERYCTL_BIN: ${{ github.workspace }}/target/debug/discoveryctl | |
| RSTACK_BIN: ${{ github.workspace }}/target/debug/rstack | |
| # The page serves on 127.0.0.1:38080 and 38090, which nothing on this | |
| # runner holds, so the replay runs on the ports a reader gets. | |
| run: node docs/site/scripts/run-tutorial.mjs --gate discovery | |
| casework-postgres: | |
| name: Casework PostgreSQL transactions (${{ matrix.part }}) | |
| needs: [changes, rust-policy] | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.casework_postgres == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 30 | |
| strategy: | |
| fail-fast: false | |
| # The offline adopter proof and the database runtime journeys are | |
| # independent gates, so they run as parallel parts instead of one | |
| # serial job; both keep their own build of the authoring tools. | |
| matrix: | |
| part: [offline, runtime] | |
| services: | |
| postgres: | |
| image: docker.io/library/postgres:17.11@sha256:67f41722b7a8cbdb868a44a4995c846eddfdc2973bccb291ce937dce88ad5675 | |
| env: | |
| POSTGRES_DB: casework | |
| POSTGRES_USER: casework | |
| POSTGRES_PASSWORD: casework_test | |
| options: >- | |
| --health-cmd "pg_isready -U casework -d casework" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| ports: | |
| - 5432/tcp | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Rust cache | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Build the Casework authoring tool | |
| run: cargo build --locked -p registry-caseworkctl -p registry-bregctl | |
| - name: Verify Casework product contracts and offline authoring journeys | |
| if: matrix.part == 'offline' | |
| env: | |
| CASEWORKCTL_BIN: ${{ github.workspace }}/target/debug/caseworkctl | |
| BREGCTL_BIN: ${{ github.workspace }}/target/debug/bregctl | |
| run: products/casework/scripts/check-checkpoint.sh | |
| - name: Casework logical backup and restore of a submitted review | |
| if: matrix.part == 'runtime' | |
| # Drives the public dev/operator binaries against owned disposable | |
| # PostgreSQL, preserving the backup point and append-only audit journal. | |
| run: products/casework/scripts/test-backup-restore.sh | |
| - name: Verify the rewritten Evidence deployment loads through the Evidence loader | |
| if: matrix.part == 'runtime' | |
| # The fixture machinery lives behind postgres-test, but this test needs | |
| # neither a database nor an issuer. An inexact name filter that selects | |
| # nothing still exits 0, so the step names the test exactly and fails | |
| # unless it reports one pass. | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| cargo test --locked -p registry-casework --features postgres-test --lib \ | |
| -- --exact task_grants::native_exchange_tests::the_rewritten_evidence_deployment_loads_through_the_evidence_loader \ | |
| | tee "${RUNNER_TEMP}/casework-evidence-fixture.log" | |
| grep -q 'test result: ok\. 1 passed' "${RUNNER_TEMP}/casework-evidence-fixture.log" || { echo "::error::expected exactly one passing test for the_rewritten_evidence_deployment_loads_through_the_evidence_loader"; exit 1; } | |
| - name: Verify review transactions, staffing, retention, HTTP and producer boundaries | |
| if: matrix.part == 'runtime' | |
| # Every maintained Casework target uses a unique schema. The service | |
| # database is disposable; no test resets public or shares task state. | |
| env: | |
| CASEWORKCTL_BIN: ${{ github.workspace }}/target/debug/caseworkctl | |
| BREGCTL_BIN: ${{ github.workspace }}/target/debug/bregctl | |
| CASEWORK_REVIEW_TEST_DATABASE_URL: postgresql://casework:casework_test@localhost:${{ job.services.postgres.ports['5432'] }}/casework | |
| CASEWORK_ACTIVATION_TEST_DATABASE_URL: postgresql://casework:casework_test@localhost:${{ job.services.postgres.ports['5432'] }}/casework | |
| CASEWORK_ASSIGNMENT_TEST_DATABASE_URL: postgresql://casework:casework_test@localhost:${{ job.services.postgres.ports['5432'] }}/casework | |
| BREG_TEST_DATABASE_URL: postgresql://casework:casework_test@localhost:${{ job.services.postgres.ports['5432'] }}/casework | |
| run: | | |
| cargo test --locked -p registry-casework --features postgres-test \ | |
| --test review_acceptance_postgres \ | |
| --test review_migration_postgres \ | |
| --test review_directory_postgres \ | |
| --test review_postgres \ | |
| --test review_http \ | |
| --test review_payment_fixture_postgres \ | |
| --test breg_review_journey | |
| cargo test --locked -p registry-casework --features postgres-test --lib task_grants:: | |
| - name: Verify operator refusal reports and split runtime database roles | |
| if: matrix.part == 'runtime' | |
| # Exact filters and the pass count keep a renamed test from silently | |
| # dropping the schema-newer and retained-session security proofs. | |
| shell: bash | |
| env: | |
| CASEWORK_REVIEW_TEST_DATABASE_URL: postgresql://casework:casework_test@localhost:${{ job.services.postgres.ports['5432'] }}/casework | |
| CASEWORK_TEST_DATABASE_URL: postgresql://casework:casework_test@localhost:${{ job.services.postgres.ports['5432'] }}/casework | |
| run: | | |
| set -euo pipefail | |
| cargo test --locked -p registry-caseworkctl --features postgres-test,schema --lib \ | |
| -- --exact operator_tests::apply_reports_a_schema_newer_than_this_binary_with_its_own_refusal \ | |
| dev::tests::a_retained_split_session_start_leaves_the_ledgers_read_only_to_the_runtime \ | |
| | tee "${RUNNER_TEMP}/caseworkctl-apply.log" | |
| grep -q 'test result: ok\. 2 passed' "${RUNNER_TEMP}/caseworkctl-apply.log" | |
| - name: Create isolated task approval database | |
| if: matrix.part == 'runtime' | |
| env: | |
| POSTGRES_CONTAINER_ID: ${{ job.services.postgres.id }} | |
| run: docker exec "$POSTGRES_CONTAINER_ID" createdb -U casework casework_task_approval | |
| - name: Casework task approval through stock issuer to Evidence, BReg, and Scheduling | |
| if: matrix.part == 'runtime' | |
| # An inexact name filter that selects nothing still exits 0, so the | |
| # step names each test exactly and fails unless it reports one pass. | |
| shell: bash | |
| env: | |
| CASEWORK_ASSIGNMENT_TEST_DATABASE_URL: postgresql://casework:casework_test@localhost:${{ job.services.postgres.ports['5432'] }}/casework_task_approval | |
| BREG_TEST_DATABASE_URL: postgresql://casework:casework_test@localhost:${{ job.services.postgres.ports['5432'] }}/casework_task_approval | |
| run: | | |
| set -euo pipefail | |
| cargo build --locked -p registry-scheduling \ | |
| --example scheduling-auth-probe | |
| SCHEDULING_AUTH_PROBE_BIN="${GITHUB_WORKSPACE}/target/debug/examples/scheduling-auth-probe" \ | |
| cargo test --locked -p registry-casework \ | |
| --features postgres-test --lib \ | |
| -- --ignored --exact \ | |
| task_grants::native_exchange_tests::approved_casework_tasks_reach_evidence_breg_and_scheduling_through_stock_thunderid \ | |
| | tee "${RUNNER_TEMP}/casework-task-approval.log" | |
| grep -q 'test result: ok\. 1 passed' "${RUNNER_TEMP}/casework-task-approval.log" || { echo "::error::expected exactly one passing test for approved_casework_tasks_reach_evidence_breg_and_scheduling_through_stock_thunderid"; exit 1; } | |
| cargo build --locked -p registry-casework -p registry-caseworkctl | |
| cargo test --locked -p registry-casework \ | |
| --features postgres-test --lib \ | |
| -- --ignored --exact \ | |
| task_grants::local_session_tests::submitted_review_dev_approves_exchanges_and_revokes_on_stock_issuer \ | |
| | tee "${RUNNER_TEMP}/casework-local-session.log" | |
| grep -q 'test result: ok\. 1 passed' "${RUNNER_TEMP}/casework-local-session.log" || { echo "::error::expected exactly one passing test for submitted_review_dev_approves_exchanges_and_revokes_on_stock_issuer"; exit 1; } | |
| scheduling-contracts: | |
| name: Scheduling product contracts | |
| needs: [changes, rust-policy] | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.scheduling_contracts == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Cache Cargo registry | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 | |
| with: | |
| version: "0.11.16" | |
| - name: Scheduling contract consistency | |
| run: uv run --no-project --with PyYAML==6.0.2 products/scheduling/scripts/check-contracts.sh | |
| - name: Check Scheduling schemas against their generators | |
| run: products/scheduling/scripts/check-schemas.sh | |
| scheduling-postgres: | |
| name: Scheduling PostgreSQL transactions | |
| needs: [changes, rust-policy] | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.scheduling_postgres == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 30 | |
| services: | |
| postgres: | |
| image: docker.io/library/postgres:17.11@sha256:67f41722b7a8cbdb868a44a4995c846eddfdc2973bccb291ce937dce88ad5675 | |
| env: | |
| POSTGRES_DB: scheduling | |
| POSTGRES_USER: scheduling | |
| POSTGRES_PASSWORD: scheduling_test | |
| options: >- | |
| --health-cmd "pg_isready -U scheduling -d scheduling" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| ports: | |
| - 5432/tcp | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Rust cache | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 | |
| with: | |
| version: "0.11.16" | |
| - name: Build the Scheduling authoring tool | |
| run: cargo build --locked -p registry-schedulingctl | |
| - name: Verify Scheduling product contracts and offline authoring journeys | |
| env: | |
| SCHEDULINGCTL_BIN: ${{ github.workspace }}/target/debug/schedulingctl | |
| run: uv run --no-project --with PyYAML==6.0.2 products/scheduling/scripts/check-checkpoint.sh | |
| - name: Verify commitment ledger transactions | |
| env: | |
| SCHEDULING_TEST_DATABASE_URL: postgresql://scheduling:scheduling_test@localhost:${{ job.services.postgres.ports['5432'] }}/scheduling | |
| run: cargo test --locked -p registry-scheduling --features postgres-test --test postgres_commitments | |
| - name: Create isolated authoring-apply test database | |
| env: | |
| POSTGRES_CONTAINER_ID: ${{ job.services.postgres.id }} | |
| run: docker exec "$POSTGRES_CONTAINER_ID" createdb -U scheduling scheduling_records_apply | |
| - name: Verify offline authoring record application | |
| env: | |
| SCHEDULING_TEST_DATABASE_URL: postgresql://scheduling:scheduling_test@localhost:${{ job.services.postgres.ports['5432'] }}/scheduling_records_apply | |
| run: cargo test --locked -p registry-schedulingctl --features postgres-test --test records_apply_postgres --test records_apply_busy_sources | |
| - name: Create isolated delivery-intent test database | |
| env: | |
| POSTGRES_CONTAINER_ID: ${{ job.services.postgres.id }} | |
| run: docker exec "$POSTGRES_CONTAINER_ID" createdb -U scheduling scheduling_intents | |
| - name: Verify undelivered delivery intent reads | |
| env: | |
| SCHEDULING_TEST_DATABASE_URL: postgresql://scheduling:scheduling_test@localhost:${{ job.services.postgres.ports['5432'] }}/scheduling_intents | |
| run: cargo test --locked -p registry-schedulingctl --features postgres-test --test intents_postgres | |
| - name: Create isolated package-activation test database | |
| env: | |
| POSTGRES_CONTAINER_ID: ${{ job.services.postgres.id }} | |
| run: docker exec "$POSTGRES_CONTAINER_ID" createdb -U scheduling scheduling_activation | |
| - name: Verify package activation, role separation, and startup refusals | |
| env: | |
| SCHEDULING_TEST_DATABASE_URL: postgresql://scheduling:scheduling_test@localhost:${{ job.services.postgres.ports['5432'] }}/scheduling_activation | |
| run: cargo test --locked -p registry-schedulingctl --features postgres-test --test activation_postgres | |
| - name: Verify shared package activation primitives | |
| env: | |
| ACTIVATION_TEST_DATABASE_URL: postgresql://scheduling:scheduling_test@localhost:${{ job.services.postgres.ports['5432'] }}/scheduling_activation | |
| run: cargo test --locked -p registry-platform-activation --features postgres-test --test postgres_activation | |
| - name: Create isolated dispatch-core test database | |
| env: | |
| POSTGRES_CONTAINER_ID: ${{ job.services.postgres.id }} | |
| run: docker exec "$POSTGRES_CONTAINER_ID" createdb -U scheduling dispatch | |
| - name: Verify the shared dispatch core's fenced lease transitions | |
| env: | |
| DISPATCH_TEST_DATABASE_URL: postgresql://scheduling:scheduling_test@localhost:${{ job.services.postgres.ports['5432'] }}/dispatch | |
| run: cargo test --locked -p registry-platform-dispatch --features postgres-test | |
| - name: Create isolated hook-delivery test database | |
| env: | |
| POSTGRES_CONTAINER_ID: ${{ job.services.postgres.id }} | |
| run: docker exec "$POSTGRES_CONTAINER_ID" createdb -U scheduling hooks | |
| - name: Verify the shared hook delivery schema installs and reinstalls | |
| # These tests are ignored without a database, and a run that selects | |
| # nothing still exits 0, so the step fails unless at least one passes. | |
| shell: bash | |
| env: | |
| HOOKS_TEST_DATABASE_URL: postgresql://scheduling:scheduling_test@localhost:${{ job.services.postgres.ports['5432'] }}/hooks | |
| run: | | |
| set -euo pipefail | |
| cargo test --locked -p registry-platform-hooks --features postgres --lib \ | |
| -- --ignored \ | |
| | tee "${RUNNER_TEMP}/platform-hooks-postgres.log" | |
| grep -Eq 'test result: ok\. [1-9][0-9]* passed' "${RUNNER_TEMP}/platform-hooks-postgres.log" || { echo "::error::expected at least one passing PostgreSQL test for registry-platform-hooks"; exit 1; } | |
| messaging-contracts: | |
| name: Messaging product contracts and vendor neutrality | |
| needs: [changes, rust-policy] | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.messaging_contracts == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Cache Cargo registry | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 | |
| with: | |
| version: "0.11.16" | |
| - name: Messaging contract consistency | |
| run: uv run --no-project --with PyYAML==6.0.2 products/messaging/scripts/check-contracts.sh | |
| - name: Self-test the Messaging vendor-neutrality gate | |
| run: products/messaging/scripts/test-check-vendor-neutrality.sh | |
| - name: Enforce Messaging vendor neutrality | |
| run: products/messaging/scripts/check-vendor-neutrality.sh | |
| messaging-postgres: | |
| name: Messaging PostgreSQL runtime | |
| needs: [changes, rust-policy] | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.messaging_postgres == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 30 | |
| services: | |
| postgres: | |
| image: docker.io/library/postgres:17.11@sha256:67f41722b7a8cbdb868a44a4995c846eddfdc2973bccb291ce937dce88ad5675 | |
| env: | |
| POSTGRES_DB: messaging | |
| POSTGRES_USER: messaging | |
| POSTGRES_PASSWORD: messaging_test | |
| options: >- | |
| --health-cmd "pg_isready -U messaging -d messaging" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| ports: | |
| - 5432/tcp | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Rust cache | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 | |
| with: | |
| version: "0.11.16" | |
| - name: Build the Messaging operator tool | |
| run: cargo build --locked -p registry-messagingctl | |
| - name: Verify Messaging product contracts and offline configuration checks | |
| env: | |
| MESSAGINGCTL_BIN: ${{ github.workspace }}/target/debug/messagingctl | |
| run: uv run --no-project --with PyYAML==6.0.2 products/messaging/scripts/check-checkpoint.sh | |
| - name: Verify migrations, readiness, and the served runtime | |
| env: | |
| MESSAGING_TEST_DATABASE_URL: postgresql://messaging:messaging_test@localhost:${{ job.services.postgres.ports['5432'] }}/messaging | |
| run: cargo test --locked -p registry-messaging --features postgres-test --test postgres_migrate | |
| - name: Verify package activation and template stability | |
| env: | |
| MESSAGING_TEST_DATABASE_URL: postgresql://messaging:messaging_test@localhost:${{ job.services.postgres.ports['5432'] }}/messaging | |
| run: cargo test --locked -p registry-messaging --features postgres-test --test postgres_package | |
| - name: Verify message submission, visibility, and cancellation routes | |
| env: | |
| MESSAGING_TEST_DATABASE_URL: postgresql://messaging:messaging_test@localhost:${{ job.services.postgres.ports['5432'] }}/messaging | |
| run: cargo test --locked -p registry-messaging --features postgres-test --test postgres_messages | |
| - name: Verify dispatch worker outcomes and settlement | |
| env: | |
| MESSAGING_TEST_DATABASE_URL: postgresql://messaging:messaging_test@localhost:${{ job.services.postgres.ports['5432'] }}/messaging | |
| run: cargo test --locked -p registry-messaging --features postgres-test --test postgres_dispatch | |
| - name: Verify provider callbacks and delivery reports | |
| env: | |
| MESSAGING_TEST_DATABASE_URL: postgresql://messaging:messaging_test@localhost:${{ job.services.postgres.ports['5432'] }}/messaging | |
| run: cargo test --locked -p registry-messaging --features postgres-test --test postgres_callbacks | |
| - name: Verify retention erasure | |
| env: | |
| MESSAGING_TEST_DATABASE_URL: postgresql://messaging:messaging_test@localhost:${{ job.services.postgres.ports['5432'] }}/messaging | |
| run: cargo test --locked -p registry-messaging --features postgres-test --test postgres_retention | |
| - name: Verify messagingctl messages commands | |
| env: | |
| MESSAGING_TEST_DATABASE_URL: postgresql://messaging:messaging_test@localhost:${{ job.services.postgres.ports['5432'] }}/messaging | |
| run: cargo test --locked -p registry-messagingctl --features postgres-test --tests | |
| - name: Send one email and one SMS through messagingctl dev | |
| env: | |
| MESSAGINGCTL_BIN: ${{ github.workspace }}/target/debug/messagingctl | |
| run: products/messaging/scripts/test-dev.sh | |
| documents-contracts: | |
| name: Document Store product contracts | |
| needs: [changes, rust-policy] | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.documents_contracts == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 | |
| with: | |
| version: "0.11.16" | |
| - name: Document Store contract consistency | |
| run: uv run --no-project --with PyYAML==6.0.2 products/documents/scripts/check-contracts.sh | |
| documents-postgres: | |
| name: Document Store PostgreSQL runtime | |
| needs: [changes, rust-policy] | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.documents_postgres == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 30 | |
| services: | |
| postgres: | |
| image: docker.io/library/postgres:17.11@sha256:67f41722b7a8cbdb868a44a4995c846eddfdc2973bccb291ce937dce88ad5675 | |
| env: | |
| POSTGRES_DB: documents | |
| POSTGRES_USER: documents | |
| POSTGRES_PASSWORD: documents_test | |
| options: >- | |
| --health-cmd "pg_isready -U documents -d documents" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| ports: | |
| - 5432/tcp | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Rust cache | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 | |
| with: | |
| version: "0.11.16" | |
| - name: Build the Document Store operator tool | |
| run: cargo build --locked -p registry-documentsctl | |
| - name: Verify Document Store product contracts and offline configuration checks | |
| env: | |
| DOCUMENTSCTL_BIN: ${{ github.workspace }}/target/debug/documentsctl | |
| run: uv run --no-project --with PyYAML==6.0.2 products/documents/scripts/check-checkpoint.sh | |
| - name: Verify database readiness, activation, the served runtime, and S3 storage | |
| env: | |
| DOCUMENTS_TEST_DATABASE_URL: postgresql://documents:documents_test@localhost:${{ job.services.postgres.ports['5432'] }}/documents | |
| run: cargo test --locked -p registry-documents --features postgres-test --test postgres_startup --test postgres_operator --test postgres_documents --test postgres_s3 | |
| - name: Verify the documentsctl activation verbs against PostgreSQL | |
| env: | |
| DOCUMENTS_TEST_DATABASE_URL: postgresql://documents:documents_test@localhost:${{ job.services.postgres.ports['5432'] }}/documents | |
| run: cargo test --locked -p registry-documentsctl --features postgres-test --test postgres_cli | |
| - name: Build Registry Render for the golden journey | |
| run: cargo build --locked -p registry-render | |
| - name: Verify the golden journey from a rendered document to an expired share | |
| env: | |
| DOCUMENTS_TEST_DATABASE_URL: postgresql://documents:documents_test@localhost:${{ job.services.postgres.ports['5432'] }}/documents | |
| REGISTRY_RENDER_BIN: ${{ github.workspace }}/target/debug/registry-render | |
| run: cargo test --locked -p registry-documents --features postgres-test --test postgres_journey | |
| - name: Verify document events are captured on commit and delivered to observers | |
| env: | |
| DOCUMENTS_TEST_DATABASE_URL: postgresql://documents:documents_test@localhost:${{ job.services.postgres.ports['5432'] }}/documents | |
| run: cargo test --locked -p registry-documents --features postgres-test --test postgres_hooks | |
| adapter-contracts: | |
| name: Registry Adapter product contracts | |
| needs: [changes, rust-policy] | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.adapter_contracts == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| # The script formats, lints, and tests the adapter crates, holds the | |
| # generated schemas and the configuration conventions against their | |
| # generators, holds the Camel port table against the code, and checks | |
| # the example, its fixture replay, the source-shape fixtures, and the | |
| # bad-authoring corpus against the adapterctl binary it builds. All | |
| # of it compiles cold: CARGO_TARGET_DIR is set because the script | |
| # builds its own adapterctl there and refuses to guess a binary | |
| # without it. | |
| timeout-minutes: 40 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Cache Cargo registry | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 | |
| with: | |
| version: "0.11.16" | |
| - name: Registry Adapter contract consistency | |
| env: | |
| CARGO_TARGET_DIR: ${{ github.workspace }}/target | |
| ADAPTER_CONTRACTS_CLEAN_BETWEEN_LANES: "1" | |
| run: products/adapter/scripts/check-contracts.sh | |
| - name: Registry Adapter facade recovery runner | |
| run: products/adapter/scripts/test-facade-recovery-runner.sh | |
| adapter-postgres: | |
| name: Registry Adapter PostgreSQL and recovery suites | |
| needs: [changes, rust-policy] | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.adapter_contracts == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| # The scripts start their own disposable PostgreSQL containers: the | |
| # ingestion-job recovery suite and the live PostgreSQL source suite. | |
| # They are a separate job from the contract script so that each keeps | |
| # its own 40-minute budget and a timeout names the suite that ran long. | |
| timeout-minutes: 40 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Cache Cargo registry | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Registry Adapter ingestion-job PostgreSQL recovery | |
| env: | |
| CARGO_TARGET_DIR: ${{ github.workspace }}/target | |
| run: products/adapter/scripts/test-job-postgres.sh | |
| # The GovStack BReg suite starts `bregctl dev`, which pulls the pinned | |
| # ThunderID image on first use. Pulling it here, with retries, makes a | |
| # registry hiccup fail as this step instead of as a test. | |
| - name: Pull the pinned ThunderID image | |
| run: | | |
| image=$(jq -r .image crates/registry-thunderid-tooling/thunderid-version.json) | |
| for attempt in 1 2 3; do | |
| if docker pull --quiet "$image"; then | |
| exit 0 | |
| fi | |
| echo "::warning::ThunderID image pull attempt ${attempt} failed" | |
| sleep $((attempt * 15)) | |
| done | |
| echo "::error::the pinned ThunderID image could not be pulled after 3 attempts" | |
| exit 1 | |
| - name: Registry Adapter live PostgreSQL suites | |
| env: | |
| CARGO_TARGET_DIR: ${{ github.workspace }}/target | |
| run: products/adapter/scripts/test-postgres.sh | |
| coordinator-postgres: | |
| name: Coordinator PostgreSQL runtime | |
| needs: [changes, rust-policy] | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.coordinator == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 30 | |
| services: | |
| postgres: | |
| image: docker.io/library/postgres:17.11@sha256:67f41722b7a8cbdb868a44a4995c846eddfdc2973bccb291ce937dce88ad5675 | |
| env: | |
| POSTGRES_DB: coordinator | |
| POSTGRES_USER: coordinator | |
| POSTGRES_PASSWORD: coordinator_test | |
| options: >- | |
| --health-cmd "pg_isready -U coordinator -d coordinator" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| ports: | |
| - 5432/tcp | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Rust cache | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| # The suite composes with real Messaging and Scheduling runtimes, which | |
| # each need a database of their own beside the Coordinator's. | |
| - name: Prepare the product test databases | |
| env: | |
| PGHOST: 127.0.0.1 | |
| PGPORT: ${{ job.services.postgres.ports['5432'] }} | |
| PGUSER: coordinator | |
| PGPASSWORD: coordinator_test | |
| run: | | |
| createdb coordinator_messaging | |
| createdb coordinator_scheduling | |
| - name: Verify coordinator restart, fencing, and native product recovery | |
| env: | |
| COORDINATOR_TEST_DATABASE_URL: postgresql://coordinator:coordinator_test@127.0.0.1:${{ job.services.postgres.ports['5432'] }}/coordinator | |
| COORDINATOR_MESSAGING_TEST_DATABASE_URL: postgresql://coordinator:coordinator_test@127.0.0.1:${{ job.services.postgres.ports['5432'] }}/coordinator_messaging | |
| COORDINATOR_SCHEDULING_TEST_DATABASE_URL: postgresql://coordinator:coordinator_test@127.0.0.1:${{ job.services.postgres.ports['5432'] }}/coordinator_scheduling | |
| run: products/coordinator/scripts/test-postgres.sh | |
| messaging-smtp: | |
| name: Messaging SMTP provider | |
| needs: [changes, rust-policy] | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.messaging_postgres == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 20 | |
| services: | |
| mailpit: | |
| image: ghcr.io/axllent/mailpit:v1.31.2@sha256:74d609a42ec279aa63c6b4622a6fa9b5408d1ad5b1d76a1c4be40a265ce0863d | |
| options: >- | |
| --health-cmd "/mailpit readyz" | |
| --health-interval 5s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| ports: | |
| - 1025/tcp | |
| - 8025/tcp | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Rust cache | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Verify the SMTP provider against a real relay | |
| env: | |
| MESSAGING_SMTP_TEST_MAILPIT_SMTP: 127.0.0.1:${{ job.services.mailpit.ports['1025'] }} | |
| MESSAGING_SMTP_TEST_MAILPIT_API: http://127.0.0.1:${{ job.services.mailpit.ports['8025'] }} | |
| run: cargo test --locked -p registry-messaging --features smtp-test --test smtp_mailpit | |
| breg-contracts: | |
| name: Base Registry Engine product contracts (${{ matrix.lane }}) | |
| needs: changes | |
| if: needs.changes.outputs.breg_contracts == 'true' | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 30 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| # Review runs the validator and adopter-journeys lanes; the merge | |
| # queue, the nightly sweep and a ci:full pull request add the | |
| # parallel PostgreSQL shard lanes. | |
| lane: ${{ fromJSON(needs.changes.outputs.breg_contracts_lanes) }} | |
| services: | |
| postgres: | |
| # PostgreSQL 17 / PostGIS 3.5.2, verified 2026-08-31. Fresh test databases | |
| # remain extension-free unless a spatial test explicitly installs it. | |
| image: postgis/postgis@sha256:01a6a70e41e6c4467c8f55f6063555ed72db2d6662cd0d571040d42eadaeb6f6 | |
| env: | |
| POSTGRES_DB: breg | |
| POSTGRES_PASSWORD: breg_test | |
| POSTGRES_USER: breg | |
| options: >- | |
| --health-cmd "pg_isready -U breg -d breg" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| ports: | |
| - 5432/tcp | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Configure Base Registry Engine test environment | |
| env: | |
| DATABASE_PORT: ${{ job.services.postgres.ports['5432'] }} | |
| POSTGRES_CONTAINER_ID: ${{ job.services.postgres.id }} | |
| TLS_CA_PEM_PATH: ${{ runner.temp }}/breg-postgres-trusted-ca.pem | |
| run: | | |
| { | |
| echo "BREG_TEST_DATABASE_URL=postgresql://breg:breg_test@localhost:${DATABASE_PORT}/breg" | |
| echo "BREG_TEST_TLS_DATABASE_HOST=localhost" | |
| echo "BREG_TEST_TLS_DATABASE_URL=postgresql://breg:breg_test@localhost:${DATABASE_PORT}/breg" | |
| echo "BREG_TEST_TLS_HOSTNAME_MISMATCH_DATABASE_URL=postgresql://breg:breg_test@127.0.0.1:${DATABASE_PORT}/breg" | |
| echo "BREG_TEST_TLS_POSTGRES_CONTAINER_ID=${POSTGRES_CONTAINER_ID}" | |
| echo "BREG_TEST_TLS_CA_PEM_PATH=${TLS_CA_PEM_PATH}" | |
| } >> "${GITHUB_ENV}" | |
| - name: Cache Cargo registry | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Install uv | |
| if: matrix.lane != 'immediate-actions' | |
| uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 | |
| with: | |
| version: "0.11.16" | |
| - name: Base Registry Engine contract consistency | |
| if: matrix.lane == 'contracts' | |
| run: uv run --no-project --with PyYAML==6.0.2 products/breg/scripts/check-contracts.sh | |
| # No shard enables `schema` on registry-breg, so its schema-gated tests | |
| # run here, where check-contracts.sh has already built the dependencies | |
| # of this feature set. | |
| - name: Base Registry Engine schema-gated tests | |
| if: matrix.lane == 'contracts' | |
| run: cargo test --locked -p registry-breg --features runtime,tooling,schema --lib --test action_evidence_compiler --test proposal_hooks --test value_type_consistency | |
| - name: BReg client contract consistency | |
| if: matrix.lane == 'contracts' | |
| run: products/breg/scripts/check-client-contract.sh | |
| - name: Enforce the citizen gateway's delegated-agent boundary | |
| if: matrix.lane == 'contracts' | |
| run: products/breg/scripts/check-mcp-gateway-boundary.sh | |
| - name: Keep the citizen gateway and review page off the registry runtime | |
| if: matrix.lane == 'contracts' | |
| run: products/breg/scripts/check-service-dependencies.sh | |
| - name: Base Registry Engine PostgreSQL journeys | |
| if: startsWith(matrix.lane, 'postgres:') || matrix.lane == 'immediate-actions' | |
| env: | |
| BREG_POSTGRES_LANE: ${{ matrix.lane }} | |
| run: products/breg/scripts/test-postgres.sh --lane "$BREG_POSTGRES_LANE" | |
| # The fixture provisions its own databases and roles through the job's | |
| # BREG_TEST_DATABASE_URL. postgres-test enables its loopback plaintext | |
| # database. Each single-copy proof is pinned to one PostgreSQL shard so | |
| # it still executes exactly once while balancing shard wall time: the | |
| # first shard carries the Evidence proof's build, the second the citizen | |
| # journey, the third the worker and S3 runs. | |
| - name: Native citizen gateway and review authority journey | |
| if: matrix.lane == 'postgres:2/3' | |
| shell: bash | |
| env: | |
| BREG_BIN: ${{ github.workspace }}/target/debug/breg | |
| BREGCTL_BIN: ${{ github.workspace }}/target/debug/bregctl | |
| BREG_REVIEW_NATIVE_BIN: ${{ github.workspace }}/target/debug/breg-review | |
| run: | | |
| cargo build --locked -p registry-breg -p registry-bregctl -p registry-breg-review \ | |
| --features registry-breg/postgres-test --bin breg --bin bregctl --bin breg-review | |
| cargo test --locked -p registry-breg-mcp --test native_citizen \ | |
| -- --ignored --exact native_citizen_gateway_and_review_share_engine_owned_authority --test-threads=1 \ | |
| | tee "${RUNNER_TEMP}/breg-native-citizen.log" | |
| grep -q 'test result: ok\. 1 passed' "${RUNNER_TEMP}/breg-native-citizen.log" || { echo "::error::expected one passing native citizen authority journey"; exit 1; } | |
| - name: Native delegated staff MCP authority journey | |
| if: matrix.lane == 'postgres:2/3' | |
| shell: bash | |
| env: | |
| BREG_BIN: ${{ github.workspace }}/target/debug/breg | |
| BREGCTL_BIN: ${{ github.workspace }}/target/debug/bregctl | |
| CASEWORK_BIN: ${{ github.workspace }}/target/debug/casework | |
| CASEWORKCTL_BIN: ${{ github.workspace }}/target/debug/caseworkctl | |
| REGISTRY_STACK_FIXTURES_ROOT: ${{ github.workspace }} | |
| run: | | |
| set -euo pipefail | |
| export CASEWORK_MCP_TEST_DATABASE_URL="$BREG_TEST_DATABASE_URL" | |
| export TMPDIR="${RUNNER_TEMP}/native-staff-mcp" | |
| mkdir -p "$TMPDIR" | |
| chmod 700 "$TMPDIR" | |
| cargo build --locked -p registry-breg -p registry-bregctl -p registry-casework -p registry-caseworkctl \ | |
| --features registry-breg/postgres-test,registry-casework/postgres-test \ | |
| --bin breg --bin bregctl --bin casework --bin caseworkctl | |
| cargo test --locked -p registry-mcp --test native_casework \ | |
| -- --ignored --exact native_staff_gateway_preserves_delegated_read_authority --test-threads=1 \ | |
| | tee "${RUNNER_TEMP}/native-staff-mcp.log" | |
| grep -q 'test result: ok\. 1 passed' "${RUNNER_TEMP}/native-staff-mcp.log" || { echo "::error::expected one passing native staff authority journey"; exit 1; } | |
| # The native worker/store library and test-only startup configuration | |
| # need postgres-test; keep the production-feature variants in the runner. | |
| # External-issuer cases compile here and execute only in their opt-in runner. | |
| - name: Base Registry Engine PostgreSQL worker and startup tests | |
| if: matrix.lane == 'postgres:3/3' | |
| run: cargo test --locked -p registry-breg --features postgres-test,tooling,schema --lib --test startup_http --test runtime_config --test issuer_portability -- --test-threads=1 | |
| # The transactional harness uses its own roles over the initial local | |
| # connection. Run it before the TLS proof makes this service TLS-only. | |
| # Both steps share the contracts-journeys lane, which owns the | |
| # TLS-dependent adopter checks the validator lane does not run. | |
| - name: Base Registry Engine immediate Action transaction and recovery | |
| if: matrix.lane == 'contracts-journeys' | |
| run: products/breg/scripts/test-immediate-action-examples.sh | |
| - name: Base Registry Engine PostgreSQL TLS proof | |
| if: matrix.lane == 'contracts-journeys' | |
| run: products/breg/scripts/test-postgres-tls.sh | |
| - name: Public bregctl schema-test lifecycles | |
| if: matrix.lane == 'contracts-journeys' | |
| env: | |
| BREG_TEST_DATABASE_URL: ${{ env.BREG_TEST_TLS_DATABASE_URL }} | |
| SSL_CERT_FILE: ${{ env.BREG_TEST_TLS_CA_PEM_PATH }} | |
| run: cargo test --locked -p registry-bregctl --features wasm --test wasm_test_lifecycle --test publicschema_inline_value_lists -- --ignored --exact | |
| - name: Base Registry Engine real S3 attachment storage | |
| if: matrix.lane == 'postgres:3/3' | |
| run: bash products/breg/scripts/test-attachment-s3.sh | |
| - name: Base Registry Engine clean-checkout adopter workflow | |
| if: matrix.lane == 'contracts-journeys' | |
| run: products/breg/scripts/test-adopter-workflow.sh | |
| - name: Base Registry Engine statistical dataset workflow | |
| if: matrix.lane == 'contracts-journeys' | |
| env: | |
| BREG_SKIP_BUILD: "1" | |
| run: products/breg/scripts/test-statistics-workflow.sh | |
| - name: Base Registry Engine staging-to-production promotion | |
| if: matrix.lane == 'contracts-journeys' | |
| env: | |
| BREG_SKIP_BUILD: "1" | |
| run: products/breg/scripts/test-promotion.sh | |
| - name: Base Registry Engine logical backup and restore | |
| if: matrix.lane == 'contracts-journeys' | |
| env: | |
| BREG_SKIP_BUILD: "1" | |
| run: products/breg/scripts/test-backup-restore.sh | |
| - name: Base Registry Engine generic quickstart | |
| if: matrix.lane == 'contracts-journeys' | |
| run: products/breg/quickstart/run.sh --smoke | |
| - name: Base Registry Engine spatial quickstart | |
| if: matrix.lane == 'contracts-journeys' | |
| run: products/breg/quickstart/run.sh --spatial --smoke | |
| breg-postgres-18: | |
| name: Base Registry Engine PostgreSQL 18 portability | |
| needs: changes | |
| if: needs.changes.outputs.breg_contracts == 'true' | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Check optional Docker Hub credentials | |
| id: dockerhub | |
| if: github.event_name != 'pull_request' && (github.event_name != 'workflow_dispatch' || github.ref == 'refs/heads/main') | |
| env: | |
| DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} | |
| DOCKERHUB_READ_TOKEN: ${{ secrets.DOCKERHUB_READ_TOKEN }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| if [[ -z "${DOCKERHUB_USERNAME}" && -z "${DOCKERHUB_READ_TOKEN}" ]]; then | |
| printf 'configured=false\n' >> "${GITHUB_OUTPUT}" | |
| elif [[ -z "${DOCKERHUB_USERNAME}" || -z "${DOCKERHUB_READ_TOKEN}" ]]; then | |
| echo 'Docker Hub credentials must configure both username and read token.' >&2 | |
| exit 1 | |
| else | |
| printf 'configured=true\n' >> "${GITHUB_OUTPUT}" | |
| fi | |
| - name: Log in to Docker Hub for the PostgreSQL 18 image | |
| if: github.event_name != 'pull_request' && (github.event_name != 'workflow_dispatch' || github.ref == 'refs/heads/main') && steps.dockerhub.outputs.configured == 'true' | |
| uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # v4.7.0 | |
| with: | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_READ_TOKEN }} | |
| - name: Start PostgreSQL 18 | |
| id: postgres | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| image='docker.io/library/postgres:18.4@sha256:a02db8cac496f15b094798a38254f14d6e00741f709360e5e00bb6668ea31636' | |
| container_name="breg-postgres-18-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" | |
| container_id="$( | |
| docker run --detach \ | |
| --name "${container_name}" \ | |
| --label org.registrystack.ci.postgres-service=true \ | |
| --env POSTGRES_DB=breg \ | |
| --env POSTGRES_USER=breg \ | |
| --env POSTGRES_PASSWORD=breg_test \ | |
| --health-cmd 'pg_isready -U breg -d breg' \ | |
| --health-interval 10s \ | |
| --health-timeout 5s \ | |
| --health-retries 5 \ | |
| --publish 127.0.0.1::5432 \ | |
| "${image}" | |
| )" | |
| printf 'container_id=%s\n' "${container_id}" >> "${GITHUB_OUTPUT}" | |
| for _ in $(seq 1 30); do | |
| health="$(docker inspect --format '{{.State.Health.Status}}' "${container_id}")" | |
| if [[ "${health}" == healthy ]]; then | |
| break | |
| fi | |
| if [[ "${health}" == unhealthy ]]; then | |
| docker logs "${container_id}" | |
| exit 1 | |
| fi | |
| sleep 2 | |
| done | |
| if [[ "$(docker inspect --format '{{.State.Health.Status}}' "${container_id}")" != healthy ]]; then | |
| docker logs "${container_id}" | |
| exit 1 | |
| fi | |
| endpoint="$(docker port "${container_id}" 5432/tcp)" | |
| port="${endpoint##*:}" | |
| [[ "${port}" =~ ^[0-9]+$ ]] | |
| printf 'port=%s\n' "${port}" >> "${GITHUB_OUTPUT}" | |
| - name: Cache Cargo registry | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Verify cross-major schema fingerprint and collation | |
| env: | |
| BREG_TEST_DATABASE_URL: postgresql://breg:breg_test@localhost:${{ steps.postgres.outputs.port }}/breg | |
| run: | | |
| cargo test --locked -p registry-breg --features postgres-test,tooling \ | |
| --test schema_fingerprint_rehearsal --no-fail-fast -- --test-threads=1 | |
| - name: Stop PostgreSQL 18 | |
| if: always() && steps.postgres.outputs.container_id != '' | |
| env: | |
| CONTAINER_ID: ${{ steps.postgres.outputs.container_id }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| label="$( | |
| docker inspect \ | |
| --format '{{ index .Config.Labels "org.registrystack.ci.postgres-service" }}' \ | |
| "${CONTAINER_ID}" | |
| )" | |
| [[ "${label}" == true ]] | |
| docker rm --force "${CONTAINER_ID}" | |
| breg-wasm: | |
| # The WASM action-handler executor runs under the `wasm` feature, which | |
| # registry-breg and registry-bregctl carry by default. This lane runs | |
| # what the ordinary Rust shards do not: the platform executor's wat | |
| # suite (both execution backends), the admission, runtime, and parity | |
| # suites in one explicit place, the PostgreSQL handler journeys against | |
| # a disposable PostGIS database, and the no-default refusal suite that | |
| # keeps `breg.action.handler-wasm-build-unsupported` and | |
| # `breg.hook.handler-wasm-build-unsupported` proven. | |
| name: Base Registry Engine WASM executor | |
| needs: changes | |
| if: needs.changes.outputs.breg_integration == 'true' | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 30 | |
| services: | |
| postgres: | |
| # PostgreSQL 17 / PostGIS 3.5.2, verified 2026-08-31. Fresh test databases | |
| # remain extension-free unless a spatial test explicitly installs it. | |
| image: postgis/postgis@sha256:01a6a70e41e6c4467c8f55f6063555ed72db2d6662cd0d571040d42eadaeb6f6 | |
| env: | |
| POSTGRES_DB: breg | |
| POSTGRES_PASSWORD: breg_test | |
| POSTGRES_USER: breg | |
| options: >- | |
| --health-cmd "pg_isready -U breg -d breg" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| ports: | |
| - 5432/tcp | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Cache Cargo registry | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Platform WASM executor wat suite | |
| run: cargo test --locked -p registry-platform-script --features wasm --test wasm_executor_wat | |
| - name: Base Registry Engine WASM admission, runtime, and parity suites | |
| run: cargo test --locked -p registry-breg --features runtime,wasm --lib --test wasm_handler_admission | |
| - name: Base Registry Engine WASM refusal suite | |
| run: cargo test --locked -p registry-breg --no-default-features --features runtime,tooling --test immediate_action_compiler --test hook_declaration | |
| - name: Base Registry Engine tooling WASM suites | |
| run: cargo test --locked -p registry-bregctl --features wasm | |
| - name: Base Registry Engine WASM handler PostgreSQL journeys | |
| env: | |
| BREG_TEST_DATABASE_URL: postgresql://breg:breg_test@localhost:${{ job.services.postgres.ports['5432'] }}/breg | |
| run: cargo test --locked -p registry-breg --features postgres-test,tooling,wasm --test postgres_wasm_action_handlers | |
| identifiers: | |
| name: Public identifier catalog | |
| needs: | |
| - changes | |
| - rust-policy | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.identifiers == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Cache Cargo registry | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # 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 | |
| - name: Check Registry Record profile artifacts | |
| run: products/registry-record/scripts/check.sh | |
| config-conformance: | |
| name: Runtime configuration conformance | |
| needs: | |
| - changes | |
| - rust-policy | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.config_conformance == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| # The check commands and the BReg citizen service schema check compile | |
| # their crates cold. | |
| timeout-minutes: 40 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| # The conventions lint compares the exceptions register with the | |
| # event baseline (CFG-CHANGE-5), so the history has to be present. | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| submodules: false | |
| - name: Cache Cargo registry | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Test runtime configuration conformance gate | |
| run: python3 -m unittest products/platform/scripts/test_check_config_conformance.py | |
| - name: Check runtime configuration conformance | |
| run: products/platform/scripts/check-config-conformance.py --check-generated | |
| - name: Check Coordinator configuration schemas | |
| run: products/coordinator/scripts/check-schemas.sh | |
| - name: Check BReg citizen service runtime schemas | |
| run: cargo test --locked -p registry-breg-mcp -p registry-breg-review --features registry-breg-mcp/schema,registry-breg-review/schema --lib schema::tests | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 | |
| with: | |
| version: "0.11.16" | |
| - name: Test configuration conventions lint | |
| run: uv run --no-project --with PyYAML==6.0.2 python -m unittest products/platform/scripts/test_check_config_conventions.py | |
| - name: Check configuration conventions | |
| env: | |
| # The event baseline the changes job resolved; the archive check | |
| # compares against the same commit. | |
| CONVENTIONS_BASE_REF: ${{ needs.changes.outputs.archive_base_ref }} | |
| CONVENTIONS_COMPARISON_REQUIRED: ${{ needs.changes.outputs.archive_comparison_required }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| lint=(uv run --no-project --with PyYAML==6.0.2 python products/platform/scripts/check-config-conventions.py) | |
| if [[ "${CONVENTIONS_COMPARISON_REQUIRED}" == "true" ]]; then | |
| if [[ -z "${CONVENTIONS_BASE_REF}" ]]; then | |
| echo "Cannot check CFG-CHANGE-5: the event baseline is unavailable." >&2 | |
| exit 1 | |
| fi | |
| register=products/platform/config-conventions-exceptions.yaml | |
| if git cat-file -e "${CONVENTIONS_BASE_REF}:${register}" 2>/dev/null; then | |
| "${lint[@]}" --base "${CONVENTIONS_BASE_REF}" | |
| else | |
| # A baseline that predates the register (the change that | |
| # introduces it) has nothing to compare with, and the lint | |
| # refuses an explicit --base without the register. | |
| echo "::notice::CFG-CHANGE-5 not checked: the event baseline predates ${register}." | |
| "${lint[@]}" | |
| fi | |
| elif [[ "${CONVENTIONS_COMPARISON_REQUIRED}" == "false" ]]; then | |
| # A scheduled sweep has no change baseline; the lint compares the | |
| # register with its merge base with origin/main. | |
| "${lint[@]}" | |
| else | |
| echo "The event comparison policy is unavailable." >&2 | |
| exit 1 | |
| fi | |
| # Every rule the convention declares has one Enforcement summary | |
| # row, and the gates that row names exist. | |
| "${lint[@]}" --rule-coverage | |
| - name: Test configuration conformance corpus runner | |
| run: uv run --no-project --with PyYAML==6.0.2 python -m unittest products/platform/scripts/test_run_config_conformance.py | |
| # The binaries the registered `check` commands name; a cell whose | |
| # program is missing from the directory fails. | |
| - name: Build configuration check commands | |
| run: >- | |
| cargo build --locked --bins | |
| -p registry-bregctl -p registry-caseworkctl -p registry-schedulingctl | |
| -p registry-coordinator | |
| -p registry-messagingctl -p registry-discoveryctl -p registry-render | |
| -p registry-documentsctl -p registry-adapterctl | |
| -p registry-evidence -p registry-evidencectl -p registry-manifest-cli | |
| -p registry-breg-mcp -p registry-breg-review -p registry-evidence-oid4vci -p registry-mcp | |
| -p registry-evidence-oid4vp | |
| # The launcher is built alone, as the release builds it, so feature | |
| # unification with the product tools cannot hide a missing feature or | |
| # turn on the session code. | |
| - name: Build the launcher check command | |
| run: cargo build --locked -p registry-rstack | |
| - name: Run configuration conformance corpus | |
| run: products/platform/scripts/run-config-conformance.sh --strict --bin-dir target/debug | |
| rust-result: | |
| name: Rust workspace | |
| if: always() | |
| needs: | |
| - changes | |
| - rust-policy | |
| - rust-quality | |
| - rust-tests | |
| - discovery-contracts | |
| - evidence-contracts | |
| - evidence-postgres | |
| - breg-contracts | |
| - breg-postgres-18 | |
| - breg-wasm | |
| - identifiers | |
| - casework-postgres | |
| - scheduling-postgres | |
| - scheduling-contracts | |
| - messaging-postgres | |
| - messaging-contracts | |
| - messaging-smtp | |
| - documents-contracts | |
| - documents-postgres | |
| - adapter-contracts | |
| - adapter-postgres | |
| - coordinator-postgres | |
| - config-conformance | |
| runs-on: ubuntu-slim | |
| timeout-minutes: 5 | |
| 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 | |
| - rust-policy | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.release_tool == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| fetch-depth: 0 | |
| submodules: false | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 | |
| with: | |
| version: "0.11.16" | |
| - name: Test release helper | |
| run: uv run --no-project --with PyYAML==6.0.2 python3 -m unittest release/scripts/test_registry_release.py | |
| - name: Test release scheduling | |
| run: uv run --no-project --with PyYAML==6.0.2 python3 -m unittest release/scripts/test_release_ci_overlap.py | |
| - name: Test release docs scheduling | |
| run: uv run --no-project --with PyYAML==6.0.2 python3 -m unittest release/scripts/test_release_docs_scheduling.py | |
| - name: Test release-note drafting | |
| run: uv run --no-project --with PyYAML==6.0.2 python3 -m unittest release/scripts/test_release_notes.py | |
| - name: Test release planning commands | |
| run: uv run --no-project --with PyYAML==6.0.2 python3 -m unittest release/scripts/test_registry_release_plans.py | |
| - name: Test documentation release preparation | |
| run: uv run --no-project --with PyYAML==6.0.2 python3 -m unittest release/scripts/test_prepare_release_docs.py | |
| - name: Test version-selected release roster | |
| run: python3 -m unittest release/scripts/test_release_roster.py | |
| - name: Test supporting release image packaging | |
| run: python3 -m unittest release/scripts/test_release_supporting_images.py | |
| - name: Test release candidate manifest and promotion verifier | |
| run: python3 -m unittest release/scripts/test_release_candidate.py | |
| - name: Test rstack release component inventory | |
| run: python3 -m unittest release/scripts/test_rstack_components.py | |
| - name: Test release unit ownership | |
| run: python3 -m unittest release/scripts/test_release_units.py | |
| - name: Test scoped candidate contracts | |
| run: uv run --no-project --with jsonschema==4.25.1 python3 -m unittest release/scripts/test_release_candidate_v3.py | |
| - name: Test distribution component selection | |
| run: python3 -m unittest release/scripts/test_release_distribution.py | |
| - name: Test unit release pipeline | |
| run: python3 -m unittest release/scripts/test_unit_release_pipeline.py | |
| - name: Test Discovery installer | |
| run: python3 -m unittest release/scripts/test_discovery_install.py | |
| - name: Test installed Discovery and SDK smoke | |
| run: python3 -m unittest release/scripts/test_smoke_discovery_distribution.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 unified Node client facade sync | |
| run: python3 -m unittest release/scripts/test_sync_registry_client_node.py | |
| - name: Test unified Python wheel assembly | |
| run: python3 -m unittest release/scripts/test_assemble_registry_client_wheel.py | |
| - name: Test local client package assembly | |
| run: python3 -m unittest release/scripts/test_assemble_registry_client_packages.py | |
| - name: Test client package smoke checks | |
| run: python3 -m unittest release/scripts/test_smoke_registry_client_package.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: uv run --no-project --with PyYAML==6.0.2 python3 -m unittest release/scripts/test_release_rehearsal.py | |
| - name: Test release upgrade rehearsal | |
| run: uv run --no-project --with PyYAML==6.0.2 python3 -m unittest release/scripts/test_rehearse_upgrade.py | |
| - name: Test rehearsal advisory evidence collector | |
| run: python3 -m unittest release/scripts/test_collect_rehearsal_advisory_evidence.py | |
| - name: Test image ELF exposure report | |
| run: python3 -m unittest release/scripts/test_image_exposure.py | |
| - name: Test advisory baseline renewal | |
| run: uv run --no-project --with PyYAML==6.0.2 python3 -m unittest release/scripts/test_advisory_renewal.py | |
| - name: Test Linux Node client release build helper | |
| run: python3 -m unittest release/scripts/test_build_linux_node_client.py | |
| - name: Test Linux Python client release build helper | |
| run: python3 -m unittest release/scripts/test_build_linux_python_client.py | |
| - name: Test Zig glibc compiler wrapper | |
| run: python3 -m unittest release/scripts/test_zig_glibc_compiler.py | |
| - name: Test canonical release binary shard merge | |
| run: python3 -m unittest release/scripts/test_merge_release_binary_shards.py | |
| - name: Test native release platform build and merge | |
| run: python3 -m unittest release/scripts/test_release_native_platform.py | |
| - name: Test macOS FIPS packaging | |
| run: python3 -m unittest release/scripts/test_macos_fips_packaging.py | |
| - name: Test macOS bundle installers | |
| run: python3 -m unittest release/scripts/test_macos_installers.py | |
| - name: Test generated product installers | |
| run: python3 -m unittest release/scripts/test_additional_installers.py | |
| - name: Test additional Linux ARM binary builds | |
| run: python3 -m unittest release/scripts/test_additional_platform_binaries.py | |
| - name: Test nightly channel and immutable publication | |
| run: python3 -m unittest release/scripts/test_nightly_release.py | |
| - name: Test nightly installer resolution | |
| run: python3 -m unittest release/scripts/test_nightly_installers.py | |
| - name: Test nightly workflow trust boundaries | |
| run: uv run --no-project --with PyYAML==6.0.2 python3 -m unittest release/scripts/test_nightly_release_workflow.py | |
| - name: Test release workflow structure | |
| run: uv run --no-project --with PyYAML==6.0.2 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@f87e5991a6d7451dcb8d9637bfbc97413f497069 | |
| with: | |
| version: v0.33.0 | |
| driver-opts: image=ghcr.io/registrystack/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: uv run --no-project --with PyYAML==6.0.2 python3 -m unittest release/scripts/test_check_gates_inventory.py | |
| - name: Validate release manifest | |
| run: uv run --no-project --with PyYAML==6.0.2 python3 release/scripts/registry-release validate-current | |
| - name: Validate release docsets | |
| run: uv run --no-project --with PyYAML==6.0.2 python3 release/scripts/registry-release validate-docsets | |
| - name: Audit import map | |
| run: uv run --no-project --with PyYAML==6.0.2 python3 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-slim | |
| timeout-minutes: 5 | |
| 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 | |
| - rust-policy | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.release_source_proof == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| fetch-depth: 0 | |
| submodules: false | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 | |
| with: | |
| version: "0.11.16" | |
| - name: Check monorepo source model | |
| run: uv run --no-project --with PyYAML==6.0.2 release/scripts/check-release-source-model.sh | |
| - name: Test source model checker | |
| run: uv run --no-project --with PyYAML==6.0.2 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-slim | |
| timeout-minutes: 5 | |
| 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@949feb2413d6458794dcd2491c4babbbce0c15c1 | |
| with: | |
| node-version: 24.11.0 | |
| cache: npm | |
| cache-dependency-path: docs/site/package-lock.json | |
| - name: Cache Cargo registry | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Install docs dependencies | |
| working-directory: docs/site | |
| # The tutorial runner needs only pure-JS packages. Skipping install | |
| # scripts keeps the Vale postinstall's unauthenticated GitHub | |
| # download, which shared runner addresses get refused on, out of | |
| # this job. | |
| run: npm ci --ignore-scripts | |
| - name: Test the tutorial runner | |
| working-directory: docs/site | |
| run: npm run test:tutorial:runner | |
| - 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 build --locked \ | |
| -p registry-evidence -p registry-evidencectl \ | |
| -p registry-evidence-oid4vci -p registry-rstack --bins | |
| cargo test --locked \ | |
| -p registry-evidence-oid4vci --test inji_interoperability --no-run | |
| test_binary=$(find target/debug/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/debug/inji-oid4vci-interop-test | |
| - name: Assemble the client package the application tutorial imports | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| # The tutorial installs the maintained client package, so the replay | |
| # imports that same package, assembled from this commit. maturin gets | |
| # the pinned release build environment. The CI profile exercises the | |
| # same six-binding assembly and installed facade without release LTO. | |
| # Production optimization remains covered by release recipe checks. | |
| 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" | |
| out_dir="${GITHUB_WORKSPACE}/target/evidence-tutorial-client" | |
| python3 release/scripts/assemble-registry-client-packages.py \ | |
| --artifacts python \ | |
| --include-casework \ | |
| --include-messaging \ | |
| --include-scheduling \ | |
| --include-render \ | |
| --include-coordinator \ | |
| --python-profile ci \ | |
| --output-dir "${out_dir}" \ | |
| --work-dir "${RUNNER_TEMP}/client-assembly" \ | |
| --maturin "${RUNNER_TEMP}/maturin/bin/maturin" \ | |
| --zig-python "${RUNNER_TEMP}/maturin/bin/python" | |
| wheel="$(find "${out_dir}" -maxdepth 1 -name 'registry_stack_client-*.whl')" | |
| if [[ "$(printf '%s\n' "${wheel}" | wc -l)" -ne 1 || ! -f "${wheel}" ]]; then | |
| echo "expected exactly one assembled client wheel in ${out_dir}" >&2 | |
| find "${out_dir}" -maxdepth 1 -name '*.whl' >&2 | |
| exit 1 | |
| fi | |
| # Prove installer metadata and native facade loading from this exact | |
| # wheel. The application tutorial separately exercises requests. | |
| python3 -m venv "${RUNNER_TEMP}/client-install-smoke" | |
| "${RUNNER_TEMP}/client-install-smoke/bin/pip" install \ | |
| --no-index --no-deps "${wheel}" | |
| "${RUNNER_TEMP}/client-install-smoke/bin/python" -I \ | |
| release/scripts/smoke-registry-client-package.py | |
| printf 'REGISTRY_CLIENT_PY_WHEEL=%s\n' "${wheel}" >>"${GITHUB_ENV}" | |
| - name: Test the exact local Evidence lifecycle | |
| shell: bash | |
| env: | |
| EVIDENCE_BIN: ${{ github.workspace }}/target/debug/evidence | |
| run: | | |
| set -euo pipefail | |
| cargo test --locked \ | |
| -p registry-evidencectl --test dev_lifecycle -- \ | |
| --ignored --test-threads=1 | |
| # The generated SQLite starter target must pass the offline target | |
| # check, which runs the binding checks of the runtime built above. | |
| cargo test --locked -p registry-evidencectl --test scaffold \ | |
| the_generated_sqlite_starter_target_binds_its_extract_profile \ | |
| -- --ignored --exact \ | |
| | tee "${RUNNER_TEMP}/evidence-sqlite-starter-target.log" | |
| grep -q 'test result: ok\. 1 passed' "${RUNNER_TEMP}/evidence-sqlite-starter-target.log" || { echo "::error::expected exactly one passing test for the_generated_sqlite_starter_target_binds_its_extract_profile"; exit 1; } | |
| # A fresh starter must package against the local target made for it, | |
| # once it binds its published extract. | |
| cargo test --locked -p registry-evidencectl --test scaffold \ | |
| a_fresh_starter_packages_against_its_new_local_target \ | |
| -- --ignored --exact \ | |
| | tee "${RUNNER_TEMP}/evidence-starter-package.log" | |
| grep -q 'test result: ok\. 1 passed' "${RUNNER_TEMP}/evidence-starter-package.log" || { echo "::error::expected exactly one passing test for a_fresh_starter_packages_against_its_new_local_target"; exit 1; } | |
| # Current authoring checks are offline. Fixture evaluation is a | |
| # separate compiled-target proof against the runtime built above. | |
| # Exact filters and one-pass guards refuse a renamed empty proof. | |
| cargo test --locked -p registry-evidencectl --test production_handoff \ | |
| offline_project_check_needs_no_disposable_signing_state \ | |
| -- --ignored --exact \ | |
| | tee "${RUNNER_TEMP}/evidence-authoring-check.log" | |
| grep -q 'test result: ok\. 1 passed' "${RUNNER_TEMP}/evidence-authoring-check.log" || { echo "::error::expected exactly one passing test for offline_project_check_needs_no_disposable_signing_state"; exit 1; } | |
| cargo test --locked -p registry-evidencectl --test production_handoff \ | |
| production_build_checks_and_evaluates_every_neutral_authoring_shape \ | |
| -- --ignored --exact \ | |
| | tee "${RUNNER_TEMP}/evidence-fixture-evaluation.log" | |
| grep -q 'test result: ok\. 1 passed' "${RUNNER_TEMP}/evidence-fixture-evaluation.log" || { echo "::error::expected exactly one passing test for production_build_checks_and_evaluates_every_neutral_authoring_shape"; exit 1; } | |
| cargo test --locked -p registry-evidencectl --test source_recipes \ | |
| curated_source_recipes_import_check_and_run_the_existing_evaluator \ | |
| -- --ignored --exact \ | |
| | tee "${RUNNER_TEMP}/evidence-source-recipes.log" | |
| grep -q 'test result: ok\. 1 passed' "${RUNNER_TEMP}/evidence-source-recipes.log" || { echo "::error::expected exactly one passing test for curated_source_recipes_import_check_and_run_the_existing_evaluator"; exit 1; } | |
| - name: Test the public certificate check example | |
| shell: bash | |
| env: | |
| EVIDENCE_BIN: ${{ github.workspace }}/target/debug/evidence | |
| run: | | |
| set -euo pipefail | |
| cargo test --locked -p registry-evidencectl --test public_check \ | |
| -- --ignored --exact the_packaged_example_answers_a_hit_and_an_identical_miss_and_audits_neither_subject \ | |
| | tee "${RUNNER_TEMP}/evidence-public-check.log" | |
| grep -q 'test result: ok\. 1 passed' "${RUNNER_TEMP}/evidence-public-check.log" || { echo "::error::expected exactly one passing test for the_packaged_example_answers_a_hit_and_an_identical_miss_and_audits_neither_subject"; exit 1; } | |
| node --test products/evidence/examples/public-check/page/check.test.mjs | |
| - name: Test the composed wallet presentation journey | |
| shell: bash | |
| env: | |
| EVIDENCE_BIN: ${{ github.workspace }}/target/debug/evidence | |
| EVIDENCECTL_BIN: ${{ github.workspace }}/target/debug/evidencectl | |
| run: | | |
| set -euo pipefail | |
| cargo test --locked -p registry-evidence-oid4vp --test evidence_journey \ | |
| a_presented_credential_becomes_a_verified_assertion \ | |
| -- --ignored --exact \ | |
| | tee "${RUNNER_TEMP}/evidence-wallet-journey.log" | |
| grep -q 'test result: ok\. 1 passed' "${RUNNER_TEMP}/evidence-wallet-journey.log" || { echo "::error::expected exactly one passing test for a_presented_credential_becomes_a_verified_assertion"; exit 1; } | |
| cargo test --locked -p registry-evidence-oid4vp --test device_run \ | |
| a_simulated_wallet_completes_the_device_run_harness \ | |
| -- --ignored --exact \ | |
| | tee "${RUNNER_TEMP}/evidence-wallet-device-run.log" | |
| grep -q 'test result: ok\. 1 passed' "${RUNNER_TEMP}/evidence-wallet-device-run.log" || { echo "::error::expected exactly one passing test for a_simulated_wallet_completes_the_device_run_harness"; exit 1; } | |
| - name: Execute the Evidence tutorials with the stock issuer | |
| shell: bash | |
| env: | |
| RSTACK_BIN: ${{ github.workspace }}/target/debug/rstack | |
| EVIDENCE_BIN: ${{ github.workspace }}/target/debug/evidence | |
| EVIDENCECTL_BIN: ${{ github.workspace }}/target/debug/evidencectl | |
| EVIDENCE_OID4VCI_BIN: ${{ github.workspace }}/target/debug/evidence-oid4vci | |
| EVIDENCE_OID4VCI_INTEROP_TEST_BIN: ${{ github.workspace }}/target/debug/inji-oid4vci-interop-test | |
| run: node docs/site/scripts/run-tutorial.mjs --gate evidence | |
| breg-tutorial: | |
| name: Base Registry Engine tutorial from source (${{ matrix.shard }}) | |
| needs: | |
| - changes | |
| - rust-policy | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.breg_tutorial == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 30 | |
| strategy: | |
| fail-fast: false | |
| # The gate's journeys are independent, so two shards replay them in | |
| # parallel; the runner's round-robin split covers every journey exactly | |
| # once across the shards. Single-copy checks pin to one shard. | |
| matrix: | |
| shard: ["1/2", "2/2"] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Setup Node | |
| uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 | |
| with: | |
| node-version: 24.11.0 | |
| cache: npm | |
| cache-dependency-path: docs/site/package-lock.json | |
| - name: Cache Cargo registry | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 | |
| with: | |
| version: "0.11.16" | |
| - name: Install docs dependencies | |
| working-directory: docs/site | |
| # The tutorial runner needs only pure-JS packages. Skipping install | |
| # scripts keeps the Vale postinstall's unauthenticated GitHub | |
| # download, which shared runner addresses get refused on, out of | |
| # this job. | |
| run: npm ci --ignore-scripts | |
| - name: Test the tutorial runner | |
| if: matrix.shard == '1/2' | |
| working-directory: docs/site | |
| run: npm run test:tutorial:runner | |
| - name: Check tutorial command drift | |
| if: matrix.shard == '1/2' | |
| working-directory: docs/site | |
| run: npm run check:tutorial:breg:dry-run | |
| - name: Build the Base Registry Engine toolset under test | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| # The client tutorial installs the client packages at the version | |
| # `breg --version` reports, and the runner assembles them at the | |
| # workspace version, so the binaries are built marked with its | |
| # release tag. GITHUB_ENV keeps the marker for every later step, so | |
| # no later cargo command rebuilds them unmarked. | |
| tag="$(node --input-type=module -e "import { workspaceReleaseTag } from './docs/site/scripts/tutorial-runner/toolsets.mjs'; console.log(workspaceReleaseTag('.'))")" | |
| printf 'REGISTRY_RELEASE_TAG=%s\n' "${tag}" >> "${GITHUB_ENV}" | |
| REGISTRY_RELEASE_TAG="${tag}" cargo build --locked \ | |
| -p registry-breg --features registry-breg/runtime \ | |
| -p registry-bregctl -p registry-rstack --bins | |
| - name: Verify native retained development lifecycle | |
| if: matrix.shard == '2/2' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| # Each retained lifecycle owns PostgreSQL, ThunderID and BREG. | |
| # Run complete sessions serially on the bounded CI runner. | |
| cargo test --locked -p registry-bregctl \ | |
| --test dev_lifecycle -- --ignored --test-threads=1 | |
| - name: Verify retained example recovery after process exit | |
| if: matrix.shard == '2/2' | |
| # An inexact name filter that selects nothing still exits 0, so the | |
| # step names each test exactly and fails unless it reports one pass. | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| for test in \ | |
| dev::examples::tests::native_create_recovers_after_process_exit_without_duplicate_records \ | |
| dev::examples::tests::native_invoke_recovers_original_conditions_after_restart; do | |
| cargo test --locked -p registry-bregctl --lib \ | |
| "$test" -- --ignored --exact \ | |
| | tee "${RUNNER_TEMP}/breg-example-recovery-${test}.log" | |
| grep -q 'test result: ok\. 1 passed' "${RUNNER_TEMP}/breg-example-recovery-${test}.log" || { echo "::error::expected exactly one passing test for ${test}"; exit 1; } | |
| done | |
| - name: Execute the Base Registry Engine tutorials from a reader directory | |
| shell: bash | |
| env: | |
| RSTACK_BIN: ${{ github.workspace }}/target/debug/rstack | |
| BREG_BIN: ${{ github.workspace }}/target/debug/breg | |
| BREGCTL_BIN: ${{ github.workspace }}/target/debug/bregctl | |
| BREG_TUTORIAL_SHARD: ${{ matrix.shard }} | |
| run: | | |
| set -euo pipefail | |
| # This replay does not run in a clean read-only container the way the | |
| # Evidence one does: `bregctl dev` runs PostgreSQL in a disposable | |
| # container of its own, which the runner stops when the journey ends. | |
| node docs/site/scripts/run-tutorial.mjs --gate breg --shard "$BREG_TUTORIAL_SHARD" | |
| casework-tutorial: | |
| name: Registry Casework native review journeys | |
| needs: | |
| - changes | |
| - rust-policy | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.casework_tutorial == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Setup Node | |
| uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 | |
| with: | |
| node-version: 24.11.0 | |
| cache: npm | |
| cache-dependency-path: | | |
| crates/registry-casework-client-node/package-lock.json | |
| docs/site/package-lock.json | |
| - name: Cache Cargo registry | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Execute the canonical Casework developer journey | |
| # The maintained submitted-review journey owns its disposable Docker | |
| # database and verifies public binaries plus Rust/Node/Python facades. | |
| run: products/casework/scripts/check-review-journeys.sh | |
| - name: Install docs dependencies | |
| working-directory: docs/site | |
| # The tutorial runner needs only pure-JS packages. Skipping install | |
| # scripts keeps the Vale postinstall's unauthenticated GitHub | |
| # download, which shared runner addresses get refused on, out of | |
| # this job. | |
| run: npm ci --ignore-scripts | |
| - name: Test the tutorial runner | |
| working-directory: docs/site | |
| run: npm run test:tutorial:runner | |
| - name: Check tutorial command drift | |
| working-directory: docs/site | |
| run: npm run check:tutorial:casework:dry-run | |
| - name: Build the Registry Casework toolset under test | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| cargo build --locked \ | |
| -p registry-casework -p registry-caseworkctl \ | |
| -p registry-breg --features registry-breg/runtime \ | |
| -p registry-bregctl -p registry-rstack --bins | |
| - name: Install native PostgreSQL 18 and PostGIS for project development | |
| # The Ubuntu runner's PostgreSQL 16 is below BReg's minimum. | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| # Use the Ubuntu archive if the runner's Azure mirror cannot resolve. | |
| if [[ -f /etc/apt/apt-mirrors.txt ]] && ! timeout 10 getent ahosts azure.archive.ubuntu.com >/dev/null; then | |
| mirror="$(bash .github/scripts/select-ubuntu-archive.sh)" | |
| printf '%s\n' "$mirror" | sudo tee /etc/apt/apt-mirrors.txt >/dev/null | |
| fi | |
| sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y | |
| sudo env DEBIAN_FRONTEND=noninteractive apt-get install --yes --no-install-recommends postgresql-18 postgresql-18-postgis-3 | |
| /usr/lib/postgresql/18/bin/postgres --version | |
| - name: Verify the combined licensing development run with native PostgreSQL | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| cargo build --locked -p registry-rstack | |
| python3 products/platform/scripts/test-rstack-dev.py \ | |
| --bin-dir "${GITHUB_WORKSPACE}/target/debug" \ | |
| --postgres-bin-dir /usr/lib/postgresql/18/bin \ | |
| --scratch-parent "${RUNNER_TEMP}" \ | |
| --spatial | |
| - name: Execute the Registry Casework tutorials from a reader directory | |
| shell: bash | |
| env: | |
| RSTACK_BIN: ${{ github.workspace }}/target/debug/rstack | |
| CASEWORK_BIN: ${{ github.workspace }}/target/debug/casework | |
| CASEWORKCTL_BIN: ${{ github.workspace }}/target/debug/caseworkctl | |
| BREG_BIN: ${{ github.workspace }}/target/debug/breg | |
| BREGCTL_BIN: ${{ github.workspace }}/target/debug/bregctl | |
| run: | | |
| set -euo pipefail | |
| # `caseworkctl dev` and `bregctl dev` each run PostgreSQL in a | |
| # disposable container of their own, which the runner stops when | |
| # the journey ends, so the replay stays on the Docker runner rather | |
| # than inside a clean read-only container. | |
| node docs/site/scripts/run-tutorial.mjs --gate casework | |
| messaging-tutorial: | |
| name: Registry Messaging tutorial from source | |
| needs: | |
| - changes | |
| - rust-policy | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.messaging_tutorial == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Setup Node | |
| uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 | |
| with: | |
| node-version: 24.11.0 | |
| cache: npm | |
| cache-dependency-path: docs/site/package-lock.json | |
| - name: Cache Cargo registry | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # 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:messaging | |
| - name: Check tutorial command drift | |
| working-directory: docs/site | |
| run: npm run check:tutorial:messaging:dry-run | |
| - name: Build the Registry Messaging toolset under test | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| cargo build --locked -p registry-messagingctl -p registry-messaging -p registry-rstack --bins | |
| - name: Execute the Registry Messaging tutorial from a reader directory | |
| shell: bash | |
| env: | |
| RSTACK_BIN: ${{ github.workspace }}/target/debug/rstack | |
| MESSAGING_BIN: ${{ github.workspace }}/target/debug/messaging | |
| MESSAGINGCTL_BIN: ${{ github.workspace }}/target/debug/messagingctl | |
| run: | | |
| set -euo pipefail | |
| # The tutorial passes no port flags, and this runner listens on | |
| # neither default, so the replay runs on the ports a reader gets. | |
| # The session the page starts runs PostgreSQL and Mailpit in | |
| # containers of its own, which is why the replay stays on the | |
| # Docker runner rather than inside a clean read-only container. | |
| bash docs/site/scripts/check-messaging-tutorial.sh | |
| documents-tutorial: | |
| name: Document Store tutorial from source | |
| needs: | |
| - changes | |
| - rust-policy | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.documents_tutorial == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Setup Node | |
| uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 | |
| with: | |
| node-version: 24.11.0 | |
| cache: npm | |
| cache-dependency-path: docs/site/package-lock.json | |
| - name: Cache Cargo registry | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Install docs dependencies | |
| working-directory: docs/site | |
| # The tutorial runner needs only pure-JS packages; see the Casework | |
| # job for why install scripts are skipped. | |
| run: npm ci --ignore-scripts | |
| - name: Test the tutorial runner | |
| working-directory: docs/site | |
| run: npm run test:tutorial:runner | |
| - name: Check tutorial command drift | |
| working-directory: docs/site | |
| run: npm run check:tutorial:documents:dry-run | |
| - name: Build registry-documentsctl under test | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| cargo build --locked -p registry-documentsctl | |
| - name: Execute the Document Store tutorial from a reader directory | |
| working-directory: docs/site | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| # The page's own build step is skipped by the runner; the binary | |
| # built above stands in for it. The journey runs documentsctl only, | |
| # with no database, container or network. | |
| export PATH="$GITHUB_WORKSPACE/target/debug:$PATH" | |
| npm run check:tutorial:documents | |
| render-tutorial: | |
| name: Registry Render tutorial from source | |
| needs: | |
| - changes | |
| - rust-policy | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.render_tutorial == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Setup Node | |
| uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 | |
| with: | |
| node-version: 24.11.0 | |
| cache: npm | |
| cache-dependency-path: docs/site/package-lock.json | |
| - name: Cache Cargo registry | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Install docs dependencies | |
| working-directory: docs/site | |
| # The tutorial runner needs only pure-JS packages; see the Casework | |
| # job for why install scripts are skipped. | |
| run: npm ci --ignore-scripts | |
| - name: Test the tutorial runner | |
| working-directory: docs/site | |
| run: npm run test:tutorial:runner | |
| - name: Check tutorial command drift | |
| working-directory: docs/site | |
| run: npm run check:tutorial:render:dry-run | |
| - name: Build registry-render under test | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| cargo build --locked -p registry-render | |
| - name: Execute the Registry Render tutorial from a reader directory | |
| working-directory: docs/site | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| # The page's own build step is skipped by the runner; the binary | |
| # built above stands in for it. The journey starts no container and | |
| # listens on loopback only. | |
| export PATH="$GITHUB_WORKSPACE/target/debug:$PATH" | |
| npm run check:tutorial:render | |
| scheduling-tutorial: | |
| name: Registry Scheduling tutorial from source | |
| needs: | |
| - changes | |
| - rust-policy | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.scheduling_tutorial == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Setup Node | |
| uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 | |
| with: | |
| node-version: 24.11.0 | |
| cache: npm | |
| cache-dependency-path: docs/site/package-lock.json | |
| - name: Cache Cargo registry | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Install docs dependencies | |
| working-directory: docs/site | |
| # The tutorial runner needs only pure-JS packages; see the Casework | |
| # job for why install scripts are skipped. | |
| run: npm ci --ignore-scripts | |
| - name: Test the tutorial runner | |
| working-directory: docs/site | |
| run: npm run test:tutorial:runner | |
| - name: Check tutorial command drift | |
| working-directory: docs/site | |
| run: npm run check:tutorial:scheduling:dry-run | |
| - name: Build scheduling and schedulingctl under test | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| cargo build --locked -p registry-scheduling -p registry-schedulingctl --bins | |
| - name: Execute the Registry Scheduling tutorial from a reader directory | |
| working-directory: docs/site | |
| shell: bash | |
| env: | |
| SCHEDULING_BIN: ${{ github.workspace }}/target/debug/scheduling | |
| SCHEDULINGCTL_BIN: ${{ github.workspace }}/target/debug/schedulingctl | |
| run: | | |
| set -euo pipefail | |
| # The pages' own install step is skipped by the runner; the binaries | |
| # built above stand in for it. The journey starts no service and no | |
| # container. | |
| npm run check:tutorial:scheduling | |
| breg-evidence-composition: | |
| # The offline proof that a BReg evidence-source export composes into an | |
| # Evidence project and that a later export updates it. It drives three | |
| # native binaries over the reviewed teaching inputs and starts no service, | |
| # so it needs neither Docker nor the tutorial replay's writable checkout. | |
| # It also proves the surface of evidencectl source add without a session: | |
| # the review it performs by default, the matching bregctl it requires, and | |
| # that a refused connection leaves both projects untouched. Successful | |
| # preparation needs a retained session and is outside this offline proof. | |
| name: Base Registry Engine to Evidence composition | |
| needs: | |
| - changes | |
| - rust-policy | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.breg_evidence_composition == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| persist-credentials: false | |
| submodules: false | |
| - name: Cache Cargo registry | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 | |
| with: | |
| version: "0.11.16" | |
| - name: Build the composition toolset under test | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| cargo build --locked \ | |
| -p registry-bregctl -p registry-evidence -p registry-evidencectl \ | |
| --bins | |
| - name: Verify native Evidence source composition and updates | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| uv run --no-project --with PyYAML==6.0.2 python \ | |
| products/breg/evidence/tests/verify-composition.py \ | |
| --bregctl "$GITHUB_WORKSPACE/target/debug/bregctl" \ | |
| --evidencectl "$GITHUB_WORKSPACE/target/debug/evidencectl" \ | |
| --evidence "$GITHUB_WORKSPACE/target/debug/evidence" | |
| 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@949feb2413d6458794dcd2491c4babbbce0c15c1 | |
| with: | |
| node-version: 24.11.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 | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| fetch-depth: 0 | |
| submodules: false | |
| - name: Setup Node | |
| uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 | |
| with: | |
| node-version: 24.11.0 | |
| cache: npm | |
| cache-dependency-path: docs/site/package-lock.json | |
| - name: Install docs shell dependency | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| # Use the Ubuntu archive if the runner's Azure mirror cannot resolve. | |
| if [[ -f /etc/apt/apt-mirrors.txt ]] && ! timeout 10 getent ahosts azure.archive.ubuntu.com >/dev/null; then | |
| mirror="$(bash .github/scripts/select-ubuntu-archive.sh)" | |
| printf '%s\n' "$mirror" | sudo tee /etc/apt/apt-mirrors.txt >/dev/null | |
| fi | |
| 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 | |
| # The only install script that matters here is the Vale postinstall, | |
| # which fetches its binary through the unauthenticated GitHub API and | |
| # is refused once a shared runner address exhausts its hourly limit. | |
| # The next step installs a pinned Vale instead. | |
| run: npm ci --ignore-scripts | |
| - name: Install pinned Vale | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| mkdir -p "${RUNNER_TEMP}/bin" | |
| curl --proto '=https' --tlsv1.2 --fail --silent --show-error --location \ | |
| --output "${RUNNER_TEMP}/vale.tar.gz" \ | |
| "https://github.com/vale-cli/vale/releases/download/v${VALE_VERSION}/vale_${VALE_VERSION}_Linux_64-bit.tar.gz" | |
| echo "${VALE_LINUX_X64_SHA256} ${RUNNER_TEMP}/vale.tar.gz" | \ | |
| sha256sum --check --strict | |
| tar -xzf "${RUNNER_TEMP}/vale.tar.gz" -C "${RUNNER_TEMP}/bin" vale | |
| echo "VALE_BIN=${RUNNER_TEMP}/bin/vale" >> "${GITHUB_ENV}" | |
| - 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-slim | |
| timeout-minutes: 5 | |
| 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 | |
| - rust-policy | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.docs_archives == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 35 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| fetch-depth: 0 | |
| submodules: false | |
| - name: Setup Node | |
| uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 | |
| with: | |
| node-version: 24.11.0 | |
| cache: npm | |
| cache-dependency-path: docs/site/package-lock.json | |
| - name: Install docs dependencies | |
| working-directory: docs/site | |
| # No step here runs Vale, the only package with an install script | |
| # this job would use. Its postinstall fetches through the | |
| # unauthenticated GitHub API, which refuses shared runner addresses | |
| # once their hourly limit is spent, so install scripts are skipped. | |
| run: npm ci --ignore-scripts | |
| - name: Validate archive lock and compare event baseline | |
| working-directory: docs/site | |
| env: | |
| ARCHIVE_LOCK_BASE_REF: ${{ needs.changes.outputs.archive_base_ref }} | |
| ARCHIVE_COMPARISON_REQUIRED: ${{ needs.changes.outputs.archive_comparison_required }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| if [[ "${ARCHIVE_COMPARISON_REQUIRED}" == "true" ]]; then | |
| if [[ -z "${ARCHIVE_LOCK_BASE_REF}" ]]; then | |
| echo "Cannot verify archive immutability: event baseline is unavailable." >&2 | |
| exit 1 | |
| fi | |
| npm run check:archive-lock -- --base-ref "${ARCHIVE_LOCK_BASE_REF}" | |
| elif [[ "${ARCHIVE_COMPARISON_REQUIRED}" == "false" ]]; then | |
| # Scheduled reconstruction validates locked bytes without a change baseline. | |
| npm run check:archive-lock | |
| else | |
| echo "Archive comparison policy is unavailable." >&2 | |
| exit 1 | |
| fi | |
| - name: Assemble and verify the published archive window | |
| working-directory: docs/site | |
| run: npm run check:archives | |
| editor-extensions: | |
| name: Editor extensions | |
| needs: | |
| - changes | |
| - rust-policy | |
| if: ${{ !cancelled() && needs.changes.result == 'success' && needs.changes.outputs.editors == 'true' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| fetch-depth: 0 | |
| submodules: false | |
| - name: Setup Node | |
| uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 | |
| with: | |
| node-version: 24.11.0 | |
| cache: npm | |
| cache-dependency-path: editors/vscode/package-lock.json | |
| - name: Test editor installer | |
| run: | | |
| bash editors/tests/install_test.sh | |
| python3 -m unittest discover -s editors/tests -p 'test_*.py' | |
| - 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 test --locked --manifest-path editors/zed/Cargo.toml | |
| 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 | |
| timeout-minutes: 45 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 | |
| with: | |
| fetch-depth: 0 | |
| submodules: false | |
| - name: Setup Node | |
| uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 | |
| with: | |
| # The napi-rs CLI's toolchain dependencies require Node 24.12 or | |
| # later. Candidate package smoke tests separately retain the Node | |
| # 24.11 runtime floor. | |
| node-version: 24.21.0 | |
| cache: npm | |
| cache-dependency-path: | | |
| crates/registry-discovery-client-node/package-lock.json | |
| crates/registry-evidence-client-node/package-lock.json | |
| crates/registry-breg-client-node/package-lock.json | |
| crates/registry-casework-client-node/package-lock.json | |
| crates/registry-messaging-client-node/package-lock.json | |
| crates/registry-scheduling-client-node/package-lock.json | |
| crates/registry-coordinator-client-node/package-lock.json | |
| crates/registry-render-client-node/package-lock.json | |
| crates/registry-stack-client-node/package-lock.json | |
| - name: Cache Cargo registry | |
| uses: Swatinem/rust-cache@c8037a86dde8214a8310e9f54a8fc61ab362aa31 # v2 | |
| with: | |
| shared-key: workspace-registry | |
| cache-targets: false | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: Build and test Node bindings | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| for client in registry-discovery-client-node registry-evidence-client-node registry-breg-client-node registry-casework-client-node registry-messaging-client-node registry-scheduling-client-node registry-coordinator-client-node registry-render-client-node; do | |
| ( | |
| cd "crates/${client}" | |
| npm ci | |
| npm run build:debug | |
| npm test | |
| npm run check:types | |
| cmp ../../LICENSE LICENSE | |
| ) | |
| done | |
| ( | |
| cd crates/registry-stack-client-node | |
| npm ci | |
| npm test | |
| npm run check:types | |
| cmp ../../LICENSE LICENSE | |
| ) | |
| - name: Build and test Python bindings | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| for client in registry-discovery-client-py registry-evidence-client-py registry-breg-client-py registry-casework-client-py registry-messaging-client-py registry-scheduling-client-py registry-coordinator-client-py registry-render-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 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 | |
| with: | |
| version: "0.11.16" | |
| - name: Test direct Python composition with the exact checkout client | |
| working-directory: products/platform/examples/python-composition | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| maturin_venv="${RUNNER_TEMP}/python-composition-maturin" | |
| uv venv "${maturin_venv}" | |
| uv pip install \ | |
| --python "${maturin_venv}/bin/python" \ | |
| --require-hashes \ | |
| --only-binary=:all: \ | |
| --requirement "${GITHUB_WORKSPACE}/release/requirements/maturin-1.9.6.txt" | |
| out_dir="${RUNNER_TEMP}/python-composition-client" | |
| python3 "${GITHUB_WORKSPACE}/release/scripts/assemble-registry-client-packages.py" \ | |
| --artifacts python \ | |
| --python-profile ci \ | |
| --output-dir "${out_dir}" \ | |
| --work-dir "${RUNNER_TEMP}/python-composition-client-assembly" \ | |
| --maturin "${maturin_venv}/bin/maturin" \ | |
| --zig-python "${maturin_venv}/bin/python" | |
| mapfile -t wheels < <(find "${out_dir}" -maxdepth 1 -type f \ | |
| -name 'registry_stack_client-*.whl') | |
| if [[ "${#wheels[@]}" -ne 1 ]]; then | |
| printf 'expected exactly one assembled client wheel in %s\n' "${out_dir}" >&2 | |
| printf '%s\n' "${wheels[@]}" >&2 | |
| exit 1 | |
| fi | |
| uv run --locked --with "${wheels[0]}" \ | |
| python -m unittest discover -s tests -v | |
| - name: Test released-client Coordinator example | |
| working-directory: products/coordinator/examples/reviewed-notice | |
| run: uv run --locked python -m unittest discover -s tests -v | |
| release-linux-node-clients: | |
| name: Release Linux native 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: Install Go for the AWS-LC-FIPS source build | |
| uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 | |
| with: | |
| go-version: 1.27.2 | |
| cache: false | |
| - name: Setup Node | |
| uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 | |
| with: | |
| node-version: 24.21.0 | |
| cache: npm | |
| cache-dependency-path: | | |
| crates/registry-discovery-client-node/package-lock.json | |
| crates/registry-evidence-client-node/package-lock.json | |
| crates/registry-breg-client-node/package-lock.json | |
| crates/registry-casework-client-node/package-lock.json | |
| crates/registry-messaging-client-node/package-lock.json | |
| crates/registry-scheduling-client-node/package-lock.json | |
| crates/registry-coordinator-client-node/package-lock.json | |
| crates/registry-render-client-node/package-lock.json | |
| crates/registry-stack-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 breg casework messaging scheduling coordinator render; 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" | |
| if [[ "${client}" == breg || "${client}" == casework || "${client}" == messaging || "${client}" == scheduling || "${client}" == coordinator || "${client}" == render ]]; then | |
| class_name=BaseRegistryClient | |
| base_url=https://registry.invalid | |
| if [[ "${client}" == casework ]]; then | |
| class_name=CaseworkClient | |
| base_url=https://casework.invalid | |
| elif [[ "${client}" == messaging ]]; then | |
| class_name=MessagingClient | |
| base_url=https://messaging.invalid | |
| elif [[ "${client}" == scheduling ]]; then | |
| class_name=SchedulingClient | |
| base_url=https://scheduling.invalid | |
| elif [[ "${client}" == render ]]; then | |
| class_name=RenderClient | |
| base_url=https://render.invalid | |
| elif [[ "${client}" == coordinator ]]; then | |
| class_name=CoordinatorClient | |
| base_url=https://coordinator.invalid | |
| fi | |
| node -e "const Client = require('${client_dir}/client')['${class_name}']; new Client({ baseUrl: '${base_url}' })" | |
| continue | |
| fi | |
| 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 | |
| client_dir="${GITHUB_WORKSPACE}/crates/registry-stack-client-node" | |
| platform_dir="${client_dir}/npm/${{ matrix.napi_platform }}" | |
| for client in discovery evidence breg casework messaging scheduling coordinator render; do | |
| cp "${GITHUB_WORKSPACE}/crates/registry-${client}-client-node/${client}-client.${{ matrix.napi_platform }}.node" \ | |
| "${platform_dir}/" | |
| done | |
| smoke="${RUNNER_TEMP}/node-smoke-registry" | |
| mkdir -p "${smoke}/node_modules/@registrystack" | |
| mkdir -p "${client_dir}/node_modules/@registrystack" | |
| ln -s "${platform_dir}" \ | |
| "${client_dir}/node_modules/@registrystack/client-${{ matrix.napi_platform }}" | |
| ln -s "${client_dir}" \ | |
| "${smoke}/node_modules/@registrystack/client" | |
| cp "${GITHUB_WORKSPACE}/release/scripts/smoke-registry-client-package.js" \ | |
| "${GITHUB_WORKSPACE}/release/scripts/smoke-registry-client-package.mjs" \ | |
| "${smoke}/" | |
| (cd "${smoke}" && node smoke-registry-client-package.js) | |
| (cd "${smoke}" && node smoke-registry-client-package.mjs) | |
| - name: Prove production Linux Python client recipe | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| wheel_dir="${RUNNER_TEMP}/python-client-wheel" | |
| mkdir -p "${wheel_dir}" | |
| release/scripts/build-linux-python-client \ | |
| --client evidence \ | |
| --target "${{ matrix.target }}" \ | |
| --compatibility manylinux_2_17 \ | |
| --zig-python "${RUNNER_TEMP}/maturin/bin/python" \ | |
| --maturin "${RUNNER_TEMP}/maturin/bin/maturin" \ | |
| --out "${wheel_dir}" \ | |
| --profile ci | |
| shopt -s nullglob | |
| wheels=("${wheel_dir}"/registry_evidence_client-*.whl) | |
| if (( "${#wheels[@]}" != 1 )); then | |
| printf 'expected exactly one audited Evidence wheel, found %s\n' \ | |
| "${#wheels[@]}" >&2 | |
| exit 1 | |
| fi | |
| ci-result: | |
| name: CI result | |
| if: always() | |
| needs: | |
| - changes | |
| - secrets | |
| - platform-quality | |
| - platform-hygiene | |
| - platform-fuzz | |
| - rust-policy | |
| - rust-quality | |
| - rust-tests | |
| - discovery-contracts | |
| - evidence-contracts | |
| - evidence-postgres | |
| - evidence-fuzz | |
| - breg-contracts | |
| - breg-postgres-18 | |
| - breg-wasm | |
| - identifiers | |
| - casework-postgres | |
| - scheduling-postgres | |
| - scheduling-contracts | |
| - messaging-postgres | |
| - messaging-contracts | |
| - messaging-smtp | |
| - documents-contracts | |
| - documents-postgres | |
| - adapter-contracts | |
| - adapter-postgres | |
| - coordinator-postgres | |
| - config-conformance | |
| - release-tool | |
| - release-source-proof | |
| - evidence-tutorials | |
| - breg-tutorial | |
| - casework-tutorial | |
| - messaging-tutorial | |
| - documents-tutorial | |
| - render-tutorial | |
| - scheduling-tutorial | |
| - breg-evidence-composition | |
| - evidence-anchors | |
| - docs | |
| - editor-extensions | |
| - client-bindings | |
| - release-linux-node-clients | |
| runs-on: ubuntu-slim | |
| timeout-minutes: 5 | |
| 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"} | |
| } | |
| # Review skips the heavy integration tier by design. Wherever the | |
| # classifier selected one of these jobs, a skip is a failure. | |
| selected_by = { | |
| "breg-contracts": "breg_contracts", | |
| "breg-postgres-18": "breg_contracts", | |
| "breg-wasm": "breg_integration", | |
| "casework-postgres": "casework_postgres", | |
| "scheduling-postgres": "scheduling_postgres", | |
| "evidence-tutorials": "evidence_tutorial", | |
| "breg-tutorial": "breg_tutorial", | |
| "casework-tutorial": "casework_tutorial", | |
| "breg-evidence-composition": "breg_evidence_composition", | |
| } | |
| selection = jobs["changes"].get("outputs", {}) | |
| for name, output in selected_by.items(): | |
| if selection.get(output) == "true" and jobs[name]["result"] != "success": | |
| failed[name] = jobs[name]["result"] | |
| 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 |