chore: apply least privilege permissions to github actions#40687
chore: apply least privilege permissions to github actions#40687yasnagat wants to merge 4 commits into
Conversation
|
Looks like this PR is not ready to merge, because of the following issues:
Please fix the issues and try again If you have any trouble, please check the PR guidelines |
|
WalkthroughAll GitHub Actions workflows are updated to explicitly define token permissions. Workflow-level ChangesExplicit GitHub Actions Permissions
🎯 2 (Simple) | ⏱️ ~12 minutes Suggested labels
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
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. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #40687 +/- ##
===========================================
+ Coverage 69.64% 69.74% +0.09%
===========================================
Files 3338 3327 -11
Lines 123232 123134 -98
Branches 21989 21963 -26
===========================================
+ Hits 85830 85883 +53
+ Misses 34049 33898 -151
Partials 3353 3353
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
This reverts commit a9f7948.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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/ci.yml:
- Around line 25-26: The workflow default grants repository read to all jobs;
change the workflow-level permissions from "contents: read" to an empty mapping
(permissions: {}) and then add "contents: read" to only the jobs that need it
(e.g., the release-versions job and any jobs that run checkout/git operations).
Update the job definitions (for example, the release-versions job) to include a
job-level permissions block granting contents: read so those jobs retain
required access while other jobs remain least-privilege.
In @.github/workflows/new-release.yml:
- Around line 23-24: The workflow currently passes the PAT to actions/checkout
(via with: token: ${{ secrets.CI_PAT }}) and also sets env: GITHUB_TOKEN at job
level, which persists the PAT for subsequent steps; update the actions/checkout
step(s) that use ${{ secrets.CI_PAT }} to include persist-credentials: false,
remove the workflow/job-level env: GITHUB_TOKEN: ${{ secrets.CI_PAT }}, and
instead pass the PAT only to the specific step(s) that need it (e.g., the
./packages/release-action step) by setting env or with on that step alone so
checkout doesn't leave a PAT-backed credential available to later steps.
🪄 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: 3af1d1cc-4784-4269-a2f3-8dbd7107970d
📒 Files selected for processing (14)
.github/workflows/auto-close-duplicates.yml.github/workflows/ci-code-check.yml.github/workflows/ci-deploy-gh-pages.yml.github/workflows/ci-test-e2e.yml.github/workflows/ci-test-storybook.yml.github/workflows/ci-test-unit.yml.github/workflows/ci.yml.github/workflows/codeql-analysis.yml.github/workflows/dedupe-issues.yml.github/workflows/new-release.yml.github/workflows/pr-update-description.yml.github/workflows/publish-release.yml.github/workflows/release-candidate.yml.github/workflows/update-version-durability.yml
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: cubic · AI code reviewer
- GitHub Check: Hacktron Security Check
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-04-27T18:32:21.871Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 40321
File: .github/workflows/ci.yml:137-145
Timestamp: 2026-04-27T18:32:21.871Z
Learning: In .github/workflows/ci.yml, the `diff` step under `release-versions` intentionally uses a bash `if` with `gh pr diff ... | grep -q ...; then ... fi`. For non-`pull_request` workflow triggers where `GH_PR_NUM` can be empty, the `gh` command may fail, but the surrounding bash `if` is relied on to treat that failure as the condition being false and skip the `then` block, allowing the step/job to exit cleanly. Do not add extra guards for non-PR event types unless this failure/skip behavior is intentionally changed.
Applied to files:
.github/workflows/ci.yml
🔇 Additional comments (10)
.github/workflows/auto-close-duplicates.yml (1)
8-16: LGTM!.github/workflows/ci-code-check.yml (1)
16-22: LGTM!.github/workflows/ci-deploy-gh-pages.yml (1)
11-17: LGTM!.github/workflows/ci-test-e2e.yml (1)
71-77: LGTM!.github/workflows/ci-test-storybook.yml (1)
22-28: LGTM!.github/workflows/ci-test-unit.yml (1)
26-32: LGTM!.github/workflows/ci.yml (1)
32-34: LGTM!.github/workflows/codeql-analysis.yml (1)
15-18: LGTM!.github/workflows/dedupe-issues.yml (1)
13-14: LGTM!Also applies to: 19-21
.github/workflows/update-version-durability.yml (1)
16-17: Permission change is safe for publishing (local action doesn’t rely on checkout’s push remote).
.github/actions/update-version-durability/index.jspublishes via Document360 (D360_TOKEN) and only reads GitHub releases via Octokit using the providedGH_TOKEN; there’s nogit push/remote configuration in the action, socontents: readonGITHUB_TOKENdoesn’t affect the publish path.
| permissions: {} | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Does actions/checkout persist the provided token in local git config by default, and what changes when persist-credentials is set to false?
💡 Result:
Yes, the actions/checkout action persists the provided authentication token (or SSH key) in the local git configuration by default to enable subsequent authenticated git commands during the job [1][2][3]. Regarding how it is persisted, recent versions of the action have improved security by storing these credentials in a separate file located under $RUNNER_TEMP, rather than writing them directly into the.git/config file [1][4][5]. Regardless of the storage location, the action automatically removes these credentials during the post-job cleanup process [1][6][3]. When you set persist-credentials to false, the action will not configure the token or SSH key in the local git configuration [1][3]. This is primarily used as an opt-out mechanism if you do not want the runner to have authenticated git access for subsequent steps or if you prefer to manage credentials manually [1][4].
Citations:
- 1: https://github.com/actions/checkout/?tab=readme-ov-file
- 2: https://github.com/actions/checkout/tree/v6.0.2?tab=readme-ov-file
- 3: https://github.com/actions/checkout/blob/72f2cec99f417b1a1c5e2e88945068983b7965f9/action.yml
- 4: https://github.com/actions/checkout
- 5: https://github.com/actions/checkout/tree/refs/heads/main
- 6: https://github.com/actions/checkout/blob/85e6279cec87321a52edac9c87bce653a07cf6c2/README.md
🏁 Script executed:
#!/bin/bash
set -euo pipefail
files=(
".github/workflows/new-release.yml"
".github/workflows/pr-update-description.yml"
".github/workflows/publish-release.yml"
".github/workflows/release-candidate.yml"
)
for f in "${files[@]}"; do
echo "===== $f ====="
if [[ ! -f "$f" ]]; then
echo "MISSING: $f"
continue
fi
# show permissions block too
rg -n "permissions:" "$f" || true
# show checkout steps and any token usage
rg -n "uses:\s*actions/checkout|with:|persist-credentials|CI_PAT|secrets\.CI_PAT|GITHUB_TOKEN" "$f" -n || true
# print small surrounding context for checkout-related lines
rg -n "uses:\s*actions/checkout" "$f" | while IFS=: read -r ln _; do
start=$((ln-5)); end=$((ln+25))
echo "--- context around checkout at line $ln (show $start-$end) ---"
sed -n "${start},${end}p" "$f" | nl -ba -w2 -s":"
done
doneRepository: RocketChat/Rocket.Chat
Length of output: 495
🏁 Script executed:
#!/bin/bash
set -euo pipefail
files=(
".github/workflows/new-release.yml"
".github/workflows/pr-update-description.yml"
".github/workflows/publish-release.yml"
".github/workflows/release-candidate.yml"
)
print_context () {
local f="$1" line="$2" start="$3" end="$4"
echo "--- context around '$f:$line' (show $start-$end) ---"
# use awk to print line numbers since nl may be unavailable
awk -v s="$start" -v e="$end" 'NR>=s && NR<=e { printf "%4d:%s\n", NR, $0 }' "$f"
}
for f in "${files[@]}"; do
echo
echo "===== $f ====="
if [[ ! -f "$f" ]]; then
echo "MISSING: $f"
continue
fi
echo "-- permissions blocks --"
rg -n "^\\s*permissions:|permissions:" "$f" || true
echo "-- checkout + token usage --"
rg -n "uses:\\s*actions/checkout@|with:|persist-credentials|token:\\s*\\$\\{\\{\\s*secrets\\.CI_PAT\\s*\\}\\}|secrets\\.CI_PAT|GITHUB_TOKEN:" "$f" || true
echo "-- persist-credentials setting (if any) --"
rg -n "persist-credentials" "$f" || true
echo "-- checkout steps (with surrounding context) --"
rg -n "uses:\\s*actions/checkout@" "$f" | while IFS=: read -r ln rest; do
start=$((ln-8)); end=$((ln+30))
(( start<1 )) && start=1
print_context "$f" "$ln" "$start" "$end"
done
echo "-- git write-like commands after checkout (best-effort) --"
# crude scan: show lines containing common write actions
rg -n "\\bgit\\b|git (push|tag|commit|fetch|config|remote|checkout)" "$f" || true
doneRepository: RocketChat/Rocket.Chat
Length of output: 6700
Reduce PAT blast radius in checkout across release workflows: these workflows set workflow-level permissions: {} (job contents: read), but still pass with: token: ${{ secrets.CI_PAT }} to actions/checkout (no persist-credentials: false), and later set env: GITHUB_TOKEN: ${{ secrets.CI_PAT }}—so checkout credential persistence leaves a broader PAT-backed git auth available for subsequent steps rather than limiting write access.
- Suggested fix (apply to all four): add
persist-credentials: falseto theactions/checkoutstep that uses${{ secrets.CI_PAT }}, and pass the PAT only to the specific./packages/release-actionstep(s) that require it.- .github/workflows/new-release.yml (~32-36, ~57)
- .github/workflows/pr-update-description.yml (~20-24, ~42)
- .github/workflows/publish-release.yml (~23-26, ~46)
- .github/workflows/release-candidate.yml (~14-19, ~39)
🤖 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/new-release.yml around lines 23 - 24, The workflow
currently passes the PAT to actions/checkout (via with: token: ${{
secrets.CI_PAT }}) and also sets env: GITHUB_TOKEN at job level, which persists
the PAT for subsequent steps; update the actions/checkout step(s) that use ${{
secrets.CI_PAT }} to include persist-credentials: false, remove the
workflow/job-level env: GITHUB_TOKEN: ${{ secrets.CI_PAT }}, and instead pass
the PAT only to the specific step(s) that need it (e.g., the
./packages/release-action step) by setting env or with on that step alone so
checkout doesn't leave a PAT-backed credential available to later steps.
There was a problem hiding this comment.
2 issues found across 14 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".github/workflows/ci-test-e2e.yml">
<violation number="1" location=".github/workflows/ci-test-e2e.yml:77">
P2: Grant `actions: read` to this job. The telemetry step needs it even with `comment_on_pr: false`, so the perf path can fail after the workflow token is locked down.</violation>
</file>
<file name=".github/workflows/ci.yml">
<violation number="1" location=".github/workflows/ci.yml:26">
P2: This workflow uses `permissions: contents: read` at the workflow level, but all other workflows in this PR correctly use `permissions: {}`. Workflow-level permissions apply as a default to any job that doesn't declare its own `permissions` block, so this grants `contents: read` to jobs that may not need GitHub API access. For consistency with the least-privilege approach, change this to `permissions: {}` and ensure each job that needs `contents: read` declares it explicitly (as `release-versions` already does).</violation>
</file>
Tip: cubic used a learning from your PR history. Let your coding agent read cubic learnings directly with the cubic MCP.
Re-trigger cubic
| test: | ||
| runs-on: ubuntu-24.04 | ||
| permissions: | ||
| contents: read |
There was a problem hiding this comment.
P2: Grant actions: read to this job. The telemetry step needs it even with comment_on_pr: false, so the perf path can fail after the workflow token is locked down.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/ci-test-e2e.yml, line 77:
<comment>Grant `actions: read` to this job. The telemetry step needs it even with `comment_on_pr: false`, so the perf path can fail after the workflow token is locked down.</comment>
<file context>
@@ -68,9 +68,13 @@ env:
test:
runs-on: ubuntu-24.04
+ permissions:
+ contents: read
env:
</file context>
| contents: read | |
| actions: read | |
| contents: read |
| TOOL_NODE_FLAGS: ${{ vars.TOOL_NODE_FLAGS }} | ||
|
|
||
| permissions: | ||
| contents: read |
There was a problem hiding this comment.
P2: This workflow uses permissions: contents: read at the workflow level, but all other workflows in this PR correctly use permissions: {}. Workflow-level permissions apply as a default to any job that doesn't declare its own permissions block, so this grants contents: read to jobs that may not need GitHub API access. For consistency with the least-privilege approach, change this to permissions: {} and ensure each job that needs contents: read declares it explicitly (as release-versions already does).
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/ci.yml, line 26:
<comment>This workflow uses `permissions: contents: read` at the workflow level, but all other workflows in this PR correctly use `permissions: {}`. Workflow-level permissions apply as a default to any job that doesn't declare its own `permissions` block, so this grants `contents: read` to jobs that may not need GitHub API access. For consistency with the least-privilege approach, change this to `permissions: {}` and ensure each job that needs `contents: read` declares it explicitly (as `release-versions` already does).</comment>
<file context>
@@ -22,10 +22,16 @@ concurrency:
TOOL_NODE_FLAGS: ${{ vars.TOOL_NODE_FLAGS }}
+permissions:
+ contents: read
+
jobs:
</file context>
Proposed changes (including videos or screenshots)
This PR applies the principle of least privilege to
GITHUB_TOKENpermissions across all GitHub Actions workflows by settingpermissions: {}globally and explicitly re-granting only the minimum permissions required per job, as part of a supply chain security hardening effort.Workflows relied on GitHub’s default token scopes, which may grant more access than most jobs actually need. Scoping permissions at the job level reduces the attack surface in the event that a GitHub Action, third-party dependency, or CI component is compromised, helping mitigate the impact of potential supply chain attacks and limiting unnecessary repository access.
This change only affects the permissions granted to the workflow
GITHUB_TOKEN. Operations authenticated using explicitly configured Personal Access Tokens (PATs) continue to have the scopes assigned to those tokens and are not affected by workflowpermissionssettings.Issue(s)
SB-975
Steps to test or reproduce
Further comments
Summary by CodeRabbit