From 7c1a217929c2267112e71f2cf32388020ddf1222 Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Wed, 17 Jun 2026 18:18:57 +0200 Subject: [PATCH 1/4] ci: zizmor security hardening, latest action versions, audit + Dependabot Harden ci.yml to pass zizmor (49 findings -> 0): - Bump every action to its latest release as of today, then pin to commit SHA (with version comments for Dependabot): checkout v4->v6.0.3, setup-uv v6->v8.2.0, actions/cache v4->v5.0.5, simulator-action v4->v5, gradle/actions v3->v6.2.0, android-emulator-runner v2.37.0, subosito/flutter-action v2.23.0, flutter-fvm-config-action v3.3. - persist-credentials: false on all checkouts (no job pushes via git; publish only reads tags with git describe). - Least-privilege top-level permissions: contents: read (publish uses PUB_DEV_TOKEN, not GITHUB_TOKEN). - template-injection: move simulator UDID output into env:. - cache-poisoning: disable caching on tag/release refs only (per zizmor remediation) so branch/PR CI stays fast while release builds cannot restore a poisoned cache: setup-uv enable-cache and gradle cache-disabled gated on github.ref, AVD cache lookup-only on tags. Add .github/workflows/zizmor.yml (official zizmor-action on push/PR -> code scanning) and .github/dependabot.yml (github-actions, monthly, grouped, 7-day cooldown). --- .github/dependabot.yml | 17 +++++++++ .github/workflows/ci.yml | 69 +++++++++++++++++++++++++----------- .github/workflows/zizmor.yml | 23 ++++++++++++ 3 files changed, 88 insertions(+), 21 deletions(-) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/zizmor.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..49cab949 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,17 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + # Check for updates monthly, 8PM UTC + interval: "monthly" + time: "20:00" + # Wait a week after a release before proposing it — lets malicious/broken + # releases get caught and yanked before we pull them. + cooldown: + default-days: 7 + # Bundle all action bumps into a single monthly PR instead of one PR per action. + groups: + github-actions: + patterns: + - "*" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f1f7b112..6470c145 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,9 @@ env: SERIOUS_PYTHON_SITE_PACKAGES: "${{ github.workspace }}/site-packages" UV_PYTHON: "3.12" +permissions: + contents: read + jobs: macos: name: Test on macOS (Python ${{ matrix.python_version }}) @@ -27,10 +30,12 @@ jobs: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + uses: kuhnroyal/flutter-fvm-config-action/setup@c378498f1d1962d33039c3989411093ef8a17b2c # v3.3 with: path: '.fvmrc' cache: true @@ -52,17 +57,19 @@ jobs: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + uses: kuhnroyal/flutter-fvm-config-action/setup@c378498f1d1962d33039c3989411093ef8a17b2c # v3.3 with: path: '.fvmrc' cache: true - name: Setup iOS Simulator id: simulator - uses: futureware-tech/simulator-action@v4 + uses: futureware-tech/simulator-action@e89aa8f93d3aec35083ff49d2854d07f7186f7f5 # v5 with: # https://github.com/futureware-tech/simulator-action/wiki/Devices-macos-latest model: 'iPhone 16 Pro Max' @@ -73,9 +80,11 @@ jobs: - name: Run tests working-directory: "src/serious_python/example/flet_example" + env: + STEPS_SIMULATOR_OUTPUTS_UDID: ${{ steps.simulator.outputs.udid }} run: | dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements flet==0.28.3 - flutter test integration_test --device-id ${{ steps.simulator.outputs.udid }} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} + flutter test integration_test --device-id ${STEPS_SIMULATOR_OUTPUTS_UDID} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} android: name: Test on Android (Python ${{ matrix.python_version }}) @@ -88,10 +97,12 @@ jobs: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + uses: kuhnroyal/flutter-fvm-config-action/setup@c378498f1d1962d33039c3989411093ef8a17b2c # v3.3 with: path: '.fvmrc' cache: true @@ -103,19 +114,24 @@ jobs: sudo udevadm trigger --name-match=kvm - name: Gradle cache - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 + with: + # Disable the Gradle cache on tag/release builds to avoid cache poisoning. + cache-disabled: ${{ startsWith(github.ref, 'refs/tags/') }} - name: AVD cache - uses: actions/cache@v4 + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 id: avd-cache with: path: | ~/.android/avd/* ~/.android/adb* key: avd + # Disable cache restore on tag/release builds to avoid cache poisoning. + lookup-only: ${{ startsWith(github.ref, 'refs/tags/') }} - name: Setup Android Emulator + Run tests - uses: reactivecircus/android-emulator-runner@v2 + uses: reactivecircus/android-emulator-runner@e89f39f1abbbd05b1113a29cf4db69e7540cae5a # v2.37.0 env: EMULATOR_PORT: 5554 with: @@ -147,10 +163,12 @@ jobs: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + uses: kuhnroyal/flutter-fvm-config-action/setup@c378498f1d1962d33039c3989411093ef8a17b2c # v3.3 with: path: '.fvmrc' cache: true @@ -180,19 +198,24 @@ jobs: SERIOUS_PYTHON_VERSION: ${{ matrix.python_version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false - name: Setup uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 + with: + # Disable the uv cache on tag/release builds to avoid cache poisoning. + enable-cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Get Flutter version from ".fvmrc" - uses: kuhnroyal/flutter-fvm-config-action/config@v3 + uses: kuhnroyal/flutter-fvm-config-action/config@c378498f1d1962d33039c3989411093ef8a17b2c # v3.3 id: fvm-config-action with: path: '.fvmrc' - name: Setup Flutter - uses: subosito/flutter-action@v2 + uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2.23.0 with: flutter-version: ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }} channel: ${{ matrix.arch == 'arm64' && 'master' || 'stable' }} # https://github.com/subosito/flutter-action/issues/345#issuecomment-2657332687 @@ -249,15 +272,19 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: fetch-depth: 0 + persist-credentials: false - name: Setup uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 + with: + # Disable the uv cache on tag/release builds to avoid cache poisoning. + enable-cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + uses: kuhnroyal/flutter-fvm-config-action/setup@c378498f1d1962d33039c3989411093ef8a17b2c # v3.3 with: path: '.fvmrc' cache: true @@ -321,4 +348,4 @@ jobs: publish_pkg src/serious_python_windows publish_pkg src/serious_python_linux sleep 600 - publish_pkg src/serious_python \ No newline at end of file + publish_pkg src/serious_python diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml new file mode 100644 index 00000000..aaae4823 --- /dev/null +++ b/.github/workflows/zizmor.yml @@ -0,0 +1,23 @@ +name: zizmor - GitHub Actions Security Analysis + +on: + push: + pull_request: + +permissions: {} + +jobs: + zizmor: + name: Run zizmor + runs-on: ubuntu-latest + permissions: + security-events: write + contents: read + steps: + - name: Checkout + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false + + - name: Run zizmor + uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6 From e782dc1ec184613fd339caba6c063bcf3a8daa9c Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Wed, 17 Jun 2026 19:20:38 +0200 Subject: [PATCH 2/4] improvements --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6470c145..c8b9ea23 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -81,10 +81,10 @@ jobs: - name: Run tests working-directory: "src/serious_python/example/flet_example" env: - STEPS_SIMULATOR_OUTPUTS_UDID: ${{ steps.simulator.outputs.udid }} + SIMULATOR_UDID: ${{ steps.simulator.outputs.udid }} run: | dart run serious_python:main package app/src --platform iOS --python-version ${{ matrix.python_version }} --requirements flet==0.28.3 - flutter test integration_test --device-id ${STEPS_SIMULATOR_OUTPUTS_UDID} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} + flutter test integration_test --device-id ${SIMULATOR_UDID} --dart-define=EXPECTED_PYTHON_VERSION=${{ matrix.python_version }} android: name: Test on Android (Python ${{ matrix.python_version }}) From 03b0a470b6b25acde77f29a22cb35bbfeb87a585 Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Wed, 17 Jun 2026 20:27:28 +0200 Subject: [PATCH 3/4] ci: skip zizmor SARIF upload on fork PRs [skip ci] Fork PRs run with a read-only GITHUB_TOKEN (no security-events: write), so the code-scanning SARIF upload fails and reddens the check for external contributors. Gate advanced-security on the PR not being from a fork: forks still get inline annotations, while pushes and same-repo PRs upload to the Security tab. --- .github/workflows/zizmor.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index aaae4823..e9ba32c0 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -21,3 +21,8 @@ jobs: - name: Run zizmor uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6 + with: + # Fork PRs get a read-only token (no security-events: write), so the + # SARIF upload would fail. Skip it for forks — they still get inline + # annotations; pushes and same-repo PRs upload to code scanning. + advanced-security: ${{ github.event.pull_request.head.repo.fork != true }} From 65363f152f9a4456759ffc5c263bf958461683d5 Mon Sep 17 00:00:00 2001 From: ndonkoHenri Date: Wed, 17 Jun 2026 23:25:52 +0200 Subject: [PATCH 4/4] ci: drop dependabot config from this PR Keep this PR focused on zizmor security hardening; Dependabot to be handled separately. --- .github/dependabot.yml | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 49cab949..00000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,17 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "github-actions" - directory: "/" - schedule: - # Check for updates monthly, 8PM UTC - interval: "monthly" - time: "20:00" - # Wait a week after a release before proposing it — lets malicious/broken - # releases get caught and yanked before we pull them. - cooldown: - default-days: 7 - # Bundle all action bumps into a single monthly PR instead of one PR per action. - groups: - github-actions: - patterns: - - "*"