Qualification #128
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: Weekly | |
| on: | |
| schedule: | |
| - cron: "0 3 * * 0" | |
| workflow_dispatch: | |
| inputs: | |
| mode: | |
| description: "Assurance is routine coverage; release adds release-grade evidence." | |
| required: true | |
| type: choice | |
| options: | |
| - assurance | |
| - release | |
| default: assurance | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name == 'workflow_dispatch' && inputs.mode == 'release' && 'release' || 'assurance' }} | |
| cancel-in-progress: true | |
| env: | |
| RUST_BACKTRACE: 1 | |
| CARGO_TERM_COLOR: always | |
| RSCRYPTO_TEST_MODE: weekly | |
| CARGO_INCREMENTAL: 0 | |
| permissions: | |
| contents: read | |
| jobs: | |
| mode: | |
| name: Resolve Weekly Mode | |
| runs-on: ubuntu-latest | |
| outputs: | |
| mode: ${{ steps.mode.outputs.mode }} | |
| steps: | |
| - name: Resolve mode | |
| id: mode | |
| shell: bash | |
| env: | |
| EVENT_NAME: ${{ github.event_name }} | |
| REQUESTED_MODE: ${{ inputs.mode }} | |
| run: | | |
| set -euo pipefail | |
| case "$EVENT_NAME" in | |
| schedule) | |
| mode=assurance | |
| ;; | |
| workflow_dispatch) | |
| case "$REQUESTED_MODE" in | |
| assurance | release) mode="$REQUESTED_MODE" ;; | |
| *) echo "Unknown Weekly mode: $REQUESTED_MODE" >&2; exit 2 ;; | |
| esac | |
| ;; | |
| *) | |
| echo "Unsupported Weekly event: $EVENT_NAME" >&2 | |
| exit 2 | |
| ;; | |
| esac | |
| echo "mode=$mode" >> "$GITHUB_OUTPUT" | |
| echo "Weekly mode: $mode" | |
| # Both modes run the full platform and feature suite. Release mode adds the | |
| # exhaustive Cargo graph and full supply-chain policy. | |
| suite: | |
| name: CI Suite (${{ needs.mode.outputs.mode }}) | |
| needs: mode | |
| uses: ./.github/workflows/_ci-suite.yaml | |
| with: | |
| cache_key_prefix: weekly | |
| supply_chain_mode: ${{ needs.mode.outputs.mode == 'release' && 'full' || 'light' }} | |
| test_mode: weekly | |
| include_cargo_graph: ${{ needs.mode.outputs.mode == 'release' }} | |
| artifact_retention_days: ${{ needs.mode.outputs.mode == 'release' && 90 || 14 }} | |
| # ─── Miri memory-safety (stacked borrows). ── | |
| miri: | |
| name: Miri (${{ matrix.target.name }}) | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| target: | |
| - name: x86_64 | |
| runner: runs-on=${{ github.run_id }}/runner=linux-x64-ci | |
| - name: aarch64 | |
| runner: runs-on=${{ github.run_id }}/runner=linux-arm64-ci | |
| uses: ./.github/workflows/_rust-job.yaml | |
| with: | |
| runner: ${{ matrix.target.runner }} | |
| timeout_minutes: 60 | |
| cache_key: weekly-miri-${{ matrix.target.name }} | |
| tools_mode: minimal | |
| toolchain_contract: nightly | |
| toolchain_components: "miri, rust-src" | |
| enable_magic_cache: true | |
| enable_rust_cache: true | |
| operation: miri | |
| # ─── Miri memory-safety (tree borrows). ── | |
| miri-tree-borrows: | |
| name: Miri (Tree Borrows) | |
| uses: ./.github/workflows/_rust-job.yaml | |
| with: | |
| runner: runs-on=${{ github.run_id }}/runner=linux-x64-ci | |
| timeout_minutes: 60 | |
| cache_key: weekly-miri-tree-borrows | |
| tools_mode: minimal | |
| toolchain_contract: nightly | |
| toolchain_components: "miri, rust-src" | |
| enable_magic_cache: true | |
| enable_rust_cache: true | |
| operation: miri | |
| miri_tree_borrows: true | |
| # ─── Fuzzing (libFuzzer full + scoped packages). ── | |
| fuzzing: | |
| name: Fuzzing (${{ matrix.target.name }}) | |
| needs: mode | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| target: | |
| - name: x86_64 | |
| runner: runs-on=${{ github.run_id }}/runner=linux-x64-ci | |
| - name: aarch64 | |
| runner: runs-on=${{ github.run_id }}/runner=linux-arm64-ci | |
| uses: ./.github/workflows/_rust-job.yaml | |
| with: | |
| runner: ${{ matrix.target.runner }} | |
| timeout_minutes: 120 | |
| cache_key: weekly-fuzz-${{ matrix.target.name }} | |
| tools_mode: fuzz | |
| toolchain_contract: nightly | |
| enable_magic_cache: true | |
| enable_rust_cache: true | |
| operation: fuzz | |
| artifact_name: fuzz-output-weekly-${{ matrix.target.name }} | |
| artifact_path: | | |
| fuzz-output/corpus.tar.gz | |
| fuzz/artifacts/ | |
| fuzz-packages/*/artifacts/ | |
| artifact_always: true | |
| artifact_retention_days: ${{ needs.mode.outputs.mode == 'release' && 90 || 14 }} | |
| asan-fuzzing: | |
| name: ASan Fuzz Corpus (${{ matrix.target.name }}) | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| target: | |
| - name: x86_64 | |
| runner: runs-on=${{ github.run_id }}/runner=linux-x64-ci | |
| - name: aarch64 | |
| runner: runs-on=${{ github.run_id }}/runner=linux-arm64-ci | |
| uses: ./.github/workflows/_rust-job.yaml | |
| with: | |
| runner: ${{ matrix.target.runner }} | |
| timeout_minutes: 120 | |
| cache_key: weekly-asan-fuzz-${{ matrix.target.name }} | |
| tools_mode: fuzz | |
| toolchain_contract: nightly | |
| toolchain_components: "rust-src" | |
| enable_magic_cache: true | |
| enable_rust_cache: true | |
| operation: fuzz-asan | |
| # --- Native ML-KEM promotion gate on the physical AWS targets. --- | |
| mlkem-graviton: | |
| name: ML-KEM Graviton Gate (${{ matrix.display_name }}) | |
| needs: mode | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - platform: graviton3 | |
| display_name: AWS Graviton3 | |
| - platform: graviton4 | |
| display_name: AWS Graviton4 | |
| uses: ./.github/workflows/_rust-job.yaml | |
| with: | |
| runner: runs-on=${{ github.run_id }}/runner=${{ matrix.platform }} | |
| timeout_minutes: 180 | |
| cache_key: weekly-mlkem-${{ matrix.platform }} | |
| tools_mode: minimal | |
| toolchain_components: "clippy, rustfmt, rust-src" | |
| enable_magic_cache: false | |
| enable_rust_cache: true | |
| operation: mlkem-aarch64 | |
| platform: ${{ matrix.platform }} | |
| artifact_name: mlkem-aarch64-gate-${{ matrix.platform }} | |
| artifact_path: mlkem-aarch64-gate/ | |
| artifact_always: true | |
| artifact_retention_days: ${{ needs.mode.outputs.mode == 'release' && 90 || 14 }} | |
| # ─── Constant-time evidence on benchmark-published physical lanes. ── | |
| ct: | |
| name: Constant-Time Evidence (${{ needs.mode.outputs.mode }}) | |
| needs: mode | |
| uses: ./.github/workflows/ct.yaml | |
| with: | |
| platforms: all | |
| dudect_timeout: 1800 | |
| binsec_timeout: 900 | |
| upload_raw_artifacts: ${{ needs.mode.outputs.mode == 'release' }} | |
| artifact_retention_days: ${{ needs.mode.outputs.mode == 'release' && 90 || 14 }} | |
| rsa: | |
| name: RSA Evidence (${{ needs.mode.outputs.mode }}) | |
| needs: mode | |
| uses: ./.github/workflows/rsa.yaml | |
| with: | |
| artifact_retention_days: ${{ needs.mode.outputs.mode == 'release' && 90 || 14 }} | |
| # ─── Coverage (nextest + fuzz corpus → codecov). ── | |
| coverage: | |
| name: Coverage | |
| needs: [mode, suite, fuzzing] | |
| runs-on: runs-on=${{ github.run_id }}/runner=linux-x64-ci | |
| timeout-minutes: 120 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Setup | |
| uses: ./.github/actions/setup | |
| with: | |
| cache-key: weekly-coverage | |
| tools-mode: coverage | |
| toolchain-components: "rust-src" | |
| enable-magic-cache: "true" | |
| enable-rust-cache: "true" | |
| - name: Download fuzz corpus artifacts | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| pattern: fuzz-output-weekly-* | |
| path: fuzz-output-artifacts | |
| - name: Restore fuzz corpora | |
| shell: bash | |
| run: | | |
| shopt -s nullglob | |
| archives=(fuzz-output-artifacts/*/fuzz-output/corpus.tar.gz) | |
| if [ "${#archives[@]}" -eq 0 ]; then | |
| echo "No fuzz corpus archives found" | |
| exit 0 | |
| fi | |
| for archive in "${archives[@]}"; do | |
| echo "Extracting $archive" | |
| tar -xzf "$archive" | |
| done | |
| - name: Total Coverage (nextest + fuzz corpus replay) | |
| run: just test-coverage | |
| - name: Install authenticated Codecov CLI | |
| id: codecov | |
| run: scripts/ci/install-codecov.sh | |
| - name: Upload to Codecov | |
| uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 | |
| with: | |
| binary: ${{ steps.codecov.outputs.binary }} | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| files: coverage/total.lcov | |
| flags: total | |
| name: total | |
| fail_ci_if_error: true | |
| - name: Upload Coverage Artifacts | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: coverage-reports | |
| path: | | |
| coverage/total.lcov | |
| coverage/SUMMARY.md | |
| retention-days: ${{ needs.mode.outputs.mode == 'release' && 90 || 14 }} | |
| if-no-files-found: warn | |
| # The mode-specific terminal name is part of the release qualification contract. | |
| complete: | |
| name: Complete (${{ needs.mode.outputs.mode }}) | |
| needs: [mode, suite, miri, miri-tree-borrows, fuzzing, asan-fuzzing, mlkem-graviton, ct, rsa, coverage] | |
| if: ${{ !cancelled() }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Assert all lanes passed | |
| run: | | |
| failed=0 | |
| for lane in \ | |
| "mode=${{ needs.mode.result }}" \ | |
| "suite=${{ needs.suite.result }}" \ | |
| "miri=${{ needs.miri.result }}" \ | |
| "miri-tree-borrows=${{ needs.miri-tree-borrows.result }}" \ | |
| "fuzzing=${{ needs.fuzzing.result }}" \ | |
| "asan-fuzzing=${{ needs.asan-fuzzing.result }}" \ | |
| "mlkem-graviton=${{ needs.mlkem-graviton.result }}" \ | |
| "ct=${{ needs.ct.result }}" \ | |
| "rsa=${{ needs.rsa.result }}" \ | |
| "coverage=${{ needs.coverage.result }}" | |
| do | |
| name="${lane%%=*}" | |
| result="${lane#*=}" | |
| if [ "$result" != "success" ]; then | |
| echo "FAIL: $name ($result)" | |
| failed=1 | |
| else | |
| echo " OK: $name" | |
| fi | |
| done | |
| if [ "$failed" -eq 1 ]; then | |
| echo "" | |
| echo "One or more required lanes failed." | |
| exit 1 | |
| fi |