diff --git a/.github-gen/velnor-workflow.toml b/.github-gen/velnor-workflow.toml index ea7a4c1..acd9aed 100644 --- a/.github-gen/velnor-workflow.toml +++ b/.github-gen/velnor-workflow.toml @@ -2,7 +2,7 @@ schema = 1 [generator] repository = "tailrocks/ruxel" -revision = "b9c3156cdb88e63c11b9e595a3e694b02238c09a" +revision = "4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d" [workflow] runners = "both" diff --git a/.github/ci/.github-actions-generator-state b/.github/ci/.github-actions-generator-state index d97f220..5eb4725 100644 --- a/.github/ci/.github-actions-generator-state +++ b/.github/ci/.github-actions-generator-state @@ -1,17 +1,17 @@ # Generated ownership state; do not edit. schema = 2 [inputs] -config f03318060fdf269b -scan 73483f0bc233ebc4 -generator 49 +config e077738d5d760ac5 +scan 64b8b7a298804718 +generator 54 [outputs] .github/actionlint.yaml ec35f48ae7e90e0e -.github/ci/project.toml a0c5060b9b02e82b -.github/workflows/ci-main.yml f876c8065e0aab47 -.github/workflows/ci-policy.yml a9a48676140ac8dd -.github/workflows/ci-pr.yml c856ce561e05155e -.github/workflows/ci-unit-docker.yml f4a6ab47c5e4bbba -.github/workflows/ci-unit-rust.yml 2bd3bb41c4614dff -.github/workflows/maintenance.yml 44cdcd6db1e77d43 +.github/ci/project.toml 90768fed45857d11 +.github/workflows/ci-main.yml 95d34976db586b85 +.github/workflows/ci-policy.yml e4f8d6d6bfe9cf06 +.github/workflows/ci-pr.yml 9a26dfbcf69e2613 +.github/workflows/ci-unit-docker.yml c1b32465f205557c +.github/workflows/ci-unit-rust.yml 3360faf9d71979b5 +.github/workflows/maintenance.yml b38094a09a507115 .github/workflows/nightly.yml c73d542eaf687a7e config/fleet/velnor-host.env d14b419216449423 diff --git a/.github/ci/project.toml b/.github/ci/project.toml index 844d5f1..684eaf9 100644 --- a/.github/ci/project.toml +++ b/.github/ci/project.toml @@ -15,7 +15,7 @@ limitations = ["Project code, build scripts, task runners, and commands are neve github_runner = "ubuntu-24.04" velnor_labels = ["self-hosted", "velnor-target-mvp"] files = ["ci-main.yml", "ci-policy.yml", "ci-pr.yml", "ci-unit-docker.yml", "ci-unit-rust.yml", "maintenance.yml", "nightly.yml"] -notes = ["Rust verification uses Mr. Boxington 1.11.1 by default on both lanes. GitHub-hosted jobs use its GitHub cache backend with bounded snapshot keys (a key names the toolchain/image/linker compatibility class and the hashed source state, so a new source state saves a new snapshot and retention keeps generations bounded). Velnor jobs use an explicit local-backend setup step against the image/runner-provided local store."] +notes = ["Rust verification uses Mr. Boxington 1.12.0 by default on both lanes. GitHub-hosted jobs use its GitHub cache backend with bounded snapshot keys (a key names the toolchain/image/linker compatibility class and the hashed source state, so a new source state saves a new snapshot and retention keeps generations bounded). Velnor jobs use an explicit local-backend setup step against the image/runner-provided local store."] [release] enabled = false diff --git a/.github/workflows/ci-main.yml b/.github/workflows/ci-main.yml index 05d5c5d..eb9efbd 100644 --- a/.github/workflows/ci-main.yml +++ b/.github/workflows/ci-main.yml @@ -58,12 +58,13 @@ jobs: fetch-depth: 0 persist-credentials: false - name: Set up Velnor workflow runtime + id: runtime if: ${{ runner.environment == 'github-hosted' }} - uses: tailrocks/velnor/.github/actions/setup-velnor-workflow@b9c3156cdb88e63c11b9e595a3e694b02238c09a + uses: tailrocks/velnor/.github/actions/setup-velnor-workflow@4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d with: - rev: b9c3156cdb88e63c11b9e595a3e694b02238c09a + rev: 4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d - name: Set trusted workflow policy revision - run: echo "VELNOR_WORKFLOW_POLICY_REVISION=b9c3156cdb88e63c11b9e595a3e694b02238c09a" >> "$GITHUB_ENV" + run: echo "VELNOR_WORKFLOW_POLICY_REVISION=4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d" >> "$GITHUB_ENV" - name: Select affected units id: plan env: @@ -80,7 +81,7 @@ jobs: - name: Prepare Velnor workflow runtime shell: bash env: - EXPECTED_REVISION: b9c3156cdb88e63c11b9e595a3e694b02238c09a + EXPECTED_REVISION: 4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d run: | set -euo pipefail stage="$RUNNER_TEMP/velnor-workflow-runtime" @@ -92,13 +93,14 @@ jobs: policy_src="${VELNOR_WORKFLOW_PINNED_BINARY:-$src}" install -m 0755 "$policy_src" "$stage/velnor-workflow-policy" policy_revision="$("$stage/velnor-workflow-policy" --revision)" - [[ "$policy_revision" == "$EXPECTED_REVISION" ]] || { echo "::error::policy runtime reports revision $policy_revision, expected $EXPECTED_REVISION" >&2; exit 1; } + policy_closure="$("$stage/velnor-workflow-policy" --closure)" + [[ "$policy_closure" == "${{ steps.runtime.outputs.closure }}" ]] || { echo "::error::policy runtime reports closure $policy_closure, expected ${{ steps.runtime.outputs.closure }}" >&2; exit 1; } policy_digest="$(sha256sum "$stage/velnor-workflow-policy" | awk '{print $1}')" - jq -n --arg repository "$GITHUB_REPOSITORY" --arg revision "$EXPECTED_REVISION" --arg head_branch "${{ github.ref_name }}" --arg platform "${{ runner.os }}-${{ runner.arch }}" --arg run_id "$GITHUB_RUN_ID" --arg job_id "${{ github.job }}" --arg binary_sha256 "$digest" --arg policy_revision "$policy_revision" --arg policy_binary_sha256 "$policy_digest" '{repository: $repository, revision: $revision, head_branch: $head_branch, platform: $platform, run_id: $run_id, job_id: $job_id, binary_sha256: $binary_sha256, policy_revision: $policy_revision, policy_binary_sha256: $policy_binary_sha256}' > "$stage/manifest.json" + jq -n --arg repository "$GITHUB_REPOSITORY" --arg revision "$EXPECTED_REVISION" --arg closure "${{ steps.runtime.outputs.closure }}" --arg head_branch "${{ github.ref_name }}" --arg platform "${{ runner.os }}-${{ runner.arch }}" --arg run_id "$GITHUB_RUN_ID" --arg job_id "${{ github.job }}" --arg binary_sha256 "$digest" --arg policy_revision "$policy_revision" --arg policy_closure "$policy_closure" --arg policy_binary_sha256 "$policy_digest" '{repository: $repository, revision: $revision, closure: $closure, head_branch: $head_branch, platform: $platform, run_id: $run_id, job_id: $job_id, binary_sha256: $binary_sha256, policy_revision: $policy_revision, policy_closure: $policy_closure, policy_binary_sha256: $policy_binary_sha256}' > "$stage/manifest.json" - name: Publish Velnor workflow runtime uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: velnor-workflow-runtime-b9c3156cdb88e63c11b9e595a3e694b02238c09a-${{ runner.os }}-${{ runner.arch }} + name: velnor-workflow-runtime-4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d-${{ runner.os }}-${{ runner.arch }} path: ${{ runner.temp }}/velnor-workflow-runtime if-no-files-found: error retention-days: 7 @@ -115,11 +117,16 @@ jobs: name: Policy runs-on: ubuntu-24.04 timeout-minutes: 20 - # Trust invariant: this job runs the base branch's validator against the - # audited tree under pull_request_target. It holds `contents: read` only, - # references no secrets, and its checkout persists no credentials, so - # building and running the tree's declared generator here is no more - # privileged than the pull_request lanes that already build the tree. + # Trust invariant: this job runs the base branch's Stage-0 validator + # product against the audited tree under pull_request_target. It holds + # `contents: read` only, references no secrets, persists no credentials, + # and never compiles. When the audited tree differs from the declared + # pin's render, it additionally EXECUTES the PR run's prebuilt + # candidate generator — PR-built code, same-repository runs only, bound + # to the audited tree by manifest closure plus binary digest before + # execution — with no secret references, no persisted credentials, the + # read-only github.token confined to the Acquire/Ruleset API steps, + # and both candidate exec points tokenless. permissions: contents: read steps: @@ -140,39 +147,34 @@ jobs: git fetch --no-tags "$GITHUB_SERVER_URL/$HEAD_REPOSITORY" "$HEAD_SHA" fi git checkout --quiet --detach "$HEAD_SHA" - - name: Bound the Mr. Boxington store - shell: bash - run: echo "MBX_GC_MAX_SIZE=12GiB" >> "$GITHUB_ENV" - - name: Set up Mr. Boxington - uses: jdx/mr-boxington-action@7234d3dd1a6ca8f6c381eea8e4dfb03f18fcf777 # v1.3.0 + - name: Set up Velnor workflow runtime + uses: tailrocks/velnor/.github/actions/setup-velnor-workflow@4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d with: - backend: github - version: 1.11.1 - cache-key: velnor-policy-mbx-1.11.1-${{ runner.os }}-${{ runner.arch }}-b9c3156cdb88e63c11b9e595a3e694b02238c09a - restore-keys: | - velnor-policy-mbx-1.11.1-${{ runner.os }}-${{ runner.arch }}- - - name: Install pinned Velnor workflow runtime - env: - CARGO_HOME: ${{ runner.temp }}/velnor-workflow-cargo-home - CARGO_TARGET_DIR: ${{ runner.temp }}/velnor-workflow-cargo-target - VELNOR_WORKFLOW_INSTALL_DIR: ${{ runner.temp }}/velnor-workflow-install - VELNOR_WORKFLOW_ROOT: ${{ runner.temp }}/velnor-workflow + rev: 4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d + checkout-path: ${{ github.workspace }}/policy-checkout + - name: Read declared generator pin + id: pin + working-directory: policy-checkout + run: | + set -euo pipefail + pin="$(sed -n -E 's/^[[:space:]]*revision[[:space:]]*=[[:space:]]*"([0-9a-f]{40})".*/\1/p' .github-gen/velnor-workflow.toml | head -n 1)" + test "$pin" != '' || pin="$(sed -n -E 's/^.*VELNOR_WORKFLOW_POLICY_REVISION:[[:space:]]*([0-9a-f]{40}).*/\1/p' .github/workflows/ci-policy.yml | head -n 1)" + test "$pin" != '' || { echo "::error::audited tree declares no generator pin" >&2; exit 1; } + echo "value=$pin" >> "$GITHUB_OUTPUT" + - name: Set up declared generator product + id: renderer + if: steps.pin.outputs.value != '4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d' + uses: tailrocks/velnor/.github/actions/setup-velnor-workflow@4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d + with: + rev: ${{ steps.pin.outputs.value }} + checkout-path: ${{ github.workspace }}/policy-checkout + - name: Resolve declared generator product + if: steps.pin.outputs.value != '4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d' run: | set -euo pipefail - install -d -m 700 \ - "$CARGO_HOME" \ - "$CARGO_TARGET_DIR" \ - "$VELNOR_WORKFLOW_INSTALL_DIR" - cd "$VELNOR_WORKFLOW_INSTALL_DIR" - env -u RUSTC_WRAPPER -u SCCACHE_GHA_ENABLED -u CARGO_INCREMENTAL -u RUSTFLAGS -u CARGO_ENCODED_RUSTFLAGS \ - cargo install \ - --locked \ - --git https://github.com/tailrocks/velnor \ - --rev b9c3156cdb88e63c11b9e595a3e694b02238c09a \ - --root "$VELNOR_WORKFLOW_ROOT" \ - velnor-workflow \ - --bin velnor-workflow - echo "$VELNOR_WORKFLOW_ROOT/bin" >> "$GITHUB_PATH" + binary="$HOME/.cache/velnor/workflow-runtime/${{ steps.renderer.outputs.closure }}/bin/velnor-workflow" + test -x "$binary" + echo "VELNOR_WORKFLOW_PINNED_BINARY=$binary" >> "$GITHUB_ENV" - name: Resolve required status checks env: GH_TOKEN: ${{ github.token }} @@ -201,14 +203,16 @@ jobs: WORKFLOW_ROOT: ${{ github.workspace }}/policy-checkout HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} BASE_SHA: ${{ github.event.pull_request.base.sha || github.sha }} - VELNOR_WORKFLOW_POLICY_REVISION: b9c3156cdb88e63c11b9e595a3e694b02238c09a + VELNOR_WORKFLOW_POLICY_REVISION: 4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d run: | set -euo pipefail velnor-workflow policy \ --workflow-root "$WORKFLOW_ROOT" \ --head-sha "$HEAD_SHA" \ --base-sha "$BASE_SHA" \ + --candidate-manifest "${VELNOR_WORKFLOW_CANDIDATE_MANIFEST:-}" \ --ruleset-contexts "$RULESET_CONTEXTS" + - name: Set up actionlint uses: jdx/mise-action@c2a87611a18de5b3828c5652fe268e992400cb5c # v4.3.0 with: @@ -216,10 +220,12 @@ jobs: cache: false - name: Lint caller workflows working-directory: policy-checkout + env: + MISE_NO_CONFIG: "1" run: mise exec actionlint@1.7.12 -- actionlint github-docker-tools-fixtures-docker: name: "Docker · Docker (tools/fixtures/docker)" - if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',docker-tools-fixtures-docker,') }} + if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',docker-tools-fixtures-docker,') && (github.event_name == 'pull_request' || (github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'github' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan, policy] uses: ./.github/workflows/ci-unit-docker.yml with: @@ -230,9 +236,10 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} + unit_admission: github velnor-docker-tools-fixtures-docker: name: "Docker · Docker (tools/fixtures/docker)" - if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',docker-tools-fixtures-docker,') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }} + if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',docker-tools-fixtures-docker,') && ((github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'velnor' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan, policy] uses: ./.github/workflows/ci-unit-docker.yml with: @@ -243,9 +250,10 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} + unit_admission: velnor prepare-cargo: name: "Control / Prepare Cargo" - if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-policy,') }} + if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && (contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-agent,') || contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-cli,') || contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-core,') || contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-proto,') || contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-spec-extract,')) && ((github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'velnor' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan, policy] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -258,7 +266,7 @@ jobs: head_sha: ${{ needs.plan.outputs.head_sha }} github-rust-policy: name: "Rust · Rust dependency policy" - if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-policy,') }} + if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-policy,') && (github.event_name == 'pull_request' || (github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'github' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan, policy] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -269,7 +277,8 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} - mbx_compat: db4503222bd1 + mbx_enabled: true + mbx_compat: e580b6b474e3 mbx_dependency_files: | .cargo/** Cargo.lock @@ -289,9 +298,10 @@ jobs: Cargo.lock rust-toolchain.toml rust-toolchain + unit_admission: github velnor-rust-policy: name: "Rust · Rust dependency policy" - if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && (needs.prepare-cargo.result == 'success' || needs.prepare-cargo.result == 'skipped') && contains(format(',{0},', needs.plan.outputs.units), ',rust-policy,') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }} + if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && (needs.prepare-cargo.result == 'success' || needs.prepare-cargo.result == 'skipped') && contains(format(',{0},', needs.plan.outputs.units), ',rust-policy,') && ((github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'velnor' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan, policy, prepare-cargo] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -303,10 +313,12 @@ jobs: base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} mise_tools: "cargo:cargo-deny" + mbx_enabled: true host_warm_layers: "rustup,mold,mbx,cargo" + unit_admission: velnor github-rust-ruxel-agent: name: "Rust · ruxel-agent" - if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-agent,') }} + if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-agent,') && (github.event_name == 'pull_request' || (github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'github' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan, policy] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -317,7 +329,8 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} - mbx_compat: e77e749f2fa1 + mbx_enabled: true + mbx_compat: d993edda3b29 mbx_dependency_files: | .cargo/** Cargo.lock @@ -351,9 +364,11 @@ jobs: rust-toolchain cargo_root: "crates/ruxel-agent" cargo_net_offline: true + unit_dependencies: "rust-ruxel-core,rust-ruxel-proto" + unit_admission: github velnor-rust-ruxel-agent: name: "Rust · ruxel-agent" - if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && (needs.prepare-cargo.result == 'success' || needs.prepare-cargo.result == 'skipped') && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-agent,') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }} + if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && (needs.prepare-cargo.result == 'success' || needs.prepare-cargo.result == 'skipped') && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-agent,') && ((github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'velnor' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan, policy, prepare-cargo] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -364,11 +379,14 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} + mbx_enabled: true cargo_net_offline: true host_warm_layers: "rustup,mold,mbx,cargo" + unit_dependencies: "rust-ruxel-core,rust-ruxel-proto" + unit_admission: velnor github-rust-ruxel-cli: name: "Rust · ruxel-cli" - if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-cli,') }} + if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-cli,') && (github.event_name == 'pull_request' || (github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'github' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan, policy] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -379,7 +397,8 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} - mbx_compat: c86d78a667f8 + mbx_enabled: true + mbx_compat: a6d6c2999a1c mbx_dependency_files: | .cargo/** Cargo.lock @@ -414,9 +433,11 @@ jobs: rust-toolchain cargo_root: "crates/ruxel" cargo_net_offline: true + unit_dependencies: "rust-ruxel-core,rust-ruxel-proto" + unit_admission: github velnor-rust-ruxel-cli: name: "Rust · ruxel-cli" - if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && (needs.prepare-cargo.result == 'success' || needs.prepare-cargo.result == 'skipped') && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-cli,') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }} + if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && (needs.prepare-cargo.result == 'success' || needs.prepare-cargo.result == 'skipped') && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-cli,') && ((github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'velnor' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan, policy, prepare-cargo] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -427,11 +448,14 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} + mbx_enabled: true cargo_net_offline: true host_warm_layers: "rustup,mold,mbx,cargo" + unit_dependencies: "rust-ruxel-core,rust-ruxel-proto" + unit_admission: velnor github-rust-ruxel-core: name: "Rust · ruxel-core" - if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-core,') }} + if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-core,') && (github.event_name == 'pull_request' || (github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'github' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan, policy] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -442,7 +466,8 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} - mbx_compat: "213494d9a3ca" + mbx_enabled: true + mbx_compat: "2feaec27fe95" mbx_dependency_files: | .cargo/** Cargo.lock @@ -465,9 +490,10 @@ jobs: rust-toolchain cargo_root: "crates/ruxel-core" cargo_net_offline: true + unit_admission: github velnor-rust-ruxel-core: name: "Rust · ruxel-core" - if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && (needs.prepare-cargo.result == 'success' || needs.prepare-cargo.result == 'skipped') && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-core,') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }} + if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && (needs.prepare-cargo.result == 'success' || needs.prepare-cargo.result == 'skipped') && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-core,') && ((github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'velnor' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan, policy, prepare-cargo] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -478,11 +504,13 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} + mbx_enabled: true cargo_net_offline: true host_warm_layers: "rustup,mold,mbx,cargo" + unit_admission: velnor github-rust-ruxel-proto: name: "Rust · ruxel-proto" - if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-proto,') }} + if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-proto,') && (github.event_name == 'pull_request' || (github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'github' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan, policy] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -493,7 +521,8 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} - mbx_compat: "42c27a4a45de" + mbx_enabled: true + mbx_compat: "30f4a7d2f856" mbx_dependency_files: | .cargo/** Cargo.lock @@ -517,9 +546,10 @@ jobs: rust-toolchain cargo_root: "crates/ruxel-proto" cargo_net_offline: true + unit_admission: github velnor-rust-ruxel-proto: name: "Rust · ruxel-proto" - if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && (needs.prepare-cargo.result == 'success' || needs.prepare-cargo.result == 'skipped') && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-proto,') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }} + if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && (needs.prepare-cargo.result == 'success' || needs.prepare-cargo.result == 'skipped') && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-proto,') && ((github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'velnor' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan, policy, prepare-cargo] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -530,11 +560,13 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} + mbx_enabled: true cargo_net_offline: true host_warm_layers: "rustup,mold,mbx,cargo" + unit_admission: velnor github-rust-ruxel-spec-extract: name: "Rust · ruxel-spec-extract" - if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-spec-extract,') }} + if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-spec-extract,') && (github.event_name == 'pull_request' || (github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'github' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan, policy] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -545,7 +577,8 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} - mbx_compat: dec8a5b0fa6f + mbx_enabled: true + mbx_compat: c41351c822c3 mbx_dependency_files: | .cargo/** Cargo.lock @@ -573,9 +606,11 @@ jobs: rust-toolchain cargo_root: "tools/spec-extract" cargo_net_offline: true + unit_dependencies: rust-ruxel-core + unit_admission: github velnor-rust-ruxel-spec-extract: name: "Rust · ruxel-spec-extract" - if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && (needs.prepare-cargo.result == 'success' || needs.prepare-cargo.result == 'skipped') && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-spec-extract,') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }} + if: ${{ always() && needs.plan.result == 'success' && needs.policy.result == 'success' && (needs.prepare-cargo.result == 'success' || needs.prepare-cargo.result == 'skipped') && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-spec-extract,') && ((github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'velnor' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan, policy, prepare-cargo] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -586,8 +621,11 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} + mbx_enabled: true cargo_net_offline: true host_warm_layers: "rustup,mold,mbx,cargo" + unit_dependencies: rust-ruxel-core + unit_admission: velnor ci-required: name: ci-required if: ${{ always() }} @@ -599,7 +637,8 @@ jobs: env: NEEDS_JSON: ${{ toJSON(needs) }} SELECTED_UNITS: ${{ needs.plan.outputs.units }} - FORK_PR: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository }} + LANE_ADMITTED_GITHUB: ${{ github.event_name == 'pull_request' || (github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'github' || github.event.inputs.runner == 'both' || github.event.inputs.runner == '')) }} + LANE_ADMITTED_VELNOR: ${{ (github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'velnor' || github.event.inputs.runner == 'both' || github.event.inputs.runner == '')) }} shell: bash run: | set -euo pipefail @@ -624,10 +663,17 @@ jobs: selected=",$SELECTED_UNITS," if [[ "$selected" == *",docker-tools-fixtures-docker,"* ]]; then result="$(result_for_job github-docker-tools-fixtures-docker)" - case "$result" in - success) ;; - *) echo "selected CI job github-docker-tools-fixtures-docker did not pass: $result" >&2; exit 1 ;; - esac + if [[ "$LANE_ADMITTED_GITHUB" == true ]]; then + case "$result" in + success) ;; + *) echo "selected CI job github-docker-tools-fixtures-docker did not pass: $result" >&2; exit 1 ;; + esac + else + case "$result" in + skipped) ;; + *) echo "selected CI job github-docker-tools-fixtures-docker ran outside its lane admission (LANE_ADMITTED_GITHUB=$LANE_ADMITTED_GITHUB): $result" >&2; exit 1 ;; + esac + fi else result="$(result_for_job github-docker-tools-fixtures-docker)" case "$result" in @@ -637,15 +683,15 @@ jobs: fi if [[ "$selected" == *",docker-tools-fixtures-docker,"* ]]; then result="$(result_for_job velnor-docker-tools-fixtures-docker)" - if [[ "$FORK_PR" == true ]]; then + if [[ "$LANE_ADMITTED_VELNOR" == true ]]; then case "$result" in - success|skipped) ;; + success) ;; *) echo "selected CI job velnor-docker-tools-fixtures-docker did not pass: $result" >&2; exit 1 ;; esac else case "$result" in - success) ;; - *) echo "selected CI job velnor-docker-tools-fixtures-docker did not pass: $result" >&2; exit 1 ;; + skipped) ;; + *) echo "selected CI job velnor-docker-tools-fixtures-docker ran outside its lane admission (LANE_ADMITTED_VELNOR=$LANE_ADMITTED_VELNOR): $result" >&2; exit 1 ;; esac fi else @@ -655,11 +701,18 @@ jobs: *) echo "unselected CI job velnor-docker-tools-fixtures-docker failed unexpectedly: $result" >&2; exit 1 ;; esac fi - if [[ "$selected" == *",rust-policy,"* ]]; then + if [[ "$selected" == *",rust-ruxel-agent,"* || "$selected" == *",rust-ruxel-cli,"* || "$selected" == *",rust-ruxel-core,"* || "$selected" == *",rust-ruxel-proto,"* || "$selected" == *",rust-ruxel-spec-extract,"* ]]; then result="$(result_for_job prepare-cargo)" - if [[ "$result" != success ]]; then - echo "selected CI prerequisite prepare-cargo did not pass: $result" >&2 - exit 1 + if [[ "$LANE_ADMITTED_VELNOR" == true ]]; then + case "$result" in + success) ;; + *) echo "selected CI prerequisite prepare-cargo did not pass: $result" >&2; exit 1 ;; + esac + else + case "$result" in + skipped) ;; + *) echo "selected CI prerequisite prepare-cargo ran outside its lane admission (LANE_ADMITTED_VELNOR=$LANE_ADMITTED_VELNOR): $result" >&2; exit 1 ;; + esac fi else result="$(result_for_job prepare-cargo)" @@ -670,10 +723,17 @@ jobs: fi if [[ "$selected" == *",rust-policy,"* ]]; then result="$(result_for_job github-rust-policy)" - case "$result" in - success) ;; - *) echo "selected CI job github-rust-policy did not pass: $result" >&2; exit 1 ;; - esac + if [[ "$LANE_ADMITTED_GITHUB" == true ]]; then + case "$result" in + success) ;; + *) echo "selected CI job github-rust-policy did not pass: $result" >&2; exit 1 ;; + esac + else + case "$result" in + skipped) ;; + *) echo "selected CI job github-rust-policy ran outside its lane admission (LANE_ADMITTED_GITHUB=$LANE_ADMITTED_GITHUB): $result" >&2; exit 1 ;; + esac + fi else result="$(result_for_job github-rust-policy)" case "$result" in @@ -683,15 +743,15 @@ jobs: fi if [[ "$selected" == *",rust-policy,"* ]]; then result="$(result_for_job velnor-rust-policy)" - if [[ "$FORK_PR" == true ]]; then + if [[ "$LANE_ADMITTED_VELNOR" == true ]]; then case "$result" in - success|skipped) ;; + success) ;; *) echo "selected CI job velnor-rust-policy did not pass: $result" >&2; exit 1 ;; esac else case "$result" in - success) ;; - *) echo "selected CI job velnor-rust-policy did not pass: $result" >&2; exit 1 ;; + skipped) ;; + *) echo "selected CI job velnor-rust-policy ran outside its lane admission (LANE_ADMITTED_VELNOR=$LANE_ADMITTED_VELNOR): $result" >&2; exit 1 ;; esac fi else @@ -703,10 +763,17 @@ jobs: fi if [[ "$selected" == *",rust-ruxel-agent,"* ]]; then result="$(result_for_job github-rust-ruxel-agent)" - case "$result" in - success) ;; - *) echo "selected CI job github-rust-ruxel-agent did not pass: $result" >&2; exit 1 ;; - esac + if [[ "$LANE_ADMITTED_GITHUB" == true ]]; then + case "$result" in + success) ;; + *) echo "selected CI job github-rust-ruxel-agent did not pass: $result" >&2; exit 1 ;; + esac + else + case "$result" in + skipped) ;; + *) echo "selected CI job github-rust-ruxel-agent ran outside its lane admission (LANE_ADMITTED_GITHUB=$LANE_ADMITTED_GITHUB): $result" >&2; exit 1 ;; + esac + fi else result="$(result_for_job github-rust-ruxel-agent)" case "$result" in @@ -716,15 +783,15 @@ jobs: fi if [[ "$selected" == *",rust-ruxel-agent,"* ]]; then result="$(result_for_job velnor-rust-ruxel-agent)" - if [[ "$FORK_PR" == true ]]; then + if [[ "$LANE_ADMITTED_VELNOR" == true ]]; then case "$result" in - success|skipped) ;; + success) ;; *) echo "selected CI job velnor-rust-ruxel-agent did not pass: $result" >&2; exit 1 ;; esac else case "$result" in - success) ;; - *) echo "selected CI job velnor-rust-ruxel-agent did not pass: $result" >&2; exit 1 ;; + skipped) ;; + *) echo "selected CI job velnor-rust-ruxel-agent ran outside its lane admission (LANE_ADMITTED_VELNOR=$LANE_ADMITTED_VELNOR): $result" >&2; exit 1 ;; esac fi else @@ -736,10 +803,17 @@ jobs: fi if [[ "$selected" == *",rust-ruxel-cli,"* ]]; then result="$(result_for_job github-rust-ruxel-cli)" - case "$result" in - success) ;; - *) echo "selected CI job github-rust-ruxel-cli did not pass: $result" >&2; exit 1 ;; - esac + if [[ "$LANE_ADMITTED_GITHUB" == true ]]; then + case "$result" in + success) ;; + *) echo "selected CI job github-rust-ruxel-cli did not pass: $result" >&2; exit 1 ;; + esac + else + case "$result" in + skipped) ;; + *) echo "selected CI job github-rust-ruxel-cli ran outside its lane admission (LANE_ADMITTED_GITHUB=$LANE_ADMITTED_GITHUB): $result" >&2; exit 1 ;; + esac + fi else result="$(result_for_job github-rust-ruxel-cli)" case "$result" in @@ -749,15 +823,15 @@ jobs: fi if [[ "$selected" == *",rust-ruxel-cli,"* ]]; then result="$(result_for_job velnor-rust-ruxel-cli)" - if [[ "$FORK_PR" == true ]]; then + if [[ "$LANE_ADMITTED_VELNOR" == true ]]; then case "$result" in - success|skipped) ;; + success) ;; *) echo "selected CI job velnor-rust-ruxel-cli did not pass: $result" >&2; exit 1 ;; esac else case "$result" in - success) ;; - *) echo "selected CI job velnor-rust-ruxel-cli did not pass: $result" >&2; exit 1 ;; + skipped) ;; + *) echo "selected CI job velnor-rust-ruxel-cli ran outside its lane admission (LANE_ADMITTED_VELNOR=$LANE_ADMITTED_VELNOR): $result" >&2; exit 1 ;; esac fi else @@ -769,10 +843,17 @@ jobs: fi if [[ "$selected" == *",rust-ruxel-core,"* ]]; then result="$(result_for_job github-rust-ruxel-core)" - case "$result" in - success) ;; - *) echo "selected CI job github-rust-ruxel-core did not pass: $result" >&2; exit 1 ;; - esac + if [[ "$LANE_ADMITTED_GITHUB" == true ]]; then + case "$result" in + success) ;; + *) echo "selected CI job github-rust-ruxel-core did not pass: $result" >&2; exit 1 ;; + esac + else + case "$result" in + skipped) ;; + *) echo "selected CI job github-rust-ruxel-core ran outside its lane admission (LANE_ADMITTED_GITHUB=$LANE_ADMITTED_GITHUB): $result" >&2; exit 1 ;; + esac + fi else result="$(result_for_job github-rust-ruxel-core)" case "$result" in @@ -782,15 +863,15 @@ jobs: fi if [[ "$selected" == *",rust-ruxel-core,"* ]]; then result="$(result_for_job velnor-rust-ruxel-core)" - if [[ "$FORK_PR" == true ]]; then + if [[ "$LANE_ADMITTED_VELNOR" == true ]]; then case "$result" in - success|skipped) ;; + success) ;; *) echo "selected CI job velnor-rust-ruxel-core did not pass: $result" >&2; exit 1 ;; esac else case "$result" in - success) ;; - *) echo "selected CI job velnor-rust-ruxel-core did not pass: $result" >&2; exit 1 ;; + skipped) ;; + *) echo "selected CI job velnor-rust-ruxel-core ran outside its lane admission (LANE_ADMITTED_VELNOR=$LANE_ADMITTED_VELNOR): $result" >&2; exit 1 ;; esac fi else @@ -802,10 +883,17 @@ jobs: fi if [[ "$selected" == *",rust-ruxel-proto,"* ]]; then result="$(result_for_job github-rust-ruxel-proto)" - case "$result" in - success) ;; - *) echo "selected CI job github-rust-ruxel-proto did not pass: $result" >&2; exit 1 ;; - esac + if [[ "$LANE_ADMITTED_GITHUB" == true ]]; then + case "$result" in + success) ;; + *) echo "selected CI job github-rust-ruxel-proto did not pass: $result" >&2; exit 1 ;; + esac + else + case "$result" in + skipped) ;; + *) echo "selected CI job github-rust-ruxel-proto ran outside its lane admission (LANE_ADMITTED_GITHUB=$LANE_ADMITTED_GITHUB): $result" >&2; exit 1 ;; + esac + fi else result="$(result_for_job github-rust-ruxel-proto)" case "$result" in @@ -815,15 +903,15 @@ jobs: fi if [[ "$selected" == *",rust-ruxel-proto,"* ]]; then result="$(result_for_job velnor-rust-ruxel-proto)" - if [[ "$FORK_PR" == true ]]; then + if [[ "$LANE_ADMITTED_VELNOR" == true ]]; then case "$result" in - success|skipped) ;; + success) ;; *) echo "selected CI job velnor-rust-ruxel-proto did not pass: $result" >&2; exit 1 ;; esac else case "$result" in - success) ;; - *) echo "selected CI job velnor-rust-ruxel-proto did not pass: $result" >&2; exit 1 ;; + skipped) ;; + *) echo "selected CI job velnor-rust-ruxel-proto ran outside its lane admission (LANE_ADMITTED_VELNOR=$LANE_ADMITTED_VELNOR): $result" >&2; exit 1 ;; esac fi else @@ -835,10 +923,17 @@ jobs: fi if [[ "$selected" == *",rust-ruxel-spec-extract,"* ]]; then result="$(result_for_job github-rust-ruxel-spec-extract)" - case "$result" in - success) ;; - *) echo "selected CI job github-rust-ruxel-spec-extract did not pass: $result" >&2; exit 1 ;; - esac + if [[ "$LANE_ADMITTED_GITHUB" == true ]]; then + case "$result" in + success) ;; + *) echo "selected CI job github-rust-ruxel-spec-extract did not pass: $result" >&2; exit 1 ;; + esac + else + case "$result" in + skipped) ;; + *) echo "selected CI job github-rust-ruxel-spec-extract ran outside its lane admission (LANE_ADMITTED_GITHUB=$LANE_ADMITTED_GITHUB): $result" >&2; exit 1 ;; + esac + fi else result="$(result_for_job github-rust-ruxel-spec-extract)" case "$result" in @@ -848,15 +943,15 @@ jobs: fi if [[ "$selected" == *",rust-ruxel-spec-extract,"* ]]; then result="$(result_for_job velnor-rust-ruxel-spec-extract)" - if [[ "$FORK_PR" == true ]]; then + if [[ "$LANE_ADMITTED_VELNOR" == true ]]; then case "$result" in - success|skipped) ;; + success) ;; *) echo "selected CI job velnor-rust-ruxel-spec-extract did not pass: $result" >&2; exit 1 ;; esac else case "$result" in - success) ;; - *) echo "selected CI job velnor-rust-ruxel-spec-extract did not pass: $result" >&2; exit 1 ;; + skipped) ;; + *) echo "selected CI job velnor-rust-ruxel-spec-extract ran outside its lane admission (LANE_ADMITTED_VELNOR=$LANE_ADMITTED_VELNOR): $result" >&2; exit 1 ;; esac fi else diff --git a/.github/workflows/ci-policy.yml b/.github/workflows/ci-policy.yml index 8d15612..592c98a 100644 --- a/.github/workflows/ci-policy.yml +++ b/.github/workflows/ci-policy.yml @@ -18,11 +18,16 @@ jobs: name: Policy runs-on: ubuntu-24.04 timeout-minutes: 20 - # Trust invariant: this job runs the base branch's validator against the - # audited tree under pull_request_target. It holds `contents: read` only, - # references no secrets, and its checkout persists no credentials, so - # building and running the tree's declared generator here is no more - # privileged than the pull_request lanes that already build the tree. + # Trust invariant: this job runs the base branch's Stage-0 validator + # product against the audited tree under pull_request_target. It holds + # `contents: read` only, references no secrets, persists no credentials, + # and never compiles. When the audited tree differs from the declared + # pin's render, it additionally EXECUTES the PR run's prebuilt + # candidate generator — PR-built code, same-repository runs only, bound + # to the audited tree by manifest closure plus binary digest before + # execution — with no secret references, no persisted credentials, the + # read-only github.token confined to the Acquire/Ruleset API steps, + # and both candidate exec points tokenless. permissions: contents: read steps: @@ -43,39 +48,34 @@ jobs: git fetch --no-tags "$GITHUB_SERVER_URL/$HEAD_REPOSITORY" "$HEAD_SHA" fi git checkout --quiet --detach "$HEAD_SHA" - - name: Bound the Mr. Boxington store - shell: bash - run: echo "MBX_GC_MAX_SIZE=12GiB" >> "$GITHUB_ENV" - - name: Set up Mr. Boxington - uses: jdx/mr-boxington-action@7234d3dd1a6ca8f6c381eea8e4dfb03f18fcf777 # v1.3.0 + - name: Set up Velnor workflow runtime + uses: tailrocks/velnor/.github/actions/setup-velnor-workflow@4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d with: - backend: github - version: 1.11.1 - cache-key: velnor-policy-mbx-1.11.1-${{ runner.os }}-${{ runner.arch }}-b9c3156cdb88e63c11b9e595a3e694b02238c09a - restore-keys: | - velnor-policy-mbx-1.11.1-${{ runner.os }}-${{ runner.arch }}- - - name: Install pinned Velnor workflow runtime - env: - CARGO_HOME: ${{ runner.temp }}/velnor-workflow-cargo-home - CARGO_TARGET_DIR: ${{ runner.temp }}/velnor-workflow-cargo-target - VELNOR_WORKFLOW_INSTALL_DIR: ${{ runner.temp }}/velnor-workflow-install - VELNOR_WORKFLOW_ROOT: ${{ runner.temp }}/velnor-workflow + rev: 4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d + checkout-path: ${{ github.workspace }}/policy-checkout + - name: Read declared generator pin + id: pin + working-directory: policy-checkout run: | set -euo pipefail - install -d -m 700 \ - "$CARGO_HOME" \ - "$CARGO_TARGET_DIR" \ - "$VELNOR_WORKFLOW_INSTALL_DIR" - cd "$VELNOR_WORKFLOW_INSTALL_DIR" - env -u RUSTC_WRAPPER -u SCCACHE_GHA_ENABLED -u CARGO_INCREMENTAL -u RUSTFLAGS -u CARGO_ENCODED_RUSTFLAGS \ - cargo install \ - --locked \ - --git https://github.com/tailrocks/velnor \ - --rev b9c3156cdb88e63c11b9e595a3e694b02238c09a \ - --root "$VELNOR_WORKFLOW_ROOT" \ - velnor-workflow \ - --bin velnor-workflow - echo "$VELNOR_WORKFLOW_ROOT/bin" >> "$GITHUB_PATH" + pin="$(sed -n -E 's/^[[:space:]]*revision[[:space:]]*=[[:space:]]*"([0-9a-f]{40})".*/\1/p' .github-gen/velnor-workflow.toml | head -n 1)" + test "$pin" != '' || pin="$(sed -n -E 's/^.*VELNOR_WORKFLOW_POLICY_REVISION:[[:space:]]*([0-9a-f]{40}).*/\1/p' .github/workflows/ci-policy.yml | head -n 1)" + test "$pin" != '' || { echo "::error::audited tree declares no generator pin" >&2; exit 1; } + echo "value=$pin" >> "$GITHUB_OUTPUT" + - name: Set up declared generator product + id: renderer + if: steps.pin.outputs.value != '4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d' + uses: tailrocks/velnor/.github/actions/setup-velnor-workflow@4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d + with: + rev: ${{ steps.pin.outputs.value }} + checkout-path: ${{ github.workspace }}/policy-checkout + - name: Resolve declared generator product + if: steps.pin.outputs.value != '4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d' + run: | + set -euo pipefail + binary="$HOME/.cache/velnor/workflow-runtime/${{ steps.renderer.outputs.closure }}/bin/velnor-workflow" + test -x "$binary" + echo "VELNOR_WORKFLOW_PINNED_BINARY=$binary" >> "$GITHUB_ENV" - name: Resolve required status checks env: GH_TOKEN: ${{ github.token }} @@ -104,14 +104,16 @@ jobs: WORKFLOW_ROOT: ${{ github.workspace }}/policy-checkout HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} BASE_SHA: ${{ github.event.pull_request.base.sha || github.sha }} - VELNOR_WORKFLOW_POLICY_REVISION: b9c3156cdb88e63c11b9e595a3e694b02238c09a + VELNOR_WORKFLOW_POLICY_REVISION: 4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d run: | set -euo pipefail velnor-workflow policy \ --workflow-root "$WORKFLOW_ROOT" \ --head-sha "$HEAD_SHA" \ --base-sha "$BASE_SHA" \ + --candidate-manifest "${VELNOR_WORKFLOW_CANDIDATE_MANIFEST:-}" \ --ruleset-contexts "$RULESET_CONTEXTS" + - name: Set up actionlint uses: jdx/mise-action@c2a87611a18de5b3828c5652fe268e992400cb5c # v4.3.0 with: @@ -119,4 +121,6 @@ jobs: cache: false - name: Lint caller workflows working-directory: policy-checkout + env: + MISE_NO_CONFIG: "1" run: mise exec actionlint@1.7.12 -- actionlint diff --git a/.github/workflows/ci-pr.yml b/.github/workflows/ci-pr.yml index eb74621..93e7afc 100644 --- a/.github/workflows/ci-pr.yml +++ b/.github/workflows/ci-pr.yml @@ -57,12 +57,13 @@ jobs: fetch-depth: 0 persist-credentials: false - name: Set up Velnor workflow runtime + id: runtime if: ${{ runner.environment == 'github-hosted' }} - uses: tailrocks/velnor/.github/actions/setup-velnor-workflow@b9c3156cdb88e63c11b9e595a3e694b02238c09a + uses: tailrocks/velnor/.github/actions/setup-velnor-workflow@4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d with: - rev: b9c3156cdb88e63c11b9e595a3e694b02238c09a + rev: 4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d - name: Set trusted workflow policy revision - run: echo "VELNOR_WORKFLOW_POLICY_REVISION=b9c3156cdb88e63c11b9e595a3e694b02238c09a" >> "$GITHUB_ENV" + run: echo "VELNOR_WORKFLOW_POLICY_REVISION=4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d" >> "$GITHUB_ENV" - name: Select affected units id: plan env: @@ -79,7 +80,7 @@ jobs: - name: Prepare Velnor workflow runtime shell: bash env: - EXPECTED_REVISION: b9c3156cdb88e63c11b9e595a3e694b02238c09a + EXPECTED_REVISION: 4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d run: | set -euo pipefail stage="$RUNNER_TEMP/velnor-workflow-runtime" @@ -91,13 +92,14 @@ jobs: policy_src="${VELNOR_WORKFLOW_PINNED_BINARY:-$src}" install -m 0755 "$policy_src" "$stage/velnor-workflow-policy" policy_revision="$("$stage/velnor-workflow-policy" --revision)" - [[ "$policy_revision" == "$EXPECTED_REVISION" ]] || { echo "::error::policy runtime reports revision $policy_revision, expected $EXPECTED_REVISION" >&2; exit 1; } + policy_closure="$("$stage/velnor-workflow-policy" --closure)" + [[ "$policy_closure" == "${{ steps.runtime.outputs.closure }}" ]] || { echo "::error::policy runtime reports closure $policy_closure, expected ${{ steps.runtime.outputs.closure }}" >&2; exit 1; } policy_digest="$(sha256sum "$stage/velnor-workflow-policy" | awk '{print $1}')" - jq -n --arg repository "$GITHUB_REPOSITORY" --arg revision "$EXPECTED_REVISION" --arg head_branch "${{ github.ref_name }}" --arg platform "${{ runner.os }}-${{ runner.arch }}" --arg run_id "$GITHUB_RUN_ID" --arg job_id "${{ github.job }}" --arg binary_sha256 "$digest" --arg policy_revision "$policy_revision" --arg policy_binary_sha256 "$policy_digest" '{repository: $repository, revision: $revision, head_branch: $head_branch, platform: $platform, run_id: $run_id, job_id: $job_id, binary_sha256: $binary_sha256, policy_revision: $policy_revision, policy_binary_sha256: $policy_binary_sha256}' > "$stage/manifest.json" + jq -n --arg repository "$GITHUB_REPOSITORY" --arg revision "$EXPECTED_REVISION" --arg closure "${{ steps.runtime.outputs.closure }}" --arg head_branch "${{ github.ref_name }}" --arg platform "${{ runner.os }}-${{ runner.arch }}" --arg run_id "$GITHUB_RUN_ID" --arg job_id "${{ github.job }}" --arg binary_sha256 "$digest" --arg policy_revision "$policy_revision" --arg policy_closure "$policy_closure" --arg policy_binary_sha256 "$policy_digest" '{repository: $repository, revision: $revision, closure: $closure, head_branch: $head_branch, platform: $platform, run_id: $run_id, job_id: $job_id, binary_sha256: $binary_sha256, policy_revision: $policy_revision, policy_closure: $policy_closure, policy_binary_sha256: $policy_binary_sha256}' > "$stage/manifest.json" - name: Publish Velnor workflow runtime uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: velnor-workflow-runtime-b9c3156cdb88e63c11b9e595a3e694b02238c09a-${{ runner.os }}-${{ runner.arch }} + name: velnor-workflow-runtime-4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d-${{ runner.os }}-${{ runner.arch }} path: ${{ runner.temp }}/velnor-workflow-runtime if-no-files-found: error retention-days: 7 @@ -112,7 +114,7 @@ jobs: echo '::notice::Velnor lane omitted for fork pull request; validating GitHub lane only.' github-docker-tools-fixtures-docker: name: "Docker · Docker (tools/fixtures/docker)" - if: ${{ always() && needs.plan.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',docker-tools-fixtures-docker,') }} + if: ${{ always() && needs.plan.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',docker-tools-fixtures-docker,') && (github.event_name == 'pull_request' || (github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'github' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan] uses: ./.github/workflows/ci-unit-docker.yml with: @@ -123,9 +125,10 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} + unit_admission: github velnor-docker-tools-fixtures-docker: name: "Docker · Docker (tools/fixtures/docker)" - if: ${{ always() && needs.plan.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',docker-tools-fixtures-docker,') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }} + if: ${{ always() && needs.plan.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',docker-tools-fixtures-docker,') && ((github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'velnor' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan] uses: ./.github/workflows/ci-unit-docker.yml with: @@ -136,9 +139,10 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} + unit_admission: velnor prepare-cargo: name: "Control / Prepare Cargo" - if: ${{ always() && needs.plan.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-policy,') }} + if: ${{ always() && needs.plan.result == 'success' && (contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-agent,') || contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-cli,') || contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-core,') || contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-proto,') || contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-spec-extract,')) && ((github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'velnor' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -151,7 +155,7 @@ jobs: head_sha: ${{ needs.plan.outputs.head_sha }} github-rust-policy: name: "Rust · Rust dependency policy" - if: ${{ always() && needs.plan.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-policy,') }} + if: ${{ always() && needs.plan.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-policy,') && (github.event_name == 'pull_request' || (github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'github' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -162,7 +166,8 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} - mbx_compat: db4503222bd1 + mbx_enabled: true + mbx_compat: e580b6b474e3 mbx_dependency_files: | .cargo/** Cargo.lock @@ -182,9 +187,10 @@ jobs: Cargo.lock rust-toolchain.toml rust-toolchain + unit_admission: github velnor-rust-policy: name: "Rust · Rust dependency policy" - if: ${{ always() && needs.plan.result == 'success' && (needs.prepare-cargo.result == 'success' || needs.prepare-cargo.result == 'skipped') && contains(format(',{0},', needs.plan.outputs.units), ',rust-policy,') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }} + if: ${{ always() && needs.plan.result == 'success' && (needs.prepare-cargo.result == 'success' || needs.prepare-cargo.result == 'skipped') && contains(format(',{0},', needs.plan.outputs.units), ',rust-policy,') && ((github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'velnor' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan, prepare-cargo] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -196,10 +202,12 @@ jobs: base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} mise_tools: "cargo:cargo-deny" + mbx_enabled: true host_warm_layers: "rustup,mold,mbx,cargo" + unit_admission: velnor github-rust-ruxel-agent: name: "Rust · ruxel-agent" - if: ${{ always() && needs.plan.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-agent,') }} + if: ${{ always() && needs.plan.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-agent,') && (github.event_name == 'pull_request' || (github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'github' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -210,7 +218,8 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} - mbx_compat: e77e749f2fa1 + mbx_enabled: true + mbx_compat: d993edda3b29 mbx_dependency_files: | .cargo/** Cargo.lock @@ -244,9 +253,11 @@ jobs: rust-toolchain cargo_root: "crates/ruxel-agent" cargo_net_offline: true + unit_dependencies: "rust-ruxel-core,rust-ruxel-proto" + unit_admission: github velnor-rust-ruxel-agent: name: "Rust · ruxel-agent" - if: ${{ always() && needs.plan.result == 'success' && (needs.prepare-cargo.result == 'success' || needs.prepare-cargo.result == 'skipped') && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-agent,') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }} + if: ${{ always() && needs.plan.result == 'success' && (needs.prepare-cargo.result == 'success' || needs.prepare-cargo.result == 'skipped') && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-agent,') && ((github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'velnor' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan, prepare-cargo] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -257,11 +268,14 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} + mbx_enabled: true cargo_net_offline: true host_warm_layers: "rustup,mold,mbx,cargo" + unit_dependencies: "rust-ruxel-core,rust-ruxel-proto" + unit_admission: velnor github-rust-ruxel-cli: name: "Rust · ruxel-cli" - if: ${{ always() && needs.plan.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-cli,') }} + if: ${{ always() && needs.plan.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-cli,') && (github.event_name == 'pull_request' || (github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'github' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -272,7 +286,8 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} - mbx_compat: c86d78a667f8 + mbx_enabled: true + mbx_compat: a6d6c2999a1c mbx_dependency_files: | .cargo/** Cargo.lock @@ -307,9 +322,11 @@ jobs: rust-toolchain cargo_root: "crates/ruxel" cargo_net_offline: true + unit_dependencies: "rust-ruxel-core,rust-ruxel-proto" + unit_admission: github velnor-rust-ruxel-cli: name: "Rust · ruxel-cli" - if: ${{ always() && needs.plan.result == 'success' && (needs.prepare-cargo.result == 'success' || needs.prepare-cargo.result == 'skipped') && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-cli,') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }} + if: ${{ always() && needs.plan.result == 'success' && (needs.prepare-cargo.result == 'success' || needs.prepare-cargo.result == 'skipped') && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-cli,') && ((github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'velnor' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan, prepare-cargo] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -320,11 +337,14 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} + mbx_enabled: true cargo_net_offline: true host_warm_layers: "rustup,mold,mbx,cargo" + unit_dependencies: "rust-ruxel-core,rust-ruxel-proto" + unit_admission: velnor github-rust-ruxel-core: name: "Rust · ruxel-core" - if: ${{ always() && needs.plan.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-core,') }} + if: ${{ always() && needs.plan.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-core,') && (github.event_name == 'pull_request' || (github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'github' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -335,7 +355,8 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} - mbx_compat: "213494d9a3ca" + mbx_enabled: true + mbx_compat: "2feaec27fe95" mbx_dependency_files: | .cargo/** Cargo.lock @@ -358,9 +379,10 @@ jobs: rust-toolchain cargo_root: "crates/ruxel-core" cargo_net_offline: true + unit_admission: github velnor-rust-ruxel-core: name: "Rust · ruxel-core" - if: ${{ always() && needs.plan.result == 'success' && (needs.prepare-cargo.result == 'success' || needs.prepare-cargo.result == 'skipped') && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-core,') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }} + if: ${{ always() && needs.plan.result == 'success' && (needs.prepare-cargo.result == 'success' || needs.prepare-cargo.result == 'skipped') && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-core,') && ((github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'velnor' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan, prepare-cargo] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -371,11 +393,13 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} + mbx_enabled: true cargo_net_offline: true host_warm_layers: "rustup,mold,mbx,cargo" + unit_admission: velnor github-rust-ruxel-proto: name: "Rust · ruxel-proto" - if: ${{ always() && needs.plan.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-proto,') }} + if: ${{ always() && needs.plan.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-proto,') && (github.event_name == 'pull_request' || (github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'github' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -386,7 +410,8 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} - mbx_compat: "42c27a4a45de" + mbx_enabled: true + mbx_compat: "30f4a7d2f856" mbx_dependency_files: | .cargo/** Cargo.lock @@ -410,9 +435,10 @@ jobs: rust-toolchain cargo_root: "crates/ruxel-proto" cargo_net_offline: true + unit_admission: github velnor-rust-ruxel-proto: name: "Rust · ruxel-proto" - if: ${{ always() && needs.plan.result == 'success' && (needs.prepare-cargo.result == 'success' || needs.prepare-cargo.result == 'skipped') && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-proto,') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }} + if: ${{ always() && needs.plan.result == 'success' && (needs.prepare-cargo.result == 'success' || needs.prepare-cargo.result == 'skipped') && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-proto,') && ((github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'velnor' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan, prepare-cargo] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -423,11 +449,13 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} + mbx_enabled: true cargo_net_offline: true host_warm_layers: "rustup,mold,mbx,cargo" + unit_admission: velnor github-rust-ruxel-spec-extract: name: "Rust · ruxel-spec-extract" - if: ${{ always() && needs.plan.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-spec-extract,') }} + if: ${{ always() && needs.plan.result == 'success' && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-spec-extract,') && (github.event_name == 'pull_request' || (github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'github' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -438,7 +466,8 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} - mbx_compat: dec8a5b0fa6f + mbx_enabled: true + mbx_compat: c41351c822c3 mbx_dependency_files: | .cargo/** Cargo.lock @@ -466,9 +495,11 @@ jobs: rust-toolchain cargo_root: "tools/spec-extract" cargo_net_offline: true + unit_dependencies: rust-ruxel-core + unit_admission: github velnor-rust-ruxel-spec-extract: name: "Rust · ruxel-spec-extract" - if: ${{ always() && needs.plan.result == 'success' && (needs.prepare-cargo.result == 'success' || needs.prepare-cargo.result == 'skipped') && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-spec-extract,') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }} + if: ${{ always() && needs.plan.result == 'success' && (needs.prepare-cargo.result == 'success' || needs.prepare-cargo.result == 'skipped') && contains(format(',{0},', needs.plan.outputs.units), ',rust-ruxel-spec-extract,') && ((github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'velnor' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} needs: [plan, prepare-cargo] uses: ./.github/workflows/ci-unit-rust.yml with: @@ -479,8 +510,11 @@ jobs: full_units: ${{ needs.plan.outputs.full_units }} base_sha: ${{ needs.plan.outputs.base_sha }} head_sha: ${{ needs.plan.outputs.head_sha }} + mbx_enabled: true cargo_net_offline: true host_warm_layers: "rustup,mold,mbx,cargo" + unit_dependencies: rust-ruxel-core + unit_admission: velnor ci-required: name: ci-required if: ${{ always() }} @@ -492,7 +526,8 @@ jobs: env: NEEDS_JSON: ${{ toJSON(needs) }} SELECTED_UNITS: ${{ needs.plan.outputs.units }} - FORK_PR: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository }} + LANE_ADMITTED_GITHUB: ${{ github.event_name == 'pull_request' || (github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'github' || github.event.inputs.runner == 'both' || github.event.inputs.runner == '')) }} + LANE_ADMITTED_VELNOR: ${{ (github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'velnor' || github.event.inputs.runner == 'both' || github.event.inputs.runner == '')) }} shell: bash run: | set -euo pipefail @@ -512,10 +547,17 @@ jobs: selected=",$SELECTED_UNITS," if [[ "$selected" == *",docker-tools-fixtures-docker,"* ]]; then result="$(result_for_job github-docker-tools-fixtures-docker)" - case "$result" in - success) ;; - *) echo "selected CI job github-docker-tools-fixtures-docker did not pass: $result" >&2; exit 1 ;; - esac + if [[ "$LANE_ADMITTED_GITHUB" == true ]]; then + case "$result" in + success) ;; + *) echo "selected CI job github-docker-tools-fixtures-docker did not pass: $result" >&2; exit 1 ;; + esac + else + case "$result" in + skipped) ;; + *) echo "selected CI job github-docker-tools-fixtures-docker ran outside its lane admission (LANE_ADMITTED_GITHUB=$LANE_ADMITTED_GITHUB): $result" >&2; exit 1 ;; + esac + fi else result="$(result_for_job github-docker-tools-fixtures-docker)" case "$result" in @@ -525,15 +567,15 @@ jobs: fi if [[ "$selected" == *",docker-tools-fixtures-docker,"* ]]; then result="$(result_for_job velnor-docker-tools-fixtures-docker)" - if [[ "$FORK_PR" == true ]]; then + if [[ "$LANE_ADMITTED_VELNOR" == true ]]; then case "$result" in - success|skipped) ;; + success) ;; *) echo "selected CI job velnor-docker-tools-fixtures-docker did not pass: $result" >&2; exit 1 ;; esac else case "$result" in - success) ;; - *) echo "selected CI job velnor-docker-tools-fixtures-docker did not pass: $result" >&2; exit 1 ;; + skipped) ;; + *) echo "selected CI job velnor-docker-tools-fixtures-docker ran outside its lane admission (LANE_ADMITTED_VELNOR=$LANE_ADMITTED_VELNOR): $result" >&2; exit 1 ;; esac fi else @@ -543,11 +585,18 @@ jobs: *) echo "unselected CI job velnor-docker-tools-fixtures-docker failed unexpectedly: $result" >&2; exit 1 ;; esac fi - if [[ "$selected" == *",rust-policy,"* ]]; then + if [[ "$selected" == *",rust-ruxel-agent,"* || "$selected" == *",rust-ruxel-cli,"* || "$selected" == *",rust-ruxel-core,"* || "$selected" == *",rust-ruxel-proto,"* || "$selected" == *",rust-ruxel-spec-extract,"* ]]; then result="$(result_for_job prepare-cargo)" - if [[ "$result" != success ]]; then - echo "selected CI prerequisite prepare-cargo did not pass: $result" >&2 - exit 1 + if [[ "$LANE_ADMITTED_VELNOR" == true ]]; then + case "$result" in + success) ;; + *) echo "selected CI prerequisite prepare-cargo did not pass: $result" >&2; exit 1 ;; + esac + else + case "$result" in + skipped) ;; + *) echo "selected CI prerequisite prepare-cargo ran outside its lane admission (LANE_ADMITTED_VELNOR=$LANE_ADMITTED_VELNOR): $result" >&2; exit 1 ;; + esac fi else result="$(result_for_job prepare-cargo)" @@ -558,10 +607,17 @@ jobs: fi if [[ "$selected" == *",rust-policy,"* ]]; then result="$(result_for_job github-rust-policy)" - case "$result" in - success) ;; - *) echo "selected CI job github-rust-policy did not pass: $result" >&2; exit 1 ;; - esac + if [[ "$LANE_ADMITTED_GITHUB" == true ]]; then + case "$result" in + success) ;; + *) echo "selected CI job github-rust-policy did not pass: $result" >&2; exit 1 ;; + esac + else + case "$result" in + skipped) ;; + *) echo "selected CI job github-rust-policy ran outside its lane admission (LANE_ADMITTED_GITHUB=$LANE_ADMITTED_GITHUB): $result" >&2; exit 1 ;; + esac + fi else result="$(result_for_job github-rust-policy)" case "$result" in @@ -571,15 +627,15 @@ jobs: fi if [[ "$selected" == *",rust-policy,"* ]]; then result="$(result_for_job velnor-rust-policy)" - if [[ "$FORK_PR" == true ]]; then + if [[ "$LANE_ADMITTED_VELNOR" == true ]]; then case "$result" in - success|skipped) ;; + success) ;; *) echo "selected CI job velnor-rust-policy did not pass: $result" >&2; exit 1 ;; esac else case "$result" in - success) ;; - *) echo "selected CI job velnor-rust-policy did not pass: $result" >&2; exit 1 ;; + skipped) ;; + *) echo "selected CI job velnor-rust-policy ran outside its lane admission (LANE_ADMITTED_VELNOR=$LANE_ADMITTED_VELNOR): $result" >&2; exit 1 ;; esac fi else @@ -591,10 +647,17 @@ jobs: fi if [[ "$selected" == *",rust-ruxel-agent,"* ]]; then result="$(result_for_job github-rust-ruxel-agent)" - case "$result" in - success) ;; - *) echo "selected CI job github-rust-ruxel-agent did not pass: $result" >&2; exit 1 ;; - esac + if [[ "$LANE_ADMITTED_GITHUB" == true ]]; then + case "$result" in + success) ;; + *) echo "selected CI job github-rust-ruxel-agent did not pass: $result" >&2; exit 1 ;; + esac + else + case "$result" in + skipped) ;; + *) echo "selected CI job github-rust-ruxel-agent ran outside its lane admission (LANE_ADMITTED_GITHUB=$LANE_ADMITTED_GITHUB): $result" >&2; exit 1 ;; + esac + fi else result="$(result_for_job github-rust-ruxel-agent)" case "$result" in @@ -604,15 +667,15 @@ jobs: fi if [[ "$selected" == *",rust-ruxel-agent,"* ]]; then result="$(result_for_job velnor-rust-ruxel-agent)" - if [[ "$FORK_PR" == true ]]; then + if [[ "$LANE_ADMITTED_VELNOR" == true ]]; then case "$result" in - success|skipped) ;; + success) ;; *) echo "selected CI job velnor-rust-ruxel-agent did not pass: $result" >&2; exit 1 ;; esac else case "$result" in - success) ;; - *) echo "selected CI job velnor-rust-ruxel-agent did not pass: $result" >&2; exit 1 ;; + skipped) ;; + *) echo "selected CI job velnor-rust-ruxel-agent ran outside its lane admission (LANE_ADMITTED_VELNOR=$LANE_ADMITTED_VELNOR): $result" >&2; exit 1 ;; esac fi else @@ -624,10 +687,17 @@ jobs: fi if [[ "$selected" == *",rust-ruxel-cli,"* ]]; then result="$(result_for_job github-rust-ruxel-cli)" - case "$result" in - success) ;; - *) echo "selected CI job github-rust-ruxel-cli did not pass: $result" >&2; exit 1 ;; - esac + if [[ "$LANE_ADMITTED_GITHUB" == true ]]; then + case "$result" in + success) ;; + *) echo "selected CI job github-rust-ruxel-cli did not pass: $result" >&2; exit 1 ;; + esac + else + case "$result" in + skipped) ;; + *) echo "selected CI job github-rust-ruxel-cli ran outside its lane admission (LANE_ADMITTED_GITHUB=$LANE_ADMITTED_GITHUB): $result" >&2; exit 1 ;; + esac + fi else result="$(result_for_job github-rust-ruxel-cli)" case "$result" in @@ -637,15 +707,15 @@ jobs: fi if [[ "$selected" == *",rust-ruxel-cli,"* ]]; then result="$(result_for_job velnor-rust-ruxel-cli)" - if [[ "$FORK_PR" == true ]]; then + if [[ "$LANE_ADMITTED_VELNOR" == true ]]; then case "$result" in - success|skipped) ;; + success) ;; *) echo "selected CI job velnor-rust-ruxel-cli did not pass: $result" >&2; exit 1 ;; esac else case "$result" in - success) ;; - *) echo "selected CI job velnor-rust-ruxel-cli did not pass: $result" >&2; exit 1 ;; + skipped) ;; + *) echo "selected CI job velnor-rust-ruxel-cli ran outside its lane admission (LANE_ADMITTED_VELNOR=$LANE_ADMITTED_VELNOR): $result" >&2; exit 1 ;; esac fi else @@ -657,10 +727,17 @@ jobs: fi if [[ "$selected" == *",rust-ruxel-core,"* ]]; then result="$(result_for_job github-rust-ruxel-core)" - case "$result" in - success) ;; - *) echo "selected CI job github-rust-ruxel-core did not pass: $result" >&2; exit 1 ;; - esac + if [[ "$LANE_ADMITTED_GITHUB" == true ]]; then + case "$result" in + success) ;; + *) echo "selected CI job github-rust-ruxel-core did not pass: $result" >&2; exit 1 ;; + esac + else + case "$result" in + skipped) ;; + *) echo "selected CI job github-rust-ruxel-core ran outside its lane admission (LANE_ADMITTED_GITHUB=$LANE_ADMITTED_GITHUB): $result" >&2; exit 1 ;; + esac + fi else result="$(result_for_job github-rust-ruxel-core)" case "$result" in @@ -670,15 +747,15 @@ jobs: fi if [[ "$selected" == *",rust-ruxel-core,"* ]]; then result="$(result_for_job velnor-rust-ruxel-core)" - if [[ "$FORK_PR" == true ]]; then + if [[ "$LANE_ADMITTED_VELNOR" == true ]]; then case "$result" in - success|skipped) ;; + success) ;; *) echo "selected CI job velnor-rust-ruxel-core did not pass: $result" >&2; exit 1 ;; esac else case "$result" in - success) ;; - *) echo "selected CI job velnor-rust-ruxel-core did not pass: $result" >&2; exit 1 ;; + skipped) ;; + *) echo "selected CI job velnor-rust-ruxel-core ran outside its lane admission (LANE_ADMITTED_VELNOR=$LANE_ADMITTED_VELNOR): $result" >&2; exit 1 ;; esac fi else @@ -690,10 +767,17 @@ jobs: fi if [[ "$selected" == *",rust-ruxel-proto,"* ]]; then result="$(result_for_job github-rust-ruxel-proto)" - case "$result" in - success) ;; - *) echo "selected CI job github-rust-ruxel-proto did not pass: $result" >&2; exit 1 ;; - esac + if [[ "$LANE_ADMITTED_GITHUB" == true ]]; then + case "$result" in + success) ;; + *) echo "selected CI job github-rust-ruxel-proto did not pass: $result" >&2; exit 1 ;; + esac + else + case "$result" in + skipped) ;; + *) echo "selected CI job github-rust-ruxel-proto ran outside its lane admission (LANE_ADMITTED_GITHUB=$LANE_ADMITTED_GITHUB): $result" >&2; exit 1 ;; + esac + fi else result="$(result_for_job github-rust-ruxel-proto)" case "$result" in @@ -703,15 +787,15 @@ jobs: fi if [[ "$selected" == *",rust-ruxel-proto,"* ]]; then result="$(result_for_job velnor-rust-ruxel-proto)" - if [[ "$FORK_PR" == true ]]; then + if [[ "$LANE_ADMITTED_VELNOR" == true ]]; then case "$result" in - success|skipped) ;; + success) ;; *) echo "selected CI job velnor-rust-ruxel-proto did not pass: $result" >&2; exit 1 ;; esac else case "$result" in - success) ;; - *) echo "selected CI job velnor-rust-ruxel-proto did not pass: $result" >&2; exit 1 ;; + skipped) ;; + *) echo "selected CI job velnor-rust-ruxel-proto ran outside its lane admission (LANE_ADMITTED_VELNOR=$LANE_ADMITTED_VELNOR): $result" >&2; exit 1 ;; esac fi else @@ -723,10 +807,17 @@ jobs: fi if [[ "$selected" == *",rust-ruxel-spec-extract,"* ]]; then result="$(result_for_job github-rust-ruxel-spec-extract)" - case "$result" in - success) ;; - *) echo "selected CI job github-rust-ruxel-spec-extract did not pass: $result" >&2; exit 1 ;; - esac + if [[ "$LANE_ADMITTED_GITHUB" == true ]]; then + case "$result" in + success) ;; + *) echo "selected CI job github-rust-ruxel-spec-extract did not pass: $result" >&2; exit 1 ;; + esac + else + case "$result" in + skipped) ;; + *) echo "selected CI job github-rust-ruxel-spec-extract ran outside its lane admission (LANE_ADMITTED_GITHUB=$LANE_ADMITTED_GITHUB): $result" >&2; exit 1 ;; + esac + fi else result="$(result_for_job github-rust-ruxel-spec-extract)" case "$result" in @@ -736,15 +827,15 @@ jobs: fi if [[ "$selected" == *",rust-ruxel-spec-extract,"* ]]; then result="$(result_for_job velnor-rust-ruxel-spec-extract)" - if [[ "$FORK_PR" == true ]]; then + if [[ "$LANE_ADMITTED_VELNOR" == true ]]; then case "$result" in - success|skipped) ;; + success) ;; *) echo "selected CI job velnor-rust-ruxel-spec-extract did not pass: $result" >&2; exit 1 ;; esac else case "$result" in - success) ;; - *) echo "selected CI job velnor-rust-ruxel-spec-extract did not pass: $result" >&2; exit 1 ;; + skipped) ;; + *) echo "selected CI job velnor-rust-ruxel-spec-extract ran outside its lane admission (LANE_ADMITTED_VELNOR=$LANE_ADMITTED_VELNOR): $result" >&2; exit 1 ;; esac fi else diff --git a/.github/workflows/ci-unit-docker.yml b/.github/workflows/ci-unit-docker.yml index b7c190b..d67379a 100644 --- a/.github/workflows/ci-unit-docker.yml +++ b/.github/workflows/ci-unit-docker.yml @@ -32,6 +32,10 @@ on: required: false type: boolean default: false + mbx_enabled: + required: false + type: boolean + default: false mbx_compat: required: false type: string @@ -96,6 +100,22 @@ on: required: false type: boolean default: false + candidate_publish: + required: false + type: boolean + default: false + apple_executor: + required: false + type: boolean + default: false + unit_dependencies: + required: false + type: string + default: "" + unit_admission: + required: false + type: string + default: "" jobs: verify-github: @@ -121,19 +141,38 @@ jobs: with: persist-credentials: false ref: ${{ inputs.head_sha }} + - name: Record unit dependencies + env: + UNIT_ID: ${{ inputs.unit }} + UNIT_DEPENDENCIES: ${{ inputs.unit_dependencies }} + UNIT_ADMISSION: ${{ inputs.unit_admission }} + UNIT_LANE: ${{ inputs.lane }} + run: | + { + echo '## Unit dependencies' + echo + echo "- Unit: $UNIT_ID" + echo "- Lane: $UNIT_LANE" + echo "- Admission: $UNIT_ADMISSION" + if [[ -z "$UNIT_DEPENDENCIES" ]]; then + echo '- Dependencies: none' + else + echo "- Dependencies: $UNIT_DEPENDENCIES" + fi + } >> "$GITHUB_STEP_SUMMARY" - name: Download Velnor workflow runtime uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: - name: velnor-workflow-runtime-b9c3156cdb88e63c11b9e595a3e694b02238c09a-${{ runner.os }}-${{ runner.arch }} + name: velnor-workflow-runtime-4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d-${{ runner.os }}-${{ runner.arch }} path: .velnor-workflow-runtime - name: Verify Velnor workflow runtime shell: bash env: - EXPECTED_REVISION: b9c3156cdb88e63c11b9e595a3e694b02238c09a + EXPECTED_REVISION: 4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d run: | set -euo pipefail manifest=.velnor-workflow-runtime/manifest.json - jq -e --arg revision "$EXPECTED_REVISION" --arg repository "$GITHUB_REPOSITORY" --arg platform "${RUNNER_OS}-${RUNNER_ARCH}" --arg run_id "$GITHUB_RUN_ID" '.revision == $revision and .repository == $repository and .platform == $platform and .run_id == $run_id and (.run_id | test("^[0-9]+$")) and .job_id != "" and (.binary_sha256 | test("^[0-9a-f]{64}$")) and .policy_revision == $revision and (.policy_binary_sha256 | test("^[0-9a-f]{64}$"))' "$manifest" >/dev/null + jq -e --arg revision "$EXPECTED_REVISION" --arg repository "$GITHUB_REPOSITORY" --arg platform "${RUNNER_OS}-${RUNNER_ARCH}" --arg run_id "$GITHUB_RUN_ID" '.revision == $revision and .repository == $repository and .platform == $platform and .run_id == $run_id and (.run_id | test("^[0-9]+$")) and .job_id != "" and (.binary_sha256 | test("^[0-9a-f]{64}$")) and (.policy_binary_sha256 | test("^[0-9a-f]{64}$")) and (.closure | test("^[0-9a-f]{64}$")) and (.policy_closure | test("^[0-9a-f]{64}$"))' "$manifest" >/dev/null expected="$(jq -er '.binary_sha256' "$manifest")" actual="$(sha256sum .velnor-workflow-runtime/velnor-workflow | awk '{print $1}')" [[ "$actual" == "$expected" ]] || { echo "::error::runtime digest mismatch" >&2; exit 1; } @@ -143,14 +182,15 @@ jobs: - name: Add Velnor workflow runtime to PATH shell: bash env: - EXPECTED_REVISION: b9c3156cdb88e63c11b9e595a3e694b02238c09a + EXPECTED_REVISION: 4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d run: | set -euo pipefail home="$RUNNER_TEMP/velnor-workflow-runtime-artifact" install -Dm0755 .velnor-workflow-runtime/velnor-workflow "$home/bin/velnor-workflow" install -Dm0755 .velnor-workflow-runtime/velnor-workflow-policy "$home/bin/velnor-workflow-policy" - reported="$("$home/bin/velnor-workflow-policy" --revision)" - [[ "$reported" == "$EXPECTED_REVISION" ]] || { echo "::error::policy runtime reports revision $reported, expected $EXPECTED_REVISION" >&2; exit 1; } + expected_closure="$(jq -er '.policy_closure' .velnor-workflow-runtime/manifest.json)" + reported="$("$home/bin/velnor-workflow-policy" --closure)" + [[ "$reported" == "$expected_closure" ]] || { echo "::error::policy runtime reports closure $reported, expected $expected_closure" >&2; exit 1; } echo "$home/bin" >> "$GITHUB_PATH" echo "VELNOR_WORKFLOW_PINNED_BINARY=$home/bin/velnor-workflow-policy" >> "$GITHUB_ENV" - name: Mark runner setup end @@ -247,6 +287,7 @@ jobs: MISE_AUTO_INSTALL: "false" MISE_EXEC_AUTO_INSTALL: "false" MISE_NOT_FOUND_AUTO_INSTALL: "false" + GITHUB_TOKEN: ${{ github.token }} run: | set -o pipefail timing_dir="$RUNNER_TEMP/velnor-ci-timing-${GITHUB_RUN_ID:-unknown}-${GITHUB_RUN_ATTEMPT:-0}-${GITHUB_JOB:-unknown}" @@ -284,14 +325,14 @@ jobs: fi - name: Report phase timings and cache outcomes if: always() - uses: tailrocks/velnor/.github/actions/report-velnor-ci-outcomes@b9c3156cdb88e63c11b9e595a3e694b02238c09a + uses: tailrocks/velnor/.github/actions/report-velnor-ci-outcomes@4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d with: job_label: ${{ inputs.unit }} ci_lane: github verify-velnor: name: Velnor - if: ${{ inputs.lane == 'velnor' && contains(format(',{0},', inputs.selected_units), format(',{0},', inputs.unit)) && (github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'velnor' || github.event.inputs.runner == 'both' || github.event.inputs.runner == '')))) }} + if: ${{ inputs.lane == 'velnor' && contains(format(',{0},', inputs.selected_units), format(',{0},', inputs.unit)) && ((github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'velnor' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} runs-on: [self-hosted, velnor-target-mvp] timeout-minutes: 45 steps: @@ -312,6 +353,25 @@ jobs: with: persist-credentials: false ref: ${{ inputs.head_sha }} + - name: Record unit dependencies + env: + UNIT_ID: ${{ inputs.unit }} + UNIT_DEPENDENCIES: ${{ inputs.unit_dependencies }} + UNIT_ADMISSION: ${{ inputs.unit_admission }} + UNIT_LANE: ${{ inputs.lane }} + run: | + { + echo '## Unit dependencies' + echo + echo "- Unit: $UNIT_ID" + echo "- Lane: $UNIT_LANE" + echo "- Admission: $UNIT_ADMISSION" + if [[ -z "$UNIT_DEPENDENCIES" ]]; then + echo '- Dependencies: none' + else + echo "- Dependencies: $UNIT_DEPENDENCIES" + fi + } >> "$GITHUB_STEP_SUMMARY" - name: Velnor runner identity shell: bash run: | @@ -454,7 +514,7 @@ jobs: fi - name: Report phase timings and cache outcomes if: always() - uses: tailrocks/velnor/.github/actions/report-velnor-ci-outcomes@b9c3156cdb88e63c11b9e595a3e694b02238c09a + uses: tailrocks/velnor/.github/actions/report-velnor-ci-outcomes@4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d with: job_label: ${{ inputs.unit }} ci_lane: velnor diff --git a/.github/workflows/ci-unit-rust.yml b/.github/workflows/ci-unit-rust.yml index 2a4f41a..cbcc8cb 100644 --- a/.github/workflows/ci-unit-rust.yml +++ b/.github/workflows/ci-unit-rust.yml @@ -32,6 +32,10 @@ on: required: false type: boolean default: false + mbx_enabled: + required: false + type: boolean + default: false mbx_compat: required: false type: string @@ -96,11 +100,27 @@ on: required: false type: boolean default: false + candidate_publish: + required: false + type: boolean + default: false + apple_executor: + required: false + type: boolean + default: false + unit_dependencies: + required: false + type: string + default: "" + unit_admission: + required: false + type: string + default: "" jobs: velnor-prepare-cargo-sources: name: prepare-cargo - if: ${{ inputs.lane == 'control' && (contains(format(',{0},', inputs.selected_units), ',rust-ruxel-agent,') || contains(format(',{0},', inputs.selected_units), ',rust-ruxel-cli,') || contains(format(',{0},', inputs.selected_units), ',rust-ruxel-core,') || contains(format(',{0},', inputs.selected_units), ',rust-ruxel-proto,') || contains(format(',{0},', inputs.selected_units), ',rust-ruxel-spec-extract,')) && (github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'velnor' || github.event.inputs.runner == 'both' || github.event.inputs.runner == '')))) }} + if: ${{ inputs.lane == 'control' && (contains(format(',{0},', inputs.selected_units), ',rust-ruxel-agent,') || contains(format(',{0},', inputs.selected_units), ',rust-ruxel-cli,') || contains(format(',{0},', inputs.selected_units), ',rust-ruxel-core,') || contains(format(',{0},', inputs.selected_units), ',rust-ruxel-proto,') || contains(format(',{0},', inputs.selected_units), ',rust-ruxel-spec-extract,')) && ((github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'velnor' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} runs-on: [self-hosted, velnor-target-mvp] timeout-minutes: 20 steps: @@ -163,19 +183,38 @@ jobs: with: persist-credentials: false ref: ${{ inputs.head_sha }} + - name: Record unit dependencies + env: + UNIT_ID: ${{ inputs.unit }} + UNIT_DEPENDENCIES: ${{ inputs.unit_dependencies }} + UNIT_ADMISSION: ${{ inputs.unit_admission }} + UNIT_LANE: ${{ inputs.lane }} + run: | + { + echo '## Unit dependencies' + echo + echo "- Unit: $UNIT_ID" + echo "- Lane: $UNIT_LANE" + echo "- Admission: $UNIT_ADMISSION" + if [[ -z "$UNIT_DEPENDENCIES" ]]; then + echo '- Dependencies: none' + else + echo "- Dependencies: $UNIT_DEPENDENCIES" + fi + } >> "$GITHUB_STEP_SUMMARY" - name: Download Velnor workflow runtime uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: - name: velnor-workflow-runtime-b9c3156cdb88e63c11b9e595a3e694b02238c09a-${{ runner.os }}-${{ runner.arch }} + name: velnor-workflow-runtime-4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d-${{ runner.os }}-${{ runner.arch }} path: .velnor-workflow-runtime - name: Verify Velnor workflow runtime shell: bash env: - EXPECTED_REVISION: b9c3156cdb88e63c11b9e595a3e694b02238c09a + EXPECTED_REVISION: 4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d run: | set -euo pipefail manifest=.velnor-workflow-runtime/manifest.json - jq -e --arg revision "$EXPECTED_REVISION" --arg repository "$GITHUB_REPOSITORY" --arg platform "${RUNNER_OS}-${RUNNER_ARCH}" --arg run_id "$GITHUB_RUN_ID" '.revision == $revision and .repository == $repository and .platform == $platform and .run_id == $run_id and (.run_id | test("^[0-9]+$")) and .job_id != "" and (.binary_sha256 | test("^[0-9a-f]{64}$")) and .policy_revision == $revision and (.policy_binary_sha256 | test("^[0-9a-f]{64}$"))' "$manifest" >/dev/null + jq -e --arg revision "$EXPECTED_REVISION" --arg repository "$GITHUB_REPOSITORY" --arg platform "${RUNNER_OS}-${RUNNER_ARCH}" --arg run_id "$GITHUB_RUN_ID" '.revision == $revision and .repository == $repository and .platform == $platform and .run_id == $run_id and (.run_id | test("^[0-9]+$")) and .job_id != "" and (.binary_sha256 | test("^[0-9a-f]{64}$")) and (.policy_binary_sha256 | test("^[0-9a-f]{64}$")) and (.closure | test("^[0-9a-f]{64}$")) and (.policy_closure | test("^[0-9a-f]{64}$"))' "$manifest" >/dev/null expected="$(jq -er '.binary_sha256' "$manifest")" actual="$(sha256sum .velnor-workflow-runtime/velnor-workflow | awk '{print $1}')" [[ "$actual" == "$expected" ]] || { echo "::error::runtime digest mismatch" >&2; exit 1; } @@ -185,14 +224,15 @@ jobs: - name: Add Velnor workflow runtime to PATH shell: bash env: - EXPECTED_REVISION: b9c3156cdb88e63c11b9e595a3e694b02238c09a + EXPECTED_REVISION: 4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d run: | set -euo pipefail home="$RUNNER_TEMP/velnor-workflow-runtime-artifact" install -Dm0755 .velnor-workflow-runtime/velnor-workflow "$home/bin/velnor-workflow" install -Dm0755 .velnor-workflow-runtime/velnor-workflow-policy "$home/bin/velnor-workflow-policy" - reported="$("$home/bin/velnor-workflow-policy" --revision)" - [[ "$reported" == "$EXPECTED_REVISION" ]] || { echo "::error::policy runtime reports revision $reported, expected $EXPECTED_REVISION" >&2; exit 1; } + expected_closure="$(jq -er '.policy_closure' .velnor-workflow-runtime/manifest.json)" + reported="$("$home/bin/velnor-workflow-policy" --closure)" + [[ "$reported" == "$expected_closure" ]] || { echo "::error::policy runtime reports closure $reported, expected $expected_closure" >&2; exit 1; } echo "$home/bin" >> "$GITHUB_PATH" echo "VELNOR_WORKFLOW_PINNED_BINARY=$home/bin/velnor-workflow-policy" >> "$GITHUB_ENV" - name: Mark runner setup end @@ -263,11 +303,11 @@ jobs: run: echo "MBX_GC_MAX_SIZE=12GiB" >> "$GITHUB_ENV" - name: Set up Mr. Boxington id: mbx-cache - uses: jdx/mr-boxington-action@7234d3dd1a6ca8f6c381eea8e4dfb03f18fcf777 # v1.3.0 + uses: jdx/mr-boxington-action@867fc530102eec5b756075d70d850dc8330d2272 # v1.4.0 with: backend: github github-cache-mode: objects - version: 1.11.1 + version: 1.12.0 cache-key: velnor-mbx-v3-${{ inputs.mbx_compat }}-${{ runner.os }}-${{ runner.arch }}-${{ inputs.unit }}-${{ hashFiles(inputs.mbx_dependency_files) }}-${{ hashFiles(inputs.mbx_freshness_files) }} restore-keys: | velnor-mbx-v3-${{ inputs.mbx_compat }}-${{ runner.os }}-${{ runner.arch }}-${{ inputs.unit }}-${{ hashFiles(inputs.mbx_dependency_files) }}- @@ -346,7 +386,7 @@ jobs: if [[ ! -s "$archive" ]]; then temporary="$archive.download" trap 'rm -f "$temporary"' EXIT - curl --fail --silent --show-error --location --retry 3 --retry-delay 2 \ + curl --fail --show-error --silent --location --http1.1 --continue-at - --retry 20 --retry-all-errors --retry-delay 5 --retry-max-time 1800 --connect-timeout 30 --max-time 900 \ --output "$temporary" \ "https://github.com/rui314/mold/releases/download/v$MOLD_VERSION/mold-$MOLD_VERSION-$mold_arch-linux.tar.gz" printf '%s %s\n' "$expected" "$temporary" | sha256sum --check --strict @@ -482,7 +522,7 @@ jobs: fi - name: Report phase timings and cache outcomes if: always() - uses: tailrocks/velnor/.github/actions/report-velnor-ci-outcomes@b9c3156cdb88e63c11b9e595a3e694b02238c09a + uses: tailrocks/velnor/.github/actions/report-velnor-ci-outcomes@4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d with: job_label: ${{ inputs.unit }} ci_lane: github @@ -497,7 +537,7 @@ jobs: verify-velnor: name: Velnor - if: ${{ inputs.lane == 'velnor' && contains(format(',{0},', inputs.selected_units), format(',{0},', inputs.unit)) && (github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'velnor' || github.event.inputs.runner == 'both' || github.event.inputs.runner == '')))) }} + if: ${{ inputs.lane == 'velnor' && contains(format(',{0},', inputs.selected_units), format(',{0},', inputs.unit)) && ((github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'schedule')) || (github.event_name == 'workflow_dispatch' && (github.event.inputs.runner == 'velnor' || github.event.inputs.runner == 'both' || github.event.inputs.runner == ''))) }} runs-on: [self-hosted, velnor-target-mvp] timeout-minutes: 45 steps: @@ -518,6 +558,25 @@ jobs: with: persist-credentials: false ref: ${{ inputs.head_sha }} + - name: Record unit dependencies + env: + UNIT_ID: ${{ inputs.unit }} + UNIT_DEPENDENCIES: ${{ inputs.unit_dependencies }} + UNIT_ADMISSION: ${{ inputs.unit_admission }} + UNIT_LANE: ${{ inputs.lane }} + run: | + { + echo '## Unit dependencies' + echo + echo "- Unit: $UNIT_ID" + echo "- Lane: $UNIT_LANE" + echo "- Admission: $UNIT_ADMISSION" + if [[ -z "$UNIT_DEPENDENCIES" ]]; then + echo '- Dependencies: none' + else + echo "- Dependencies: $UNIT_DEPENDENCIES" + fi + } >> "$GITHUB_STEP_SUMMARY" - name: Velnor runner identity shell: bash run: | @@ -586,7 +645,7 @@ jobs: mise --yes install "${tools[@]}" - name: Set up Mr. Boxington id: mbx-cache - uses: jdx/mr-boxington-action@7234d3dd1a6ca8f6c381eea8e4dfb03f18fcf777 # v1.3.0 + uses: jdx/mr-boxington-action@867fc530102eec5b756075d70d850dc8330d2272 # v1.4.0 with: backend: local - name: Mark tool bootstrap end @@ -674,7 +733,7 @@ jobs: fi - name: Report phase timings and cache outcomes if: always() - uses: tailrocks/velnor/.github/actions/report-velnor-ci-outcomes@b9c3156cdb88e63c11b9e595a3e694b02238c09a + uses: tailrocks/velnor/.github/actions/report-velnor-ci-outcomes@4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d with: job_label: ${{ inputs.unit }} ci_lane: velnor diff --git a/.github/workflows/maintenance.yml b/.github/workflows/maintenance.yml index 5c5fb60..14f5cb7 100644 --- a/.github/workflows/maintenance.yml +++ b/.github/workflows/maintenance.yml @@ -6,7 +6,7 @@ on: pull_request: types: [closed] schedule: - - cron: '31 3 * * *' + - cron: "31 3 * * *" workflow_dispatch: inputs: pull_request_number: @@ -35,29 +35,53 @@ jobs: PR_NUMBER: ${{ github.event.pull_request.number || inputs.pull_request_number }} run: | set -euo pipefail + delete_cache_id() { + local id="$1" error attempt + for attempt in 1 2 3; do + error="$(gh api --method DELETE "repos/$GITHUB_REPOSITORY/actions/caches/$id" 2>&1 >/dev/null)" && return 0 + if grep -qi 'not found' <<<"$error"; then + return 0 + fi + if grep -Eq 'HTTP 40[13]' <<<"$error"; then + echo "::error::cache delete refused for id $id ($error); refusing to retry an authorization failure" >&2 + return 2 + fi + if (( attempt < 3 )); then + sleep $((attempt * 2)) + fi + done + echo "::error::failed to delete cache id $id after bounded retries" >&2 + return 1 + } ref="refs/pull/$PR_NUMBER/merge" encoded="$(printf '%s' "$ref" | jq -sRr @uri)" - cache_ids="$(gh api --paginate "repos/$GITHUB_REPOSITORY/actions/caches?ref=$encoded" --jq '.actions_caches[].id')" - if [[ -z "$cache_ids" ]]; then + listing="$(gh api --paginate "repos/$GITHUB_REPOSITORY/actions/caches?ref=$encoded" --jq '.actions_caches[].id')" || { + echo "::error::failed to list cache entries for $ref" >&2 + exit 1 + } + if [[ -z "$listing" ]]; then echo "No merge-ref cache entries found for $ref" exit 0 fi + mapfile -t cache_ids <<<"$listing" + deleted=0 failed=0 - while IFS= read -r id; do + for id in "${cache_ids[@]}"; do [[ -z "$id" ]] && continue - deleted=false - for delay in 1 2 4 8; do - if gh api --method DELETE "repos/$GITHUB_REPOSITORY/actions/caches/$id" >/dev/null 2>&1; then - deleted=true - break + if (( deleted + failed >= 500 )); then + echo "::error::maintenance delete bound reached (500 cache deletes); rerun maintenance to continue" >&2 + exit 1 + fi + if delete_cache_id "$id"; then + deleted=$((deleted + 1)) + else + status=$? + if (( status == 2 )); then + exit 1 fi - sleep "$delay" - done - if [[ "$deleted" != true ]]; then failed=$((failed + 1)) - echo "::error::failed to delete cache id $id after retries" >&2 fi - done <<< "$cache_ids" + done if (( failed > 0 )); then echo "::error::$failed closed-PR cache entries could not be deleted; rerun maintenance" >&2 exit 1 @@ -87,27 +111,52 @@ jobs: done echo "skip=false" >> "$GITHUB_OUTPUT" - name: Set up Velnor workflow runtime + id: runtime if: ${{ steps.retention-gate.outputs.skip != 'true' && runner.environment == 'github-hosted' }} - uses: tailrocks/velnor/.github/actions/setup-velnor-workflow@b9c3156cdb88e63c11b9e595a3e694b02238c09a + uses: tailrocks/velnor/.github/actions/setup-velnor-workflow@4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d with: - rev: b9c3156cdb88e63c11b9e595a3e694b02238c09a + rev: 4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d - name: Set trusted workflow policy revision if: steps.retention-gate.outputs.skip != 'true' - run: echo "VELNOR_WORKFLOW_POLICY_REVISION=b9c3156cdb88e63c11b9e595a3e694b02238c09a" >> "$GITHUB_ENV" + run: echo "VELNOR_WORKFLOW_POLICY_REVISION=4fa7a3a85f141a6bb95bc9bdf0eef9e3ddde165d" >> "$GITHUB_ENV" - name: Sweep closed-PR merge-ref caches if: steps.retention-gate.outputs.skip != 'true' env: GH_TOKEN: ${{ github.token }} run: | set -euo pipefail + delete_cache_id() { + local id="$1" error attempt + for attempt in 1 2 3; do + error="$(gh api --method DELETE "repos/$GITHUB_REPOSITORY/actions/caches/$id" 2>&1 >/dev/null)" && return 0 + if grep -qi 'not found' <<<"$error"; then + return 0 + fi + if grep -Eq 'HTTP 40[13]' <<<"$error"; then + echo "::error::cache delete refused for id $id ($error); refusing to retry an authorization failure" >&2 + return 2 + fi + if (( attempt < 3 )); then + sleep $((attempt * 2)) + fi + done + echo "::error::failed to delete cache id $id after bounded retries" >&2 + return 1 + } failed=0 - mapfile -t refs < <(gh api --paginate "repos/$GITHUB_REPOSITORY/actions/caches?per_page=100" \ - --jq '.actions_caches[].ref' | grep -E '^refs/pull/[0-9]+/merge$' | sort -u) + processed=0 + all_refs="$(gh api --paginate "repos/$GITHUB_REPOSITORY/actions/caches?per_page=100" \ + --jq '.actions_caches[].ref')" || { + echo "::error::failed to list cache scopes" >&2 + exit 1 + } + mapfile -t refs < <(printf '%s\n' "$all_refs" | grep -E '^refs/pull/[0-9]+/merge$' | sort -u) if ((${#refs[@]} == 0)); then echo "No merge-ref cache scopes found" exit 0 fi for ref in "${refs[@]}"; do + [[ -z "$ref" ]] && continue pr="${ref#refs/pull/}" pr="${pr%/merge}" state="$(gh pr view "$pr" --json state --jq .state 2>/dev/null || echo unknown)" @@ -115,25 +164,32 @@ jobs: continue fi encoded="$(printf '%s' "$ref" | jq -sRr @uri)" - mapfile -t cache_ids < <(gh api --paginate "repos/$GITHUB_REPOSITORY/actions/caches?ref=$encoded" \ - --jq '.actions_caches[].id') - if ((${#cache_ids[@]} == 0)); then + listing="$(gh api --paginate "repos/$GITHUB_REPOSITORY/actions/caches?ref=$encoded" \ + --jq '.actions_caches[].id')" || { + echo "::error::failed to list cache entries for $ref" >&2 + exit 1 + } + if [[ -z "$listing" ]]; then continue fi + mapfile -t cache_ids <<<"$listing" echo "Sweeping $ref ($pr): ${#cache_ids[@]} entries" for id in "${cache_ids[@]}"; do - deleted=false - for delay in 1 2 4 8; do - if gh api --method DELETE "repos/$GITHUB_REPOSITORY/actions/caches/$id" >/dev/null 2>&1; then - deleted=true - break + [[ -z "$id" ]] && continue + if (( processed >= 500 )); then + echo "::error::maintenance delete bound reached (500 cache deletes); rerun maintenance to continue" >&2 + exit 1 + fi + if delete_cache_id "$id"; then + : + else + status=$? + if (( status == 2 )); then + exit 1 fi - sleep "$delay" - done - if [[ "$deleted" != true ]]; then failed=$((failed + 1)) - echo "::error::failed to delete cache id $id for $ref after retries" >&2 fi + processed=$((processed + 1)) done done if (( failed > 0 )); then @@ -207,18 +263,46 @@ jobs: GH_TOKEN: ${{ github.token }} run: | set -euo pipefail + delete_cache_id() { + local id="$1" error attempt + for attempt in 1 2 3; do + error="$(gh api --method DELETE "repos/$GITHUB_REPOSITORY/actions/caches/$id" 2>&1 >/dev/null)" && return 0 + if grep -qi 'not found' <<<"$error"; then + return 0 + fi + if grep -Eq 'HTTP 40[13]' <<<"$error"; then + echo "::error::cache delete refused for id $id ($error); refusing to retry an authorization failure" >&2 + return 2 + fi + if (( attempt < 3 )); then + sleep $((attempt * 2)) + fi + done + echo "::error::failed to delete cache id $id after bounded retries" >&2 + return 1 + } evicted=0 freed=0 failed=0 # The plan is applied verbatim, in its own order: generations beyond # their class bound first, then classes over budget, then the global - # sweep - which never touches a protected class. + # sweep - which never touches a protected class. The per-run delete + # bound stops the sweep instead of letting one run empty the + # account; the next run continues where this one stopped. while IFS=$'\t' read -r class reason id size key; do - if gh api --method DELETE "repos/$GITHUB_REPOSITORY/actions/caches/$id" >/dev/null; then + if (( evicted + failed >= 500 )); then + echo "::error::maintenance delete bound reached (500 cache deletes); rerun maintenance to continue" >&2 + exit 1 + fi + if delete_cache_id "$id"; then evicted=$((evicted + 1)) freed=$((freed + size)) echo "evicted id=$id class=$class reason=$reason size=$size key=$key" else + status=$? + if (( status == 2 )); then + exit 1 + fi failed=$((failed + 1)) echo "::warning::failed to evict cache id $id (class $class, key $key)" >&2 fi diff --git a/mise.toml b/mise.toml index 7d69b08..38ed380 100644 --- a/mise.toml +++ b/mise.toml @@ -13,8 +13,13 @@ idiomatic_version_file_enable_tools = ["rust"] cargo.binstall_only = true cargo.binstall_quickinstall = true -[tasks.ci] -run = "cargo check --all-targets --all-features --locked" +[tasks.install] +description = "Provision every pinned tool from mise.lock" +run = "mise install --locked" + +[tasks.build] +description = "Compile every workspace target with a real codegen build" +run = "cargo build --all-targets --all-features --locked" [tasks.test] run = "cargo nextest run --all-features --color=always --no-tests=pass" @@ -27,3 +32,7 @@ run = "cargo fmt --all --check" [tasks."fmt-fix"] run = "cargo fmt --all" + +[tasks.ci] +description = "Local aggregate of install, build, test, lint, and fmt" +depends = ["install", "build", "test", "lint", "fmt"]