From baca561f7b437bcdbae626b2094c9e5954048a51 Mon Sep 17 00:00:00 2001 From: Matt Hammond Date: Tue, 26 May 2026 11:02:57 +0100 Subject: [PATCH 1/7] ci: pass workflow_dispatch inputs via env in package workflow Move `github.event.inputs.version` from inline expressions into step `env:` blocks so the value is interpolated by the shell rather than substituted into the shell command at workflow-rendering time. Addresses zizmor `template-injection` findings in the three packaging steps. --- .github/workflows/package.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index e6ec978c0..bae476f73 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -79,7 +79,9 @@ jobs: run: dotnet tool restore - name: Package - run: ./package.cmd ${{ github.event.inputs.version }} + env: + VERSION: ${{ github.event.inputs.version }} + run: ./package.cmd $env:VERSION - name: Archive package uses: actions/upload-artifact@v4 @@ -137,7 +139,9 @@ jobs: run: dotnet tool restore - name: Package Push (iOS & Android) - run: ./package-push.sh ${{ github.event.inputs.version }} + env: + VERSION: ${{ github.event.inputs.version }} + run: ./package-push.sh "$VERSION" - name: Archive push packages uses: actions/upload-artifact@v4 @@ -164,7 +168,9 @@ jobs: run: dotnet tool restore - name: Package Unity - run: ./package-unity.sh ${{ github.event.inputs.version }} + env: + VERSION: ${{ github.event.inputs.version }} + run: ./package-unity.sh "$VERSION" - name: Archive Unity package uses: actions/upload-artifact@v4 From 61abc483d10d8dd7effe087a033ca58919ba5db4 Mon Sep 17 00:00:00 2001 From: Matt Hammond Date: Tue, 26 May 2026 11:05:02 +0100 Subject: [PATCH 2/7] ci: pin third-party actions to commit SHAs Pin all `uses:` references to immutable commit hashes (with the resolved tag as a trailing comment), so a compromise of an upstream tag cannot silently change what runs in CI. The pinned versions match what the floating tags currently resolve to, so no behaviour change is intended. Addresses zizmor `unpinned-uses` findings. --- .github/workflows/features.yml | 2 +- .github/workflows/package.yml | 28 +++++++++---------- .github/workflows/run-tests-linux.yml | 4 +-- .github/workflows/run-tests-macos-mono.yml | 4 +-- .github/workflows/run-tests-macos.yml | 4 +-- .../run-tests-windows-netframework.yml | 4 +-- .github/workflows/run-tests-windows.yml | 4 +-- 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/.github/workflows/features.yml b/.github/workflows/features.yml index 778c89b6d..28cc4f7e6 100644 --- a/.github/workflows/features.yml +++ b/.github/workflows/features.yml @@ -8,7 +8,7 @@ on: jobs: build: - uses: ably/features/.github/workflows/sdk-features.yml@main + uses: ably/features/.github/workflows/sdk-features.yml@6b3fc7a8ede2ebdd7a6325314f3a96c6466f1453 # main as of 2026-05-26 with: repository-name: ably-dotnet secrets: inherit diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index bae476f73..f96ea5a58 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -24,12 +24,12 @@ jobs: package-library: runs-on: windows-2022 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: submodules: 'recursive' - name: Download dotnet framework - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 with: dotnet-version: | 3.1.426 @@ -37,7 +37,7 @@ jobs: 7.0.410 - name: Setup Android SDK - uses: android-actions/setup-android@v3 + uses: android-actions/setup-android@9fc6c4e9069bf8d3d10b2204b1fb8f6ef7065407 # v3.2.2 - name: Install Android SDK Platform 30 shell: pwsh @@ -84,7 +84,7 @@ jobs: run: ./package.cmd $env:VERSION - name: Archive package - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: ably-package path: | @@ -96,17 +96,17 @@ jobs: DOTNET_NOLOGO: true steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: submodules: 'recursive' - name: Setup Xcode - uses: maxim-lobanov/setup-xcode@v1 + uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1.7.0 with: xcode-version: '14.3' - name: Setup Android SDK - uses: android-actions/setup-android@v3 + uses: android-actions/setup-android@9fc6c4e9069bf8d3d10b2204b1fb8f6ef7065407 # v3.2.2 - name: Install Android SDK Platform 30 run: | @@ -114,7 +114,7 @@ jobs: yes | "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" "build-tools;30.0.3" - name: Download dotnet framework - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 with: dotnet-version: | 3.1.426 @@ -144,7 +144,7 @@ jobs: run: ./package-push.sh "$VERSION" - name: Archive push packages - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: ably-push-package path: | @@ -153,12 +153,12 @@ jobs: package-unity: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: submodules: 'recursive' - name: Download dotnet framework - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 with: dotnet-version: | 2.1.818 @@ -173,7 +173,7 @@ jobs: run: ./package-unity.sh "$VERSION" - name: Archive Unity package - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: ably-unity-package path: | @@ -184,7 +184,7 @@ jobs: needs: [package-library, package-push, package-unity] steps: - name: Download all artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: path: artifacts @@ -229,7 +229,7 @@ jobs: echo "Total files: $(ls -1 output-package | wc -l)" - name: Upload merged artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: output-package path: output-package/ diff --git a/.github/workflows/run-tests-linux.yml b/.github/workflows/run-tests-linux.yml index 074e64fc9..a41fb78f4 100644 --- a/.github/workflows/run-tests-linux.yml +++ b/.github/workflows/run-tests-linux.yml @@ -17,12 +17,12 @@ jobs: targetframework: [ "net6.0", "net7.0", "net8.0", "net9.0" ] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: submodules: 'recursive' - name: Download dotnet framework - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 with: dotnet-version: | 6.0.428 diff --git a/.github/workflows/run-tests-macos-mono.yml b/.github/workflows/run-tests-macos-mono.yml index cb0d4a1db..534cc8331 100644 --- a/.github/workflows/run-tests-macos-mono.yml +++ b/.github/workflows/run-tests-macos-mono.yml @@ -12,12 +12,12 @@ jobs: DOTNET_NOLOGO: true steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: submodules: 'recursive' - name: Download dotnet framework - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 with: dotnet-version: | 3.1.426 diff --git a/.github/workflows/run-tests-macos.yml b/.github/workflows/run-tests-macos.yml index 8aed4abff..9d51d8b8b 100644 --- a/.github/workflows/run-tests-macos.yml +++ b/.github/workflows/run-tests-macos.yml @@ -17,12 +17,12 @@ jobs: targetframework: [ "net6.0", "net7.0", "net8.0", "net9.0" ] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: submodules: 'recursive' - name: Download dotnet framework - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 with: dotnet-version: | 6.0.428 diff --git a/.github/workflows/run-tests-windows-netframework.yml b/.github/workflows/run-tests-windows-netframework.yml index aed622f01..14c0a4cd2 100644 --- a/.github/workflows/run-tests-windows-netframework.yml +++ b/.github/workflows/run-tests-windows-netframework.yml @@ -12,12 +12,12 @@ jobs: DOTNET_NOLOGO: true steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: submodules: 'recursive' - name: Download dotnet framework - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 with: dotnet-version: | 7.0.410 diff --git a/.github/workflows/run-tests-windows.yml b/.github/workflows/run-tests-windows.yml index 96996fc27..6b5b5f352 100644 --- a/.github/workflows/run-tests-windows.yml +++ b/.github/workflows/run-tests-windows.yml @@ -17,12 +17,12 @@ jobs: targetframework: [ "net6.0", "net7.0", "net8.0", "net9.0" ] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: submodules: 'recursive' - name: Download framework - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 with: dotnet-version: | 6.0.428 From f57bf0ce877206e02981d712f6c15cb799797ee6 Mon Sep 17 00:00:00 2001 From: Matt Hammond Date: Tue, 26 May 2026 11:05:51 +0100 Subject: [PATCH 3/7] ci: disable credential persistence in checkout steps Set `persist-credentials: false` on every `actions/checkout` step so the GITHUB_TOKEN is not left available to subsequent steps after the checkout completes. None of the workflows push back to the repo, so no compensating change is needed. Addresses zizmor `artipacked` findings. --- .github/workflows/package.yml | 3 +++ .github/workflows/run-tests-linux.yml | 1 + .github/workflows/run-tests-macos-mono.yml | 1 + .github/workflows/run-tests-macos.yml | 1 + .github/workflows/run-tests-windows-netframework.yml | 1 + .github/workflows/run-tests-windows.yml | 1 + 6 files changed, 8 insertions(+) diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index f96ea5a58..cb105241f 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -27,6 +27,7 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: submodules: 'recursive' + persist-credentials: false - name: Download dotnet framework uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 @@ -99,6 +100,7 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: submodules: 'recursive' + persist-credentials: false - name: Setup Xcode uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1.7.0 @@ -156,6 +158,7 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: submodules: 'recursive' + persist-credentials: false - name: Download dotnet framework uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 diff --git a/.github/workflows/run-tests-linux.yml b/.github/workflows/run-tests-linux.yml index a41fb78f4..1fd0ace7e 100644 --- a/.github/workflows/run-tests-linux.yml +++ b/.github/workflows/run-tests-linux.yml @@ -20,6 +20,7 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: submodules: 'recursive' + persist-credentials: false - name: Download dotnet framework uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 diff --git a/.github/workflows/run-tests-macos-mono.yml b/.github/workflows/run-tests-macos-mono.yml index 534cc8331..04687126c 100644 --- a/.github/workflows/run-tests-macos-mono.yml +++ b/.github/workflows/run-tests-macos-mono.yml @@ -15,6 +15,7 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: submodules: 'recursive' + persist-credentials: false - name: Download dotnet framework uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 diff --git a/.github/workflows/run-tests-macos.yml b/.github/workflows/run-tests-macos.yml index 9d51d8b8b..652265483 100644 --- a/.github/workflows/run-tests-macos.yml +++ b/.github/workflows/run-tests-macos.yml @@ -20,6 +20,7 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: submodules: 'recursive' + persist-credentials: false - name: Download dotnet framework uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 diff --git a/.github/workflows/run-tests-windows-netframework.yml b/.github/workflows/run-tests-windows-netframework.yml index 14c0a4cd2..8fbca38fd 100644 --- a/.github/workflows/run-tests-windows-netframework.yml +++ b/.github/workflows/run-tests-windows-netframework.yml @@ -15,6 +15,7 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: submodules: 'recursive' + persist-credentials: false - name: Download dotnet framework uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 diff --git a/.github/workflows/run-tests-windows.yml b/.github/workflows/run-tests-windows.yml index 6b5b5f352..2589f3794 100644 --- a/.github/workflows/run-tests-windows.yml +++ b/.github/workflows/run-tests-windows.yml @@ -20,6 +20,7 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: submodules: 'recursive' + persist-credentials: false - name: Download framework uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 From 5c848bbceadf89b8ed7249f8a7f34792e3501e98 Mon Sep 17 00:00:00 2001 From: Matt Hammond Date: Tue, 26 May 2026 11:07:07 +0100 Subject: [PATCH 4/7] ci: add explicit minimal workflow permissions Add a top-level `permissions: contents: read` block to every workflow so the GITHUB_TOKEN is scoped down from the repo's default rather than relying on whatever the default happens to be. None of these workflows need to write back to the repo (no commits, comments, releases or package publishing happens here), so read-only is enough. Addresses zizmor `excessive-permissions` findings. --- .github/workflows/features.yml | 3 +++ .github/workflows/package.yml | 3 +++ .github/workflows/run-tests-linux.yml | 3 +++ .github/workflows/run-tests-macos-mono.yml | 3 +++ .github/workflows/run-tests-macos.yml | 3 +++ .github/workflows/run-tests-windows-netframework.yml | 3 +++ .github/workflows/run-tests-windows.yml | 3 +++ 7 files changed, 21 insertions(+) diff --git a/.github/workflows/features.yml b/.github/workflows/features.yml index 28cc4f7e6..285da8850 100644 --- a/.github/workflows/features.yml +++ b/.github/workflows/features.yml @@ -6,6 +6,9 @@ on: branches: - main +permissions: + contents: read + jobs: build: uses: ably/features/.github/workflows/sdk-features.yml@6b3fc7a8ede2ebdd7a6325314f3a96c6466f1453 # main as of 2026-05-26 diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index cb105241f..76a52fcdc 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -20,6 +20,9 @@ on: description: 'Ably version' required: true +permissions: + contents: read + jobs: package-library: runs-on: windows-2022 diff --git a/.github/workflows/run-tests-linux.yml b/.github/workflows/run-tests-linux.yml index 1fd0ace7e..e2c7f04ac 100644 --- a/.github/workflows/run-tests-linux.yml +++ b/.github/workflows/run-tests-linux.yml @@ -5,6 +5,9 @@ on: branches: - main +permissions: + contents: read + jobs: check: runs-on: ubuntu-22.04 diff --git a/.github/workflows/run-tests-macos-mono.yml b/.github/workflows/run-tests-macos-mono.yml index 04687126c..aadc89e9b 100644 --- a/.github/workflows/run-tests-macos-mono.yml +++ b/.github/workflows/run-tests-macos-mono.yml @@ -5,6 +5,9 @@ on: branches: - main +permissions: + contents: read + jobs: check: runs-on: macos-14 diff --git a/.github/workflows/run-tests-macos.yml b/.github/workflows/run-tests-macos.yml index 652265483..a081592e1 100644 --- a/.github/workflows/run-tests-macos.yml +++ b/.github/workflows/run-tests-macos.yml @@ -5,6 +5,9 @@ on: branches: - main +permissions: + contents: read + jobs: check: runs-on: macos-14 diff --git a/.github/workflows/run-tests-windows-netframework.yml b/.github/workflows/run-tests-windows-netframework.yml index 8fbca38fd..960f7fda7 100644 --- a/.github/workflows/run-tests-windows-netframework.yml +++ b/.github/workflows/run-tests-windows-netframework.yml @@ -5,6 +5,9 @@ on: branches: - main +permissions: + contents: read + jobs: check: runs-on: windows-2022 diff --git a/.github/workflows/run-tests-windows.yml b/.github/workflows/run-tests-windows.yml index 2589f3794..85e037faa 100644 --- a/.github/workflows/run-tests-windows.yml +++ b/.github/workflows/run-tests-windows.yml @@ -5,6 +5,9 @@ on: branches: - main +permissions: + contents: read + jobs: check: runs-on: windows-2022 From b74cd9dcec7c0c43737818e8699e65f48ff24924 Mon Sep 17 00:00:00 2001 From: Matt Hammond Date: Tue, 26 May 2026 11:07:48 +0100 Subject: [PATCH 5/7] ci: pass only the required secret to the features workflow The reusable `ably/features/.github/workflows/sdk-features.yml` workflow declares one required secret (`ABLY_AWS_ACCOUNT_ID_SDK`) plus the auto-provided GITHUB_TOKEN, so there is no reason to forward every secret on this repo to it. Replace `secrets: inherit` with an explicit map containing just that secret. Addresses zizmor `secrets-inherit` finding. --- .github/workflows/features.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/features.yml b/.github/workflows/features.yml index 285da8850..6e415a3dc 100644 --- a/.github/workflows/features.yml +++ b/.github/workflows/features.yml @@ -14,4 +14,5 @@ jobs: uses: ably/features/.github/workflows/sdk-features.yml@6b3fc7a8ede2ebdd7a6325314f3a96c6466f1453 # main as of 2026-05-26 with: repository-name: ably-dotnet - secrets: inherit + secrets: + ABLY_AWS_ACCOUNT_ID_SDK: ${{ secrets.ABLY_AWS_ACCOUNT_ID_SDK }} From 303b5948e3c6accd5500b01b7b055dc1ea17f7f4 Mon Sep 17 00:00:00 2001 From: Matt Hammond Date: Tue, 26 May 2026 11:25:30 +0100 Subject: [PATCH 6/7] ci: keep ably/features reusable workflow tracking main MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Revert the SHA pin on `ably/features/.github/workflows/sdk-features.yml` back to `@main`. This workflow is the SDK feature-spec compliance suite — pinning it freezes the spec under test, which defeats the purpose of running it on every PR. The repo is org-owned and trusted, so the `unpinned-uses` finding is suppressed inline rather than fixed. --- .github/workflows/features.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/features.yml b/.github/workflows/features.yml index 6e415a3dc..46e4ea7cd 100644 --- a/.github/workflows/features.yml +++ b/.github/workflows/features.yml @@ -11,7 +11,8 @@ permissions: jobs: build: - uses: ably/features/.github/workflows/sdk-features.yml@6b3fc7a8ede2ebdd7a6325314f3a96c6466f1453 # main as of 2026-05-26 + # Track the live SDK feature spec on main rather than pinning. + uses: ably/features/.github/workflows/sdk-features.yml@main # zizmor: ignore[unpinned-uses] with: repository-name: ably-dotnet secrets: From bea3f78d68d96a72a1179dc42fe47112493f9d6d Mon Sep 17 00:00:00 2001 From: Matt Hammond Date: Thu, 25 Jun 2026 22:33:59 +0100 Subject: [PATCH 7/7] ci: grant sdk-features reusable workflow required permissions The reusable ably/features sdk-features.yml job needs deployments:write and id-token:write (OIDC AWS auth + deployment upload). The top-level contents:read added during workflow hardening stripped these, causing an invisible startup failure of the Features workflow. Grant the required scopes at the build job level (least privilege) and default the top level to no permissions. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/features.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/features.yml b/.github/workflows/features.yml index 46e4ea7cd..7996318f2 100644 --- a/.github/workflows/features.yml +++ b/.github/workflows/features.yml @@ -6,11 +6,14 @@ on: branches: - main -permissions: - contents: read +permissions: {} jobs: build: + permissions: + contents: read + deployments: write + id-token: write # Track the live SDK feature spec on main rather than pinning. uses: ably/features/.github/workflows/sdk-features.yml@main # zizmor: ignore[unpinned-uses] with: