From ce1365f211f41565e92c6aad9d21e8be2911f502 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 25 May 2026 16:47:25 +0000 Subject: [PATCH 1/6] ci: add musl toolchain multi-level cache Agent-Logs-Url: https://github.com/HiGarfield/cpulimit/sessions/7e127b92-21f8-4257-ba2a-cd70a0944178 Co-authored-by: HiGarfield <32226909+HiGarfield@users.noreply.github.com> --- .github/workflows/CI.yml | 77 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 73 insertions(+), 4 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index ebc1b98a..864fc1a2 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -17,6 +17,7 @@ jobs: build-Linux-macOS: name: Build on ${{ matrix.os }} permissions: + actions: read contents: read strategy: matrix: @@ -35,17 +36,77 @@ jobs: sudo apt -qq update sudo apt -qq install gcc-multilib libc6-dev-i386 - - name: Download musl.cc i486 toolchain (Ubuntu) + - name: Restore musl i486 extracted cache (Ubuntu) + id: musl-cache-bin if: startsWith(matrix.os, 'ubuntu-') + uses: actions/cache@v4 + with: + path: ${{ github.workspace }}/.musl-toolchain/i486-linux-musl-cross + key: musl-i486-bin-v0.0.1-1b7eceb2022f4a664028dd314c5c44332b601bd271e40f0934b4bc8fd3b0fcf5 + + - name: Restore musl i486 archive cache (Ubuntu) + id: musl-cache-archive + if: startsWith(matrix.os, 'ubuntu-') && steps.musl-cache-bin.outputs.cache-hit != 'true' + uses: actions/cache@v4 + with: + path: ${{ runner.temp }}/i486-linux-musl-cross.tgz + key: musl-i486-archive-v0.0.1-1b7eceb2022f4a664028dd314c5c44332b601bd271e40f0934b4bc8fd3b0fcf5 + + - name: Prepare musl.cc i486 toolchain (Ubuntu) + if: startsWith(matrix.os, 'ubuntu-') && steps.musl-cache-bin.outputs.cache-hit != 'true' run: | set -euo pipefail MUSL_ROOT="${GITHUB_WORKSPACE}/.musl-toolchain" MUSL_ARCHIVE="${RUNNER_TEMP}/i486-linux-musl-cross.tgz" MUSL_ARCHIVE_URL="https://github.com/musl-cc/musl.cc/releases/download/v0.0.1/i486-linux-musl-cross.tgz" MUSL_ARCHIVE_SHA256="1b7eceb2022f4a664028dd314c5c44332b601bd271e40f0934b4bc8fd3b0fcf5" - curl -fL \ - "${MUSL_ARCHIVE_URL}" \ - -o "${MUSL_ARCHIVE}" + + if [ ! -s "${MUSL_ARCHIVE}" ]; then + curl -fL \ + "${MUSL_ARCHIVE_URL}" \ + -o "${MUSL_ARCHIVE}" \ + || true + fi + + if [ ! -s "${MUSL_ARCHIVE}" ]; then + artifact_api_url="${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/actions/artifacts?name=musl-i486-toolchain&per_page=100" + artifact_json="${RUNNER_TEMP}/musl-i486-artifacts.json" + artifact_zip="${RUNNER_TEMP}/musl-i486-artifact.zip" + artifact_download_url="" + if curl -fsSL \ + -H "Authorization: Bearer ${GITHUB_TOKEN}" \ + -H "Accept: application/vnd.github+json" \ + "${artifact_api_url}" \ + -o "${artifact_json}"; then + artifact_download_url="$(python3 - "${artifact_json}" <<'PY' +import json +import sys + +with open(sys.argv[1], "r", encoding="utf-8") as f: + payload = json.load(f) + +artifacts = payload.get("artifacts", []) +artifacts = [a for a in artifacts if not a.get("expired")] +artifacts.sort(key=lambda a: a.get("created_at", ""), reverse=True) + +if artifacts: + print(artifacts[0].get("archive_download_url", "")) +PY + )" + fi + if [ -n "${artifact_download_url}" ]; then + curl -fL \ + -H "Authorization: Bearer ${GITHUB_TOKEN}" \ + -H "Accept: application/vnd.github+json" \ + "${artifact_download_url}" \ + -o "${artifact_zip}" + unzip -p "${artifact_zip}" i486-linux-musl-cross.tgz > "${MUSL_ARCHIVE}" + else + echo "No non-expired musl-i486-toolchain artifact available." >&2 + fi + fi + + test -s "${MUSL_ARCHIVE}" printf '%s %s\n' "${MUSL_ARCHIVE_SHA256}" "${MUSL_ARCHIVE}" \ | sha256sum -c - rm -rf "${MUSL_ROOT}" @@ -53,6 +114,14 @@ jobs: tar -xzf "${MUSL_ARCHIVE}" -C "${MUSL_ROOT}" test -x "${MUSL_ROOT}/i486-linux-musl-cross/bin/i486-linux-musl-gcc" + - name: Upload musl i486 toolchain artifact backup (Ubuntu) + if: startsWith(matrix.os, 'ubuntu-') && github.event_name != 'pull_request' && steps.musl-cache-bin.outputs.cache-hit != 'true' + uses: actions/upload-artifact@main + with: + name: musl-i486-toolchain + path: ${{ runner.temp }}/i486-linux-musl-cross.tgz + retention-days: 90 + - name: Build and test run: | for compiler in gcc clang; do From 8496a7e0001e7afd1cc444a056727e66ec333120 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 25 May 2026 16:55:09 +0000 Subject: [PATCH 2/6] ci: harden musl artifact fallback handling Agent-Logs-Url: https://github.com/HiGarfield/cpulimit/sessions/7e127b92-21f8-4257-ba2a-cd70a0944178 Co-authored-by: HiGarfield <32226909+HiGarfield@users.noreply.github.com> --- .github/workflows/CI.yml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 864fc1a2..8e85b890 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -54,6 +54,8 @@ jobs: - name: Prepare musl.cc i486 toolchain (Ubuntu) if: startsWith(matrix.os, 'ubuntu-') && steps.musl-cache-bin.outputs.cache-hit != 'true' + env: + GITHUB_TOKEN: ${{ github.token }} run: | set -euo pipefail MUSL_ROOT="${GITHUB_WORKSPACE}/.musl-toolchain" @@ -72,6 +74,7 @@ jobs: artifact_api_url="${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/actions/artifacts?name=musl-i486-toolchain&per_page=100" artifact_json="${RUNNER_TEMP}/musl-i486-artifacts.json" artifact_zip="${RUNNER_TEMP}/musl-i486-artifact.zip" + artifact_archive="${RUNNER_TEMP}/i486-linux-musl-cross.from-artifact.tgz" artifact_download_url="" if curl -fsSL \ -H "Authorization: Bearer ${GITHUB_TOKEN}" \ @@ -100,7 +103,17 @@ PY -H "Accept: application/vnd.github+json" \ "${artifact_download_url}" \ -o "${artifact_zip}" - unzip -p "${artifact_zip}" i486-linux-musl-cross.tgz > "${MUSL_ARCHIVE}" + rm -f "${artifact_archive}" + if unzip -Z -1 "${artifact_zip}" | grep -qx "i486-linux-musl-cross.tgz"; then + if unzip -p "${artifact_zip}" i486-linux-musl-cross.tgz > "${artifact_archive}"; then + mv -f "${artifact_archive}" "${MUSL_ARCHIVE}" + else + rm -f "${artifact_archive}" + echo "Failed to extract i486-linux-musl-cross.tgz from artifact." >&2 + fi + else + echo "Artifact is missing i486-linux-musl-cross.tgz entry." >&2 + fi else echo "No non-expired musl-i486-toolchain artifact available." >&2 fi @@ -116,7 +129,7 @@ PY - name: Upload musl i486 toolchain artifact backup (Ubuntu) if: startsWith(matrix.os, 'ubuntu-') && github.event_name != 'pull_request' && steps.musl-cache-bin.outputs.cache-hit != 'true' - uses: actions/upload-artifact@main + uses: actions/upload-artifact@v4 with: name: musl-i486-toolchain path: ${{ runner.temp }}/i486-linux-musl-cross.tgz From 25505c5e5185805f2da57caed2a1364c5e01f13f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 25 May 2026 17:23:16 +0000 Subject: [PATCH 3/6] ci: address musl workflow review Agent-Logs-Url: https://github.com/HiGarfield/cpulimit/sessions/cdef6235-11f8-4d31-bae2-5a158e5a6b25 Co-authored-by: HiGarfield <32226909+HiGarfield@users.noreply.github.com> --- .github/workflows/CI.yml | 47 ++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 8e85b890..5be839d0 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -44,22 +44,41 @@ jobs: path: ${{ github.workspace }}/.musl-toolchain/i486-linux-musl-cross key: musl-i486-bin-v0.0.1-1b7eceb2022f4a664028dd314c5c44332b601bd271e40f0934b4bc8fd3b0fcf5 + - name: Validate musl i486 extracted cache (Ubuntu) + id: musl-cache-bin-validate + if: startsWith(matrix.os, 'ubuntu-') + run: | + set -euo pipefail + musl_root="${GITHUB_WORKSPACE}/.musl-toolchain/i486-linux-musl-cross" + musl_gcc="${musl_root}/bin/i486-linux-musl-gcc" + if [ "${{ steps.musl-cache-bin.outputs.cache-hit }}" = 'true' ] \ + && [ -x "${musl_gcc}" ]; then + echo "cache-valid=true" >> "${GITHUB_OUTPUT}" + else + if [ "${{ steps.musl-cache-bin.outputs.cache-hit }}" = 'true' ]; then + rm -rf "${musl_root}" + echo "Cached musl toolchain is missing ${musl_gcc}." >&2 + fi + echo "cache-valid=false" >> "${GITHUB_OUTPUT}" + fi + - name: Restore musl i486 archive cache (Ubuntu) id: musl-cache-archive - if: startsWith(matrix.os, 'ubuntu-') && steps.musl-cache-bin.outputs.cache-hit != 'true' + if: startsWith(matrix.os, 'ubuntu-') && steps.musl-cache-bin-validate.outputs.cache-valid != 'true' uses: actions/cache@v4 with: path: ${{ runner.temp }}/i486-linux-musl-cross.tgz key: musl-i486-archive-v0.0.1-1b7eceb2022f4a664028dd314c5c44332b601bd271e40f0934b4bc8fd3b0fcf5 - name: Prepare musl.cc i486 toolchain (Ubuntu) - if: startsWith(matrix.os, 'ubuntu-') && steps.musl-cache-bin.outputs.cache-hit != 'true' + if: startsWith(matrix.os, 'ubuntu-') && steps.musl-cache-bin-validate.outputs.cache-valid != 'true' env: GITHUB_TOKEN: ${{ github.token }} run: | set -euo pipefail MUSL_ROOT="${GITHUB_WORKSPACE}/.musl-toolchain" MUSL_ARCHIVE="${RUNNER_TEMP}/i486-linux-musl-cross.tgz" + MUSL_ARTIFACT_NAME="musl-i486-toolchain-${{ matrix.os }}" MUSL_ARCHIVE_URL="https://github.com/musl-cc/musl.cc/releases/download/v0.0.1/i486-linux-musl-cross.tgz" MUSL_ARCHIVE_SHA256="1b7eceb2022f4a664028dd314c5c44332b601bd271e40f0934b4bc8fd3b0fcf5" @@ -71,7 +90,7 @@ jobs: fi if [ ! -s "${MUSL_ARCHIVE}" ]; then - artifact_api_url="${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/actions/artifacts?name=musl-i486-toolchain&per_page=100" + artifact_api_url="${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/actions/artifacts?per_page=100" artifact_json="${RUNNER_TEMP}/musl-i486-artifacts.json" artifact_zip="${RUNNER_TEMP}/musl-i486-artifact.zip" artifact_archive="${RUNNER_TEMP}/i486-linux-musl-cross.from-artifact.tgz" @@ -81,21 +100,7 @@ jobs: -H "Accept: application/vnd.github+json" \ "${artifact_api_url}" \ -o "${artifact_json}"; then - artifact_download_url="$(python3 - "${artifact_json}" <<'PY' -import json -import sys - -with open(sys.argv[1], "r", encoding="utf-8") as f: - payload = json.load(f) - -artifacts = payload.get("artifacts", []) -artifacts = [a for a in artifacts if not a.get("expired")] -artifacts.sort(key=lambda a: a.get("created_at", ""), reverse=True) - -if artifacts: - print(artifacts[0].get("archive_download_url", "")) -PY - )" + artifact_download_url="$(python3 -c 'import json, sys; payload = json.load(open(sys.argv[1], "r", encoding="utf-8")); artifact_name = sys.argv[2]; artifacts = [a for a in payload.get("artifacts", []) if a.get("name") == artifact_name and not a.get("expired")]; artifacts.sort(key=lambda a: a.get("created_at", ""), reverse=True); print(artifacts[0].get("archive_download_url", "") if artifacts else "")' "${artifact_json}" "${MUSL_ARTIFACT_NAME}")" fi if [ -n "${artifact_download_url}" ]; then curl -fL \ @@ -115,7 +120,7 @@ PY echo "Artifact is missing i486-linux-musl-cross.tgz entry." >&2 fi else - echo "No non-expired musl-i486-toolchain artifact available." >&2 + echo "No non-expired ${MUSL_ARTIFACT_NAME} artifact available." >&2 fi fi @@ -128,10 +133,10 @@ PY test -x "${MUSL_ROOT}/i486-linux-musl-cross/bin/i486-linux-musl-gcc" - name: Upload musl i486 toolchain artifact backup (Ubuntu) - if: startsWith(matrix.os, 'ubuntu-') && github.event_name != 'pull_request' && steps.musl-cache-bin.outputs.cache-hit != 'true' + if: startsWith(matrix.os, 'ubuntu-') && github.event_name != 'pull_request' && steps.musl-cache-bin-validate.outputs.cache-valid != 'true' uses: actions/upload-artifact@v4 with: - name: musl-i486-toolchain + name: musl-i486-toolchain-${{ matrix.os }} path: ${{ runner.temp }}/i486-linux-musl-cross.tgz retention-days: 90 From 47c63fc587cc89d858f4023c294d903c04c89dfb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 25 May 2026 17:25:13 +0000 Subject: [PATCH 4/6] ci: clarify musl fallback errors Agent-Logs-Url: https://github.com/HiGarfield/cpulimit/sessions/cdef6235-11f8-4d31-bae2-5a158e5a6b25 Co-authored-by: HiGarfield <32226909+HiGarfield@users.noreply.github.com> --- .github/workflows/CI.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 5be839d0..56cc3a3f 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -114,13 +114,13 @@ jobs: mv -f "${artifact_archive}" "${MUSL_ARCHIVE}" else rm -f "${artifact_archive}" - echo "Failed to extract i486-linux-musl-cross.tgz from artifact." >&2 + echo "Failed to extract i486-linux-musl-cross.tgz from artifact; the workflow will fail if no other archive source succeeds." >&2 fi else - echo "Artifact is missing i486-linux-musl-cross.tgz entry." >&2 + echo "Artifact is missing i486-linux-musl-cross.tgz; the workflow will fail if no other archive source succeeds." >&2 fi else - echo "No non-expired ${MUSL_ARTIFACT_NAME} artifact available." >&2 + echo "No non-expired ${MUSL_ARTIFACT_NAME} artifact is available; the workflow will fail if no other archive source succeeds." >&2 fi fi From 59c97e534434a153effad908aaff84fd4469c4c0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 25 May 2026 17:26:02 +0000 Subject: [PATCH 5/6] ci: log musl fallback failures Agent-Logs-Url: https://github.com/HiGarfield/cpulimit/sessions/cdef6235-11f8-4d31-bae2-5a158e5a6b25 Co-authored-by: HiGarfield <32226909+HiGarfield@users.noreply.github.com> --- .github/workflows/CI.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 56cc3a3f..266272bb 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -83,10 +83,11 @@ jobs: MUSL_ARCHIVE_SHA256="1b7eceb2022f4a664028dd314c5c44332b601bd271e40f0934b4bc8fd3b0fcf5" if [ ! -s "${MUSL_ARCHIVE}" ]; then - curl -fL \ + if ! curl -fL \ "${MUSL_ARCHIVE_URL}" \ - -o "${MUSL_ARCHIVE}" \ - || true + -o "${MUSL_ARCHIVE}"; then + echo "Download from ${MUSL_ARCHIVE_URL} failed; trying artifact fallback." >&2 + fi fi if [ ! -s "${MUSL_ARCHIVE}" ]; then @@ -101,6 +102,8 @@ jobs: "${artifact_api_url}" \ -o "${artifact_json}"; then artifact_download_url="$(python3 -c 'import json, sys; payload = json.load(open(sys.argv[1], "r", encoding="utf-8")); artifact_name = sys.argv[2]; artifacts = [a for a in payload.get("artifacts", []) if a.get("name") == artifact_name and not a.get("expired")]; artifacts.sort(key=lambda a: a.get("created_at", ""), reverse=True); print(artifacts[0].get("archive_download_url", "") if artifacts else "")' "${artifact_json}" "${MUSL_ARTIFACT_NAME}")" + else + echo "Failed to query workflow artifacts; skipping artifact fallback lookup." >&2 fi if [ -n "${artifact_download_url}" ]; then curl -fL \ From 7a7b953bacd672766b4ad993eb39a72e1fb757b1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 25 May 2026 17:26:48 +0000 Subject: [PATCH 6/6] ci: harden musl archive checks Agent-Logs-Url: https://github.com/HiGarfield/cpulimit/sessions/cdef6235-11f8-4d31-bae2-5a158e5a6b25 Co-authored-by: HiGarfield <32226909+HiGarfield@users.noreply.github.com> --- .github/workflows/CI.yml | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 266272bb..a85af69e 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -95,6 +95,7 @@ jobs: artifact_json="${RUNNER_TEMP}/musl-i486-artifacts.json" artifact_zip="${RUNNER_TEMP}/musl-i486-artifact.zip" artifact_archive="${RUNNER_TEMP}/i486-linux-musl-cross.from-artifact.tgz" + artifact_entries="${RUNNER_TEMP}/musl-i486-artifact.entries" artifact_download_url="" if curl -fsSL \ -H "Authorization: Bearer ${GITHUB_TOKEN}" \ @@ -112,21 +113,29 @@ jobs: "${artifact_download_url}" \ -o "${artifact_zip}" rm -f "${artifact_archive}" - if unzip -Z -1 "${artifact_zip}" | grep -qx "i486-linux-musl-cross.tgz"; then - if unzip -p "${artifact_zip}" i486-linux-musl-cross.tgz > "${artifact_archive}"; then - mv -f "${artifact_archive}" "${MUSL_ARCHIVE}" + if unzip -Z -1 "${artifact_zip}" > "${artifact_entries}" 2>/dev/null; then + if grep -qx "i486-linux-musl-cross.tgz" "${artifact_entries}"; then + if unzip -p "${artifact_zip}" i486-linux-musl-cross.tgz > "${artifact_archive}"; then + mv -f "${artifact_archive}" "${MUSL_ARCHIVE}" + else + rm -f "${artifact_archive}" + echo "Failed to extract i486-linux-musl-cross.tgz from artifact; the workflow will fail if no other archive source succeeds." >&2 + fi else - rm -f "${artifact_archive}" - echo "Failed to extract i486-linux-musl-cross.tgz from artifact; the workflow will fail if no other archive source succeeds." >&2 + echo "Artifact is missing i486-linux-musl-cross.tgz; the workflow will fail if no other archive source succeeds." >&2 fi else - echo "Artifact is missing i486-linux-musl-cross.tgz; the workflow will fail if no other archive source succeeds." >&2 + echo "Failed to list artifact zip contents; the workflow will fail if no other archive source succeeds." >&2 fi + rm -f "${artifact_entries}" else echo "No non-expired ${MUSL_ARTIFACT_NAME} artifact is available; the workflow will fail if no other archive source succeeds." >&2 fi fi + if [ ! -s "${MUSL_ARCHIVE}" ]; then + echo "Failed to obtain musl toolchain archive from any source." >&2 + fi test -s "${MUSL_ARCHIVE}" printf '%s %s\n' "${MUSL_ARCHIVE_SHA256}" "${MUSL_ARCHIVE}" \ | sha256sum -c -