From a9683943f769a4342def1f6191e0bed41c935371 Mon Sep 17 00:00:00 2001 From: Dmitry Prudnikov Date: Wed, 4 Nov 2026 10:47:21 +0200 Subject: [PATCH] ci: free runner disk before the heaviest jobs The coverage job and the test blocks build the whole workspace beside the restored caches and the native oracle, and on GitHub-hosted Ubuntu they intermittently abort with "No space left on device". A local composite action removes preinstalled toolchains the build never uses (.NET, the Android SDK, GHC, the CodeQL bundle) on hosted Linux runners only, and logs free space before and after. Both jobs call it before any cache is restored; a workflow contract test pins the order. Closes #389 --- .github/actions/free-runner-disk/action.yml | 16 ++++++++++++++ .github/workflows/ci.yml | 2 ++ tools/xml-sec-tools/src/workflow_contracts.rs | 21 +++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 .github/actions/free-runner-disk/action.yml diff --git a/.github/actions/free-runner-disk/action.yml b/.github/actions/free-runner-disk/action.yml new file mode 100644 index 00000000..84a8f857 --- /dev/null +++ b/.github/actions/free-runner-disk/action.yml @@ -0,0 +1,16 @@ +name: Free runner disk +description: Remove preinstalled toolchains the build never uses from a hosted Linux runner +runs: + using: composite + steps: + # The hosted Ubuntu image leaves too little free space for a full + # instrumented or all-feature workspace build beside the restored caches + # and the native oracle. These toolchains are never used by this build. + # Self-hosted runners keep their own provisioning. + - name: Remove unused hosted toolchains + if: runner.os == 'Linux' && runner.environment == 'github-hosted' + shell: bash + run: | + df -h / + sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /opt/hostedtoolcache/CodeQL + df -h / diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2d8377c1..f4575bbe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,6 +56,7 @@ jobs: - uses: actions/checkout@v7 with: persist-credentials: false + - uses: ./.github/actions/free-runner-disk - name: Read pinned oracle revisions id: coverage-oracles run: | @@ -334,6 +335,7 @@ jobs: - uses: actions/checkout@v7 with: persist-credentials: false + - uses: ./.github/actions/free-runner-disk - name: Read pinned donor revision id: test-donor-revision run: | diff --git a/tools/xml-sec-tools/src/workflow_contracts.rs b/tools/xml-sec-tools/src/workflow_contracts.rs index 97d357c9..fd9e54b6 100644 --- a/tools/xml-sec-tools/src/workflow_contracts.rs +++ b/tools/xml-sec-tools/src/workflow_contracts.rs @@ -253,6 +253,27 @@ fn runner_image_identity_is_read_at_runtime_rather_than_an_empty_env_context() { } } +#[test] +fn the_heaviest_jobs_free_hosted_runner_disk_before_restoring_any_cache() { + // Full-workspace builds beside the caches and the native oracle exhaust the + // hosted image's disk; the space must be freed before anything is restored. + let action = read(".github/actions/free-runner-disk/action.yml"); + assert!(action.contains("if: runner.os == 'Linux' && runner.environment == 'github-hosted'")); + let workflow = read(".github/workflows/ci.yml"); + for job in ["coverage", "test-matrix"] { + let body = section(&workflow, job); + let freed = body + .find("uses: ./.github/actions/free-runner-disk") + .unwrap_or_else(|| panic!("{job} frees no disk")); + for cache in ["rust-build-cache", "xmlsec-oracle-cache"] { + let restored = body + .find(&format!("uses: ./.github/actions/{cache}")) + .unwrap(); + assert!(freed < restored, "{job}: {cache}"); + } + } +} + #[test] fn coverage_checkout_references_resolve_existing_pinned_oracle_revisions() { // Validate the actual setup program, not just YAML syntax: a misspelled