Skip to content

ci: GHA workflow security cleanup#2208

Open
emptyhammond wants to merge 4 commits into
mainfrom
worktree-fixup-workflows
Open

ci: GHA workflow security cleanup#2208
emptyhammond wants to merge 4 commits into
mainfrom
worktree-fixup-workflows

Conversation

@emptyhammond
Copy link
Copy Markdown

@emptyhammond emptyhammond commented May 26, 2026

Routine hygiene pass over the seven GitHub Actions workflows in this repo, prompted by a workflow security audit. No behavioural changes are intended.

The changes are split into four commits, one per finding type:

  1. Declare minimal permissions on workflows — every workflow now sets an explicit permissions: block (most are contents: read). Without one, the job's GITHUB_TOKEN falls back
    to the repository-default scope, which is broader than these workflows need.

  2. Disable credential persistence on checkout stepsactions/checkout writes a token to .git/config and leaves it there for the rest of the job by default. Setting
    persist-credentials: false means the token is only used to fetch and is then removed.

  3. Pass only the required secret to the features workflowfeatures.yml previously used secrets: inherit, forwarding every secret to the reusable workflow. It now passes only
    ABLY_AWS_ACCOUNT_ID_SDK, which is the single named secret the called workflow declares.

  4. Pin third-party actions to commit SHAs — tag references like @v4 are mutable; pinning to a full commit SHA freezes the exact code that runs in CI. The tagged release is
    recorded in a trailing comment so updates are still easy to review. ably/features and editorconfig-checker/action-editorconfig-checker were previously tracking @main and are now
    pinned to a specific commit.

Summary by CodeRabbit

  • Chores
    • Enhanced GitHub Actions workflow security by pinning action versions to specific commit SHAs instead of floating version tags.
    • Added explicit job-level permissions blocks across all workflows, restricting access to minimal required scopes.
    • Configured checkout steps to disable credential persistence for improved security posture.

Review Change Stack

Without an explicit permissions block, jobs fall back to the
repository-default GITHUB_TOKEN scope, which is broader than any of
these workflows need. Set contents: read at the workflow level (with
the additional deployments/id-token write scopes the features.yml
reusable workflow requires on its job).
actions/checkout writes a token to .git/config and leaves it there for
the rest of the job by default. With persist-credentials: false the
token is only used to fetch and is then removed, so later steps in the
same job cannot reuse it.
The reusable workflow ably/features/.github/workflows/sdk-features.yml
declares one named secret (ABLY_AWS_ACCOUNT_ID_SDK). Passing it
explicitly instead of using secrets: inherit means new repository or
organisation secrets are not silently forwarded to the called workflow.
GitHub tag references like @v4 are mutable - the maintainer (or anyone
who compromises their account) can move the tag to a different commit.
Pinning to a full commit SHA freezes the exact code that runs in CI;
the trailing comment records which tagged release each SHA corresponds
to so updates are still easy to review.

ably/features and editorconfig-checker were previously tracking @main
and are now pinned to a specific commit.
@emptyhammond emptyhammond requested a review from ttypic May 26, 2026 11:07
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 26, 2026

Walkthrough

Six GitHub Actions workflows are updated to improve supply-chain security by adding explicit read-only permissions, pinning all external actions and reusable workflows to specific commit SHAs instead of version tags, disabling credential persistence in checkout steps, and tightening secret handling in the features workflow.

Changes

GitHub Actions Supply-Chain Security Hardening

Layer / File(s) Summary
Core workflow permissions and checkout hardening
.github/workflows/check-pod.yaml, .github/workflows/check-spm.yaml, .github/workflows/docs.yml, .github/workflows/examples.yaml, .github/workflows/integration-test.yaml, .github/workflows/lint.yml
Permissions blocks granting read-only repository contents access are added to all workflows. Checkout actions are pinned to specific commit SHAs and configured with persist-credentials: false across all six workflows.
Artifact upload and cache action pinning
.github/workflows/check-pod.yaml, .github/workflows/integration-test.yaml
Upload-artifact actions are pinned to specific commit SHAs (v4.6.2 in check-pod and integration-test). Integration-test additionally pins the xcparse cache action to a specific commit SHA.
Documentation publishing and specialized action hardening
.github/workflows/docs.yml, .github/workflows/lint.yml
AWS credential configuration action (v1.7.0 SHA) and SDK upload actions for Jazzy and Markdown API documentation (v1.3.0 and v2.2.0 SHAs respectively) are pinned in docs.yml. Editorconfig-checker action is pinned to v2.2.0 commit in lint.yml instead of the moving main reference.
Reusable workflow security and explicit secret handling
.github/workflows/features.yml
Reusable workflow reference is pinned to a specific commit SHA instead of main, explicit top-level and job-level permissions are added (with contents read, deployments write, and id-token write at job level), and secrets: inherit is replaced with an explicit secrets map containing only ABLY_AWS_ACCOUNT_ID_SDK.

🎯 2 (Simple) | ⏱️ ~12 minutes

A rabbit hops through workflows with care,
Pinning actions with a careful stare,
Permissions read-only, credentials secured tight,
Supply chains hardened from morning to night,
YAML workflows now shining so bright! 🐰✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'ci: GHA workflow security cleanup' accurately summarizes the main change: security hardening of GitHub Actions workflows through permissions, credential handling, secrets management, and action pinning.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch worktree-fixup-workflows

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/docs.yml (1)

15-23: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add contents: read to this job’s permissions.

actions/checkout runs with the job’s GITHUB_TOKEN, and when a job-level permissions block is present, any omitted scopes are set to none, which can block checkout (especially for private repos).

Suggested fix
     permissions:
+      contents: read
       deployments: write
       id-token: write
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/docs.yml around lines 15 - 23, The job-level permissions
block currently lists only deployments and id-token, which causes omitted scopes
like contents to be set to none and can break actions/checkout; update the
permissions block to include contents: read so actions/checkout can access the
repository (i.e., add contents: read alongside deployments: write and id-token:
write in the permissions section referenced around the actions/checkout@...
step).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/integration-test.yaml:
- Around line 65-68: The workflow step get-xcparse-commit-sha currently uses the
deprecated ::set-output command; replace the echo "::set-output name=sha::$(git
rev-parse HEAD)" approach by writing the output key/value into $GITHUB_OUTPUT so
the output remains available as steps.get-xcparse-commit-sha.outputs.sha (i.e.,
append a line of the form sha=<git rev-parse HEAD> to the $GITHUB_OUTPUT file in
that step).

---

Outside diff comments:
In @.github/workflows/docs.yml:
- Around line 15-23: The job-level permissions block currently lists only
deployments and id-token, which causes omitted scopes like contents to be set to
none and can break actions/checkout; update the permissions block to include
contents: read so actions/checkout can access the repository (i.e., add
contents: read alongside deployments: write and id-token: write in the
permissions section referenced around the actions/checkout@... step).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3e6c7a3c-8776-4dad-846a-d7bb925217c1

📥 Commits

Reviewing files that changed from the base of the PR and between 5df40cc and 2ea4120.

📒 Files selected for processing (7)
  • .github/workflows/check-pod.yaml
  • .github/workflows/check-spm.yaml
  • .github/workflows/docs.yml
  • .github/workflows/examples.yaml
  • .github/workflows/features.yml
  • .github/workflows/integration-test.yaml
  • .github/workflows/lint.yml

Comment on lines 65 to 68
run: |
cd xcparse
echo "::set-output name=sha::$(git rev-parse HEAD)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify there are no deprecated set-output commands left in workflows.
rg -n --iglob '*.yml' --iglob '*.yaml' '::set-output\s+name=' .github/workflows

Repository: ably/ably-cocoa

Length of output: 164


🏁 Script executed:

#!/bin/bash
set -euo pipefail
nl -ba .github/workflows/integration-test.yaml | sed -n '55,80p'

Repository: ably/ably-cocoa

Length of output: 102


🏁 Script executed:

#!/bin/bash
set -euo pipefail
awk 'NR>=55 && NR<=80 {printf "%d:%s\n", NR, $0}' .github/workflows/integration-test.yaml

Repository: ably/ably-cocoa

Length of output: 1003


Replace deprecated set-output in workflow

.github/workflows/integration-test.yaml uses the deprecated workflow command on the get-xcparse-commit-sha step; migrate it to write to $GITHUB_OUTPUT (so steps.get-xcparse-commit-sha.outputs.sha keeps working).

Suggested fix
           cd xcparse
-          echo "::set-output name=sha::$(git rev-parse HEAD)"
+          echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
run: |
cd xcparse
echo "::set-output name=sha::$(git rev-parse HEAD)"
run: |
cd xcparse
echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
🧰 Tools
🪛 actionlint (1.7.12)

[error] 65-65: workflow command "set-output" was deprecated. use echo "{name}={value}" >> $GITHUB_OUTPUT instead: https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions

(deprecated-commands)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/integration-test.yaml around lines 65 - 68, The workflow
step get-xcparse-commit-sha currently uses the deprecated ::set-output command;
replace the echo "::set-output name=sha::$(git rev-parse HEAD)" approach by
writing the output key/value into $GITHUB_OUTPUT so the output remains available
as steps.get-xcparse-commit-sha.outputs.sha (i.e., append a line of the form
sha=<git rev-parse HEAD> to the $GITHUB_OUTPUT file in that step).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants