From a7d8b554d22e44297f5df29873c194cefb87025c Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 1 Mar 2026 10:03:00 +1100 Subject: [PATCH 1/6] ci: pin redis image to SHA digest and add Docker Hub auth Fixes Docker Hub unauthenticated rate limit errors on self-hosted runners by adding credentials block and pinning redis:7-alpine to its amd64 manifest digest. --- .github/workflows/ci.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1c0aefa..f944059 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -128,7 +128,10 @@ jobs: services: redis: - image: redis:7-alpine + image: redis@sha256:4bfd9eca23339865dc14fe75f6d9ae643f714924623978dd2798f1a673b08f43 # redis:7-alpine amd64 + credentials: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} ports: - 6379:6379 options: >- From 804f45a232d1a5cacb0227e80874d605b01ffeb2 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 1 Mar 2026 10:33:36 +1100 Subject: [PATCH 2/6] ci: retrigger after setting DOCKERHUB_TOKEN org secret From 880e4576d061ee0bfdf206cffa63c2063c5cb76c Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 1 Mar 2026 10:55:43 +1100 Subject: [PATCH 3/6] ci: use self-hosted runners for all CI events --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f944059..e13827d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -116,7 +116,7 @@ jobs: # PRs: runs on GitHub-hosted runners (untrusted code never touches lab infra) test-critical: name: Tests (Python ${{ matrix.python-version }}) - runs-on: ${{ github.event_name == 'push' && 'cachekit' || 'ubuntu-latest' }} + runs-on: cachekit timeout-minutes: 15 permissions: contents: read From 4eac7a95f2daf4369d90a6448136d754ddb8c798 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 1 Mar 2026 10:59:19 +1100 Subject: [PATCH 4/6] ci: slim PR pipeline to single Python version, defer full matrix to push PR: lint + critical tests on Python 3.12 only (1 runner) Push: full 6-version matrix + doc tests + version check + pip-audit --- .github/workflows/ci.yml | 108 ++++++++++++++------------------------- 1 file changed, 37 insertions(+), 71 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e13827d..916903c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,32 +22,10 @@ concurrency: cancel-in-progress: true jobs: - # Fast version consistency check - version-check: - name: Version Sync - runs-on: ubuntu-latest - timeout-minutes: 5 - steps: - - uses: actions/checkout@v4 - - - name: Check Python ↔ Rust version consistency - run: | - PYTHON_VERSION=$(grep -E "^version = " pyproject.toml | head -1 | cut -d'"' -f2) - RUST_VERSION=$(grep -E "^version = " rust/Cargo.toml | head -1 | cut -d'"' -f2) - - echo "Python: $PYTHON_VERSION" - echo "Rust: $RUST_VERSION" - - if [ "$PYTHON_VERSION" != "$RUST_VERSION" ]; then - echo "❌ Version mismatch!" - exit 1 - fi - echo "✅ Versions in sync: $PYTHON_VERSION" - - # Fast format & lint checks (parallel) + # Lint, format, type check (runs on all events) quick-check: name: Format & Lint - runs-on: ubuntu-latest + runs-on: cachekit timeout-minutes: 10 steps: - uses: actions/checkout@v4 @@ -79,42 +57,30 @@ jobs: venv-${{ runner.os }}-py${{ env.DEFAULT_PYTHON_VERSION }}- - name: Install dependencies (if not cached) - run: | - uv sync --group dev + run: uv sync --group dev - name: Check Python formatting - run: | - uv run ruff format --check . + run: uv run ruff format --check . - name: Lint Python if: success() || failure() - run: | - uv run ruff check . - - - name: Scan Python dependencies for CVEs - if: success() || failure() - run: | - uv run pip-audit --desc + run: uv run ruff check . - name: Type check Python if: success() || failure() - run: | - uv run basedpyright --level error + run: uv run basedpyright --level error - name: Check Rust formatting if: success() || failure() - run: | - cd rust && cargo fmt --check + run: cd rust && cargo fmt --check - name: Lint Rust if: success() || failure() - run: | - cd rust && cargo clippy -- -D warnings + run: cd rust && cargo clippy -- -D warnings - # Critical test suite (parallel matrix) - # Push to main: runs on lab self-hosted runners (consistent perf, free minutes) - # PRs: runs on GitHub-hosted runners (untrusted code never touches lab infra) - test-critical: + # PR: single Python version, critical tests only + # Push: full matrix, full test suite + test: name: Tests (Python ${{ matrix.python-version }}) runs-on: cachekit timeout-minutes: 15 @@ -124,7 +90,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] + python-version: ${{ github.event_name == 'push' && fromJSON('["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]') || fromJSON('["3.12"]') }} services: redis: @@ -168,8 +134,7 @@ jobs: venv-${{ runner.os }}-py${{ matrix.python-version }}- - name: Install dependencies (if not cached) - run: | - uv sync --group dev + run: uv sync --group dev - name: Run critical tests (PRs) if: github.event_name == 'pull_request' @@ -215,14 +180,24 @@ jobs: flags: ${{ github.event_name == 'push' && 'full' || 'critical' }}-python-${{ matrix.python-version }} fail_ci_if_error: false - # Markdown documentation tests - test-docs: - name: Documentation Examples - runs-on: ubuntu-latest + # Version sync + doc tests (push to main only) + post-merge: + name: Post-Merge Checks + if: github.event_name == 'push' + runs-on: cachekit timeout-minutes: 10 steps: - uses: actions/checkout@v4 + - name: Check Python ↔ Rust version consistency + run: | + PYTHON_VERSION=$(grep -E "^version = " pyproject.toml | head -1 | cut -d'"' -f2) + RUST_VERSION=$(grep -E "^version = " rust/Cargo.toml | head -1 | cut -d'"' -f2) + if [ "$PYTHON_VERSION" != "$RUST_VERSION" ]; then + echo "Version mismatch: Python=$PYTHON_VERSION Rust=$RUST_VERSION" + exit 1 + fi + - name: Install uv uses: astral-sh/setup-uv@v3 with: @@ -239,36 +214,27 @@ jobs: with: workspaces: rust - - name: Cache Python virtual environment - uses: actions/cache@v4 - with: - path: .venv - key: venv-${{ runner.os }}-py${{ env.DEFAULT_PYTHON_VERSION }}-${{ hashFiles('**/pyproject.toml', '**/uv.lock', 'rust/**/*.rs', 'rust/**/Cargo.toml') }} - restore-keys: | - venv-${{ runner.os }}-py${{ env.DEFAULT_PYTHON_VERSION }}- - - name: Install dependencies (if not cached) - run: | - uv sync --group dev + run: uv sync --group dev + + - name: Scan Python dependencies for CVEs + run: uv run pip-audit --desc - name: Run markdown documentation tests - run: | - make test-docs-examples + run: make test-docs-examples # Summary job (required for branch protection) ci-success: name: CI Success runs-on: ubuntu-latest - needs: [version-check, quick-check, test-critical, test-docs] + needs: [quick-check, test] if: always() steps: - name: Check all jobs succeeded run: | - if [[ "${{ needs.version-check.result }}" != "success" ]] || \ - [[ "${{ needs.quick-check.result }}" != "success" ]] || \ - [[ "${{ needs.test-critical.result }}" != "success" ]] || \ - [[ "${{ needs.test-docs.result }}" != "success" ]]; then - echo "❌ One or more jobs failed" + if [[ "${{ needs.quick-check.result }}" != "success" ]] || \ + [[ "${{ needs.test.result }}" != "success" ]]; then + echo "One or more jobs failed" exit 1 fi - echo "✅ All CI checks passed" + echo "All CI checks passed" From 9aebcf9e33068702dd0965845f759b31badd492d Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 1 Mar 2026 11:26:11 +1100 Subject: [PATCH 5/6] ci: remove redundant toolchain setup steps uv, Rust stable (rustfmt, clippy), and Python 3.9-3.14 are now baked into the custom runner image (ghcr.io/cachekit-io/runner). Removes per-job: setup-uv action, uv python install, dtolnay/rust-toolchain. Keeps: Swatinem/rust-cache and actions/cache for compiled artifacts. --- .github/workflows/ci.yml | 37 +------------------------------------ 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 916903c..33c1c69 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,19 +30,6 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Install uv - uses: astral-sh/setup-uv@v3 - with: - enable-cache: true - - - name: Set up Python - run: uv python install ${{ env.DEFAULT_PYTHON_VERSION }} - - - name: Set up Rust - uses: dtolnay/rust-toolchain@stable - with: - components: rustfmt, clippy - - name: Cache Rust dependencies uses: Swatinem/rust-cache@v2 with: @@ -109,17 +96,6 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Install uv - uses: astral-sh/setup-uv@v3 - with: - enable-cache: true - - - name: Set up Python - run: uv python install ${{ matrix.python-version }} - - - name: Set up Rust - uses: dtolnay/rust-toolchain@stable - - name: Cache Rust dependencies uses: Swatinem/rust-cache@v2 with: @@ -134,7 +110,7 @@ jobs: venv-${{ runner.os }}-py${{ matrix.python-version }}- - name: Install dependencies (if not cached) - run: uv sync --group dev + run: uv sync --python ${{ matrix.python-version }} --group dev - name: Run critical tests (PRs) if: github.event_name == 'pull_request' @@ -198,17 +174,6 @@ jobs: exit 1 fi - - name: Install uv - uses: astral-sh/setup-uv@v3 - with: - enable-cache: true - - - name: Set up Python - run: uv python install ${{ env.DEFAULT_PYTHON_VERSION }} - - - name: Set up Rust - uses: dtolnay/rust-toolchain@stable - - name: Cache Rust dependencies uses: Swatinem/rust-cache@v2 with: From f5496abe2584fcd252a301c746d07d532fa5bd38 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 1 Mar 2026 11:26:42 +1100 Subject: [PATCH 6/6] ci: bump actions to latest majors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - actions/checkout v4 → v6 - actions/cache v4 → v5 --- .github/workflows/ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 33c1c69..49856ee 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: runs-on: cachekit timeout-minutes: 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Cache Rust dependencies uses: Swatinem/rust-cache@v2 @@ -36,7 +36,7 @@ jobs: workspaces: rust - name: Cache Python virtual environment - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: .venv key: venv-${{ runner.os }}-py${{ env.DEFAULT_PYTHON_VERSION }}-${{ hashFiles('**/pyproject.toml', '**/uv.lock', 'rust/**/*.rs', 'rust/**/Cargo.toml') }} @@ -94,7 +94,7 @@ jobs: --health-retries 5 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Cache Rust dependencies uses: Swatinem/rust-cache@v2 @@ -102,7 +102,7 @@ jobs: workspaces: rust - name: Cache Python virtual environment - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: .venv key: venv-${{ runner.os }}-py${{ matrix.python-version }}-${{ hashFiles('**/pyproject.toml', '**/uv.lock', 'rust/**/*.rs', 'rust/**/Cargo.toml') }} @@ -163,7 +163,7 @@ jobs: runs-on: cachekit timeout-minutes: 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Check Python ↔ Rust version consistency run: |