From c7e2d67a293471ed3d141525705e474bd7b3c628 Mon Sep 17 00:00:00 2001 From: Jacob Magar Date: Thu, 1 Oct 2026 01:11:00 -0400 Subject: [PATCH] fix(ci): isolate kache canary schemas and trusted credentials --- .github/workflows/hosted-incus-image.yml | 2 +- .github/workflows/hosted-kache-canary.yml | 31 ++++++++++++++++++++--- .github/workflows/hosted-rust-release.yml | 2 +- README.md | 4 +++ catalog.json | 2 +- tests/test_validate.py | 17 ++++++++++++- 6 files changed, 50 insertions(+), 8 deletions(-) diff --git a/.github/workflows/hosted-incus-image.yml b/.github/workflows/hosted-incus-image.yml index f555334..c6c443c 100644 --- a/.github/workflows/hosted-incus-image.yml +++ b/.github/workflows/hosted-incus-image.yml @@ -66,7 +66,7 @@ jobs: set -euo pipefail test -n "$KACHE_ACCESS_KEY" test -n "$KACHE_SECRET_KEY" - - uses: kunobi-ninja/kache-action@a257c055543c2840700a9bbca8f9c3094a421b1b + - uses: kunobi-ninja/kache-action@ad7317540dcdd71c904f7a60a87b620a0c0e67ed if: inputs.enable-kache with: version: '0.28.1' diff --git a/.github/workflows/hosted-kache-canary.yml b/.github/workflows/hosted-kache-canary.yml index a37ff41..ba0669a 100644 --- a/.github/workflows/hosted-kache-canary.yml +++ b/.github/workflows/hosted-kache-canary.yml @@ -21,9 +21,31 @@ env: CANARY_MANIFEST: ci/kache-hosted-canary/Cargo.toml CANARY_ROOT: ci/kache-hosted-canary KACHE_MANIFEST_KEY: hosted-canary-ubuntu-24.04-x64 + CANARY_CACHE_PREFIX: canary/kache-0.28.1/${{ github.run_id }} jobs: + pr-build: + name: Build canary without shared credentials + if: github.event_name == 'pull_request' + runs-on: ubuntu-24.04 + timeout-minutes: 15 + steps: + - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5 + with: + persist-credentials: false + - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 + with: + toolchain: "1.97.1" + - uses: kunobi-ninja/kache-action@ad7317540dcdd71c904f7a60a87b620a0c0e67ed # v1 + with: + version: '0.28.1' + github-cache: 'true' + max-size: '10GB' + pr-comment: 'false' + - name: Compile the canary + run: cargo build --release --locked --manifest-path "$CANARY_MANIFEST" seed: + if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' name: Seed hosted remote runs-on: ubuntu-24.04 timeout-minutes: 15 @@ -34,12 +56,12 @@ jobs: - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 with: toolchain: "1.97.1" - - uses: kunobi-ninja/kache-action@a257c055543c2840700a9bbca8f9c3094a421b1b + - uses: kunobi-ninja/kache-action@ad7317540dcdd71c904f7a60a87b620a0c0e67ed with: version: '0.28.1' s3-bucket: kache s3-region: us-east-1 - s3-prefix: canary + s3-prefix: ${{ env.CANARY_CACHE_PREFIX }} s3-endpoint: ${{ vars.KACHE_S3_ENDPOINT }} s3-access-key-id: ${{ secrets.KACHE_S3_ACCESS_KEY }} s3-secret-access-key: ${{ secrets.KACHE_S3_SECRET_KEY }} @@ -60,6 +82,7 @@ jobs: >> "$GITHUB_STEP_SUMMARY" verify: + if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' name: Verify fresh hosted remote reuse needs: [seed] runs-on: ubuntu-24.04 @@ -71,12 +94,12 @@ jobs: - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 with: toolchain: "1.97.1" - - uses: kunobi-ninja/kache-action@a257c055543c2840700a9bbca8f9c3094a421b1b + - uses: kunobi-ninja/kache-action@ad7317540dcdd71c904f7a60a87b620a0c0e67ed with: version: '0.28.1' s3-bucket: kache s3-region: us-east-1 - s3-prefix: canary + s3-prefix: ${{ env.CANARY_CACHE_PREFIX }} s3-endpoint: ${{ vars.KACHE_S3_ENDPOINT }} s3-access-key-id: ${{ secrets.KACHE_S3_ACCESS_KEY }} s3-secret-access-key: ${{ secrets.KACHE_S3_SECRET_KEY }} diff --git a/.github/workflows/hosted-rust-release.yml b/.github/workflows/hosted-rust-release.yml index b1de153..4465eb4 100644 --- a/.github/workflows/hosted-rust-release.yml +++ b/.github/workflows/hosted-rust-release.yml @@ -55,7 +55,7 @@ jobs: - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 with: toolchain: ${{ inputs.toolchain }} - - uses: kunobi-ninja/kache-action@a257c055543c2840700a9bbca8f9c3094a421b1b + - uses: kunobi-ninja/kache-action@ad7317540dcdd71c904f7a60a87b620a0c0e67ed with: version: '0.28.1' s3-bucket: kache diff --git a/README.md b/README.md index 421d773..13159d6 100644 --- a/README.md +++ b/README.md @@ -254,3 +254,7 @@ or self-hosted release jobs. ## License Original Dinglebear-authored portions of this project are licensed under [AGPL-3.0-only](LICENSE). Separate commercial licensing is available for organizations that need terms outside the AGPL. Third-party material remains under its original license. See [LICENSING.md](LICENSING.md). + +The hosted kache canary builds pull requests without shared cache credentials. +Trusted main runs seed and verify remote reuse in a version-and-run-specific +prefix, so prior key schemas cannot contaminate the probe. diff --git a/catalog.json b/catalog.json index 06b00ab..b1ed277 100644 --- a/catalog.json +++ b/catalog.json @@ -101,7 +101,7 @@ {"file": "hosted-container-release.yml", "kind": "release", "category": "container", "summary": "Build, smoke, scan, attest, and promote one linux/amd64 digest."}, {"file": "hosted-go-release.yml", "kind": "release", "category": "go", "summary": "Build x86_64 Go release archives and checksums."}, {"file": "hosted-incus-image.yml", "kind": "release", "category": "incus", "summary": "Build, optionally Kache, smoke, checksum, SBOM, and retain one hosted x86_64 Incus image."}, - {"file": "hosted-kache-canary.yml", "kind": "internal", "category": "rust", "summary": "Seed MinIO Kache on one hosted runner and require remote cache reuse on a second fresh runner."}, + {"file": "hosted-kache-canary.yml", "kind": "internal", "category": "rust", "summary": "Check PR builds without credentials; verify isolated MinIO reuse on trusted main runs."}, {"file": "hosted-python-package-release.yml", "kind": "release", "category": "python", "summary": "Build, verify, and trusted-publish wheel and sdist artifacts."}, {"file": "hosted-python-wheels.yml", "kind": "release", "category": "python", "summary": "Build native x86_64 Python wheels on hosted Linux, macOS, and Windows."}, {"file": "hosted-release-command.yml", "kind": "release", "category": "release", "summary": "Run one product-specific hosted release command and retain exact outputs."}, diff --git a/tests/test_validate.py b/tests/test_validate.py index fdf769c..24bf159 100644 --- a/tests/test_validate.py +++ b/tests/test_validate.py @@ -160,7 +160,7 @@ def test_marketplace_caches_are_independently_optional(self) -> None: def test_kache_action_uses_shard_capable_pin(self) -> None: pinned = ( "kunobi-ninja/kache-action" - "@a257c055543c2840700a9bbca8f9c3094a421b1b" + "@ad7317540dcdd71c904f7a60a87b620a0c0e67ed" ) for workflow_name in ( "hosted-incus-image.yml", @@ -172,6 +172,21 @@ def test_kache_action_uses_shard_capable_pin(self) -> None: self.assertIn("\n namespace:", text) self.assertIn('\n pr-comment: "false"', text) + def test_canary_keeps_shared_credentials_off_pull_requests(self) -> None: + workflow = yaml.load( + (ROOT / ".github/workflows/hosted-kache-canary.yml").read_text(), + Loader=yaml.BaseLoader, + ) + for job_name in ("seed", "verify"): + job = workflow["jobs"][job_name] + self.assertIn("github.event_name != 'pull_request'", job["if"]) + self.assertIn("github.ref == 'refs/heads/main'", job["if"]) + cache = next(step for step in job["steps"] if "kache-action@" in step.get("uses", "")) + self.assertEqual(cache["with"]["s3-prefix"], "${{ env.CANARY_CACHE_PREFIX }}") + self.assertIn("github.run_id", workflow["env"]["CANARY_CACHE_PREFIX"]) + self.assertIn("kache-0.28.1", workflow["env"]["CANARY_CACHE_PREFIX"]) + self.assertNotIn("secrets.", str(workflow["jobs"]["pr-build"])) + def test_platform_release_cache_stays_credentialless(self) -> None: workflow = yaml.load( (ROOT / ".github/workflows/hosted-rust-platform-release.yml").read_text(),