From 5c6143d08e9c83b268be2f4477b75a974e2ff52c Mon Sep 17 00:00:00 2001 From: Matt Hammond Date: Fri, 22 May 2026 16:45:43 +0100 Subject: [PATCH 1/7] ci: pin GitHub Actions to commit SHAs across all workflows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pin every `uses:` reference in the 7 workflow files to a 40-character commit SHA, preserving the original tag as a trailing comment. Versions are not changed — each action is pinned to the commit that the previously-floating tag resolved to at the time of this commit. This mitigates supply-chain risk from compromised or moved tags: a malicious actor able to force-push a tag in a third-party action repo can no longer affect this repository's CI without first compromising a specific SHA that has already been vetted here. Includes the reusable workflow reference in features.yml (`ably/features/.github/workflows/sdk-features.yml`), which was previously tracking `@main`. --- .github/workflows/check.yml | 6 ++--- .github/workflows/emulate.yml | 10 ++++---- .github/workflows/example-app.yml | 8 +++--- .github/workflows/features.yml | 2 +- .github/workflows/integration-test.yml | 34 +++++++++++++------------- .github/workflows/javadoc.yml | 10 ++++---- .github/workflows/release.yaml | 6 ++--- 7 files changed, 38 insertions(+), 38 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 0ae15c491..62330995d 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -11,12 +11,12 @@ jobs: check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3 - name: Set up the JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@17f84c3641ba7b8f6deff6309fc4c864478f5d62 # v3 with: java-version: '17' distribution: 'temurin' - name: Set up Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3 - run: ./gradlew checkWithCodenarc checkstyleMain checkstyleTest runUnitTests runLiveObjectUnitTests diff --git a/.github/workflows/emulate.yml b/.github/workflows/emulate.yml index eca63a3eb..910ed0cd8 100644 --- a/.github/workflows/emulate.yml +++ b/.github/workflows/emulate.yml @@ -16,16 +16,16 @@ jobs: steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Set up the JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@17f84c3641ba7b8f6deff6309fc4c864478f5d62 # v3 with: java-version: '17' distribution: 'temurin' - name: Set up Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5 timeout-minutes: 5 # API 30+ emulators only have x86_64 system images. @@ -38,7 +38,7 @@ jobs: sudo udevadm control --reload-rules sudo udevadm trigger --name-match=kvm - - uses: reactivecircus/android-emulator-runner@v2 + - uses: reactivecircus/android-emulator-runner@e89f39f1abbbd05b1113a29cf4db69e7540cae5a # v2 with: api-level: ${{ matrix.android-api-level }} emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none @@ -48,7 +48,7 @@ jobs: # Print emulator logs if tests fail script: ./gradlew :android:connectedAndroidTest ${{ matrix.android-api-level == 19 && '-PhttpURLConnection' || '' }} || (adb logcat -d System.out:I && exit 1) - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 if: always() with: name: android-build-reports-${{ matrix.android-api-level }} diff --git a/.github/workflows/example-app.yml b/.github/workflows/example-app.yml index 454594810..10a7d1187 100644 --- a/.github/workflows/example-app.yml +++ b/.github/workflows/example-app.yml @@ -16,16 +16,16 @@ jobs: steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Set up the JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@17f84c3641ba7b8f6deff6309fc4c864478f5d62 # v3 with: java-version: '17' distribution: 'temurin' - name: Set up Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3 - name: Enable KVM run: | @@ -33,7 +33,7 @@ jobs: sudo udevadm control --reload-rules sudo udevadm trigger --name-match=kvm - - uses: reactivecircus/android-emulator-runner@v2 + - uses: reactivecircus/android-emulator-runner@e89f39f1abbbd05b1113a29cf4db69e7540cae5a # v2 with: api-level: ${{ matrix.android-api-level }} emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none diff --git a/.github/workflows/features.yml b/.github/workflows/features.yml index bf45ed810..2f2d3bc75 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 with: repository-name: ably-java secrets: inherit diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 373926f2d..ce2291a73 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -11,22 +11,22 @@ jobs: check-rest-httpurlconnection: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: submodules: 'recursive' - name: Set up the JDK - uses: actions/setup-java@v4 + uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4 with: java-version: '17' distribution: 'temurin' - name: Set up Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3 - run: ./gradlew :java:testRestSuite -PhttpURLConnection - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 if: always() with: name: java-build-reports-rest @@ -35,22 +35,22 @@ jobs: check-realtime-httpurlconnection: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: submodules: 'recursive' - name: Set up the JDK - uses: actions/setup-java@v4 + uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4 with: java-version: '17' distribution: 'temurin' - name: Set up Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3 - run: ./gradlew :java:testRealtimeSuite -PhttpURLConnection - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 if: always() with: name: java-build-reports-realtime @@ -58,53 +58,53 @@ jobs: check-rest-okhttp: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: submodules: 'recursive' - name: Set up the JDK - uses: actions/setup-java@v4 + uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4 with: java-version: '17' distribution: 'temurin' - name: Set up Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3 - run: ./gradlew :java:testRestSuite check-realtime-okhttp: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: submodules: 'recursive' - name: Set up the JDK - uses: actions/setup-java@v4 + uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4 with: java-version: '17' distribution: 'temurin' - name: Set up Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3 - run: ./gradlew :java:testRealtimeSuite check-liveobjects: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: submodules: 'recursive' - name: Set up the JDK - uses: actions/setup-java@v4 + uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4 with: java-version: '17' distribution: 'temurin' - name: Set up Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3 - run: ./gradlew runLiveObjectIntegrationTests diff --git a/.github/workflows/javadoc.yml b/.github/workflows/javadoc.yml index 504c014b4..b3dc35d17 100644 --- a/.github/workflows/javadoc.yml +++ b/.github/workflows/javadoc.yml @@ -13,29 +13,29 @@ jobs: id-token: write deployments: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v1 + uses: aws-actions/configure-aws-credentials@67fbcbb121271f7775d2e7715933280b06314838 # v1 with: aws-region: eu-west-2 role-to-assume: arn:aws:iam::${{ secrets.ABLY_AWS_ACCOUNT_ID_SDK }}:role/ably-sdk-builds-ably-java role-session-name: "${{ github.run_id }}-${{ github.run_number }}" - name: Set up the JDK - uses: actions/setup-java@v4 + uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4 with: java-version: '17' distribution: 'temurin' - name: Set up Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3 - name: Build docs run: ./gradlew javadoc - name: Upload Documentation - uses: ably/sdk-upload-action@v2 + uses: ably/sdk-upload-action@4e694297f208b72b5a9f6b1248a1556f19f821d6 # v2 with: sourcePath: java/build/docs/javadoc githubToken: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 44a6814fe..7aa1bf678 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -9,7 +9,7 @@ jobs: if: github.repository == 'ably/ably-java' steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Extract tag id: tag @@ -34,13 +34,13 @@ jobs: TAG: ${{ steps.tag.outputs.tag }} - name: Set up JDK - uses: actions/setup-java@v4 + uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4 with: java-version: 17 distribution: temurin - name: Set up Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3 - name: Publish and release to Maven Central run: ./gradlew publishAndReleaseToMavenCentral From c08ae40fa98df8eaecaf497b562817a9dba85e95 Mon Sep 17 00:00:00 2001 From: Matt Hammond Date: Fri, 22 May 2026 16:46:30 +0100 Subject: [PATCH 2/7] ci(integration-test): scope GITHUB_TOKEN to contents:read per job Add an explicit `permissions: contents: read` block to each of the 5 jobs in the Integration Test workflow. Previously the workflow relied on the repository default token permissions, which grant broader write scopes than these jobs need. These jobs only check out source (read), build with Gradle, and (for two of them) upload artifacts via `actions/upload-artifact`. The upload uses the runtime artifacts API rather than a `GITHUB_TOKEN` scope, so `contents: read` is sufficient for all 5 jobs. Scoped per-job rather than workflow-wide so each job declares its own minimum permissions and a future job added here cannot silently inherit a broader default. --- .github/workflows/integration-test.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index ce2291a73..d97b3549d 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -10,6 +10,8 @@ on: jobs: check-rest-httpurlconnection: runs-on: ubuntu-latest + permissions: + contents: read steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: @@ -34,6 +36,8 @@ jobs: check-realtime-httpurlconnection: runs-on: ubuntu-latest + permissions: + contents: read steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: @@ -57,6 +61,8 @@ jobs: path: java/build/reports/ check-rest-okhttp: runs-on: ubuntu-latest + permissions: + contents: read steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: @@ -75,6 +81,8 @@ jobs: check-realtime-okhttp: runs-on: ubuntu-latest + permissions: + contents: read steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: @@ -93,6 +101,8 @@ jobs: check-liveobjects: runs-on: ubuntu-latest + permissions: + contents: read steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: From 1c663d597e5b4daff6f12324185b5306e470d198 Mon Sep 17 00:00:00 2001 From: Matt Hammond Date: Fri, 22 May 2026 16:47:01 +0100 Subject: [PATCH 3/7] ci(integration-test): disable credential persistence on checkout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add `persist-credentials: false` to each of the 5 `actions/checkout` steps in the Integration Test workflow. By default `actions/checkout` writes a short-lived `GITHUB_TOKEN`-derived credential into the local `.git/config` for the duration of the job. That credential can then leak into uploaded artifacts, into subprocesses that read the git config, or into remote-tracking operations subsequent steps perform. None of the integration test jobs push, tag, or otherwise need write access to the repository over git — they only need a working tree to build and test against — so the persisted credential is pure attack surface. --- .github/workflows/integration-test.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index d97b3549d..1c59f771a 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -16,6 +16,7 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: submodules: 'recursive' + persist-credentials: false - name: Set up the JDK uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4 @@ -42,6 +43,7 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: submodules: 'recursive' + persist-credentials: false - name: Set up the JDK uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4 @@ -67,6 +69,7 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: submodules: 'recursive' + persist-credentials: false - name: Set up the JDK uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4 @@ -87,6 +90,7 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: submodules: 'recursive' + persist-credentials: false - name: Set up the JDK uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4 @@ -107,6 +111,7 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: submodules: 'recursive' + persist-credentials: false - name: Set up the JDK uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4 From b649607f618d1dc5d40e2626d19d5550e6376e89 Mon Sep 17 00:00:00 2001 From: Matt Hammond Date: Fri, 22 May 2026 16:47:42 +0100 Subject: [PATCH 4/7] ci(release): scope publish job permissions to contents:read Add an explicit `permissions: contents: read` block to the `run-on-release` job in the Maven Central publish workflow. This is the sole automated production path that publishes ably-java artifacts to Sonatype / Maven Central, so it warrants the strictest permissions footprint we can give it. Authentication to Maven Central is entirely via repository secrets passed as Gradle environment variables (`SONATYPE_USERNAME`, `SONATYPE_PASSWORD`) plus the in-memory GPG signing key (`SIGNING_IN_MEMORY_KEY`, `SIGNING_KEY_ID`, `SIGNING_PASSWORD`). None of those depend on `GITHUB_TOKEN` scopes. The job performs no git push, no tag creation, no release publishing, and no other API call against the GitHub side, so `contents: read` covers everything the job actually does. --- .github/workflows/release.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 7aa1bf678..859d62354 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -7,6 +7,8 @@ jobs: run-on-release: runs-on: ubuntu-latest if: github.repository == 'ably/ably-java' + permissions: + contents: read steps: - name: Checkout code uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 From d33179f220cdaaf6408c18f1609778af69e787fa Mon Sep 17 00:00:00 2001 From: Matt Hammond Date: Fri, 22 May 2026 16:48:30 +0100 Subject: [PATCH 5/7] ci(features): pass only the secrets the called workflow actually needs Replace `secrets: inherit` with an explicit `secrets:` map that forwards only `ABLY_AWS_ACCOUNT_ID_SDK` to the called reusable workflow. With `secrets: inherit` every secret available to this repository is implicitly handed to `ably/features/.github/workflows/sdk-features.yml` on each invocation, including secrets that workflow does not need (Sonatype publishing credentials, GPG signing keys, etc.). The called workflow declares only one required secret on its `workflow_call` trigger and otherwise relies on `GITHUB_TOKEN`, which reusable workflows receive automatically from the caller and so does not need to be passed via `secrets:`. --- .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 2f2d3bc75..72a43f49d 100644 --- a/.github/workflows/features.yml +++ b/.github/workflows/features.yml @@ -11,4 +11,5 @@ jobs: uses: ably/features/.github/workflows/sdk-features.yml@6b3fc7a8ede2ebdd7a6325314f3a96c6466f1453 # main with: repository-name: ably-java - secrets: inherit + secrets: + ABLY_AWS_ACCOUNT_ID_SDK: ${{ secrets.ABLY_AWS_ACCOUNT_ID_SDK }} From 2f703763f19b5f8a73863117c13d4cf875d51a5f Mon Sep 17 00:00:00 2001 From: Matt Hammond Date: Fri, 22 May 2026 17:16:57 +0100 Subject: [PATCH 6/7] ci: disable credential persistence on the remaining checkouts Add `persist-credentials: false` to the `actions/checkout` steps in the 5 workflows that were not covered by the earlier integration-test change: `check.yml`, `emulate.yml`, `example-app.yml`, `javadoc.yml`, and `release.yaml`. By default `actions/checkout` writes a short-lived `GITHUB_TOKEN`-derived credential into the local `.git/config` for the duration of the job. None of these jobs perform a `git push`, create tags, open PRs, or otherwise require write access to the repository over git: - `check.yml` runs Gradle linters and unit tests - `emulate.yml` runs Android emulator tests and uploads a reports artifact via `actions/upload-artifact` (which uses the runtime artifacts API, not git) - `example-app.yml` runs the example-app connectedAndroidTest - `javadoc.yml` builds Javadoc and uploads it to S3 via `ably/sdk-upload-action`; `githubToken` is passed to that action as an explicit input parameter, not via the checkout-persisted credential, so disabling persistence does not affect the upload - `release.yaml` publishes to Maven Central using Sonatype + GPG credentials from repository secrets and performs no git write `features.yml` only invokes a reusable workflow and has no checkout step of its own, so it requires no change here. --- .github/workflows/check.yml | 2 ++ .github/workflows/emulate.yml | 2 ++ .github/workflows/example-app.yml | 2 ++ .github/workflows/javadoc.yml | 2 ++ .github/workflows/release.yaml | 2 ++ 5 files changed, 10 insertions(+) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 62330995d..fe67f8932 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -12,6 +12,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3 + with: + persist-credentials: false - name: Set up the JDK uses: actions/setup-java@17f84c3641ba7b8f6deff6309fc4c864478f5d62 # v3 with: diff --git a/.github/workflows/emulate.yml b/.github/workflows/emulate.yml index 910ed0cd8..fc248f282 100644 --- a/.github/workflows/emulate.yml +++ b/.github/workflows/emulate.yml @@ -17,6 +17,8 @@ jobs: steps: - name: checkout uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false - name: Set up the JDK uses: actions/setup-java@17f84c3641ba7b8f6deff6309fc4c864478f5d62 # v3 diff --git a/.github/workflows/example-app.yml b/.github/workflows/example-app.yml index 10a7d1187..0539b74a2 100644 --- a/.github/workflows/example-app.yml +++ b/.github/workflows/example-app.yml @@ -17,6 +17,8 @@ jobs: steps: - name: checkout uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false - name: Set up the JDK uses: actions/setup-java@17f84c3641ba7b8f6deff6309fc4c864478f5d62 # v3 diff --git a/.github/workflows/javadoc.yml b/.github/workflows/javadoc.yml index b3dc35d17..8876dbb11 100644 --- a/.github/workflows/javadoc.yml +++ b/.github/workflows/javadoc.yml @@ -14,6 +14,8 @@ jobs: deployments: write steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@67fbcbb121271f7775d2e7715933280b06314838 # v1 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 859d62354..c55cc27a9 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -12,6 +12,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false - name: Extract tag id: tag From 194a4b5ca8b3baec192432ac279c800bd7802c06 Mon Sep 17 00:00:00 2001 From: Matt Hammond Date: Fri, 22 May 2026 17:39:18 +0100 Subject: [PATCH 7/7] ci: scope per-job permissions on the remaining workflows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add explicit per-job `permissions:` blocks to the 4 workflows that were still relying on the repository default token permissions: `check.yml`, `emulate.yml`, `example-app.yml`, `features.yml`. - `check.yml`, `emulate.yml`, `example-app.yml` each have a single job that only needs to read source and run Gradle. They get `permissions: contents: read`. - `features.yml` invokes a reusable workflow at `ably/features/.github/workflows/sdk-features.yml`. Permissions for a reusable workflow are inherited from the calling job — the called workflow's own `permissions:` block cannot upgrade scopes the caller has not granted. The called workflow at the pinned SHA runs `actions/checkout`, then `aws-actions/configure-aws-credentials` (AWS OIDC), then `ably/sdk-upload-action` (creates a GitHub deployment). It therefore needs: permissions: contents: read id-token: write deployments: write These match the inline equivalent in `javadoc.yml`, which does the same upload work directly; `contents: read` is added here as an explicit tightening rather than relying on the public-repo default. --- .github/workflows/check.yml | 2 ++ .github/workflows/emulate.yml | 2 ++ .github/workflows/example-app.yml | 2 ++ .github/workflows/features.yml | 4 ++++ 4 files changed, 10 insertions(+) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index fe67f8932..054a81eb0 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -10,6 +10,8 @@ on: jobs: check: runs-on: ubuntu-latest + permissions: + contents: read steps: - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3 with: diff --git a/.github/workflows/emulate.yml b/.github/workflows/emulate.yml index fc248f282..a95d1386c 100644 --- a/.github/workflows/emulate.yml +++ b/.github/workflows/emulate.yml @@ -9,6 +9,8 @@ on: jobs: check: runs-on: ubuntu-latest + permissions: + contents: read strategy: fail-fast: false matrix: diff --git a/.github/workflows/example-app.yml b/.github/workflows/example-app.yml index 0539b74a2..414ebe05d 100644 --- a/.github/workflows/example-app.yml +++ b/.github/workflows/example-app.yml @@ -9,6 +9,8 @@ on: jobs: check: runs-on: ubuntu-latest + permissions: + contents: read strategy: fail-fast: false matrix: diff --git a/.github/workflows/features.yml b/.github/workflows/features.yml index 72a43f49d..804458d17 100644 --- a/.github/workflows/features.yml +++ b/.github/workflows/features.yml @@ -8,6 +8,10 @@ on: jobs: build: + permissions: + contents: read + id-token: write + deployments: write uses: ably/features/.github/workflows/sdk-features.yml@6b3fc7a8ede2ebdd7a6325314f3a96c6466f1453 # main with: repository-name: ably-java