ci: harden workflow token permissions and pin actions by SHA#2849
Conversation
|
Note Gemini is unable to generate a summary for this pull request due to the file types involved not being currently supported. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (13)
🚧 Files skipped from review as they are similar to previous changes (5)
📝 WalkthroughWalkthroughThis PR standardizes GitHub Actions security across workflows by defaulting workflow permissions to ChangesGitHub Actions Security Hardening
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
.github/workflows/pull-requests.yaml (1)
128-133: 💤 Low valueConsider adding
persist-credentials: falseas a follow-up hardening measure.Zizmor flags that
actions/checkoutpersists credentials by default, which could leak tokens if subsequent steps upload the.gitdirectory to artifacts. This is a defense-in-depth measure that complements the permissions work in this PR. Since it's out of the PR's stated scope (permissions and pinning only), this can be tracked separately.🛡️ Optional hardening for credential persistence
- name: Checkout code if: contains(github.event.pull_request.labels.*.name, 'release') uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 fetch-tags: true + persist-credentials: false🤖 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/pull-requests.yaml around lines 128 - 133, The checkout step named "Checkout code" currently uses actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 and should explicitly disable credential persistence to avoid leaking tokens; update the step (the "Checkout code" step that calls actions/checkout) to include persist-credentials: false in its with: block so credentials are not left in the checked-out repository.Source: Linters/SAST tools
.github/workflows/tags.yaml (1)
307-336: 💤 Low valueConsider disabling default caching in
actions/setup-nodeto mitigate cache-poisoning risk.Zizmor flags that
actions/setup-nodeenables caching by default, which can be exploited in cache-poisoning attacks on shared runners. Since this workflow runs on self-hosted runners and the cache is only used for the short-lived Copilot CLI installation, the risk is low. However, explicitly disabling caching would satisfy the OpenSSF Scorecard check and eliminate the warning.🛡️ Optional fix to disable default caching
- name: Setup Node.js if: steps.check_changelog.outputs.exists == 'false' uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 22 + cache: ''🤖 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/tags.yaml around lines 307 - 336, The actions/setup-node step named "Setup Node.js" currently uses actions/setup-node without explicitly disabling its built-in caching; add a explicit with entry to turn off caching (e.g., add a with: cache: 'false' under the actions/setup-node usage) so the step does not enable dependency/tool caching and avoids cache-poisoning warnings from Scorecard.Source: Linters/SAST tools
🤖 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/auto-release.yaml:
- Around line 29-33: The GitHub App token is being minted with
actions/create-github-app-token (uses: actions/create-github-app-token@...) and
owner: cozystack but no repository restriction, so add the repositories input
and set it to the current repo (use the github.repository expression) to scope
the installation token to this repository only; update the action invocation
that includes app-id and private-key to also include repositories: ${{
github.repository }}.
In @.github/workflows/labels.yaml:
- Line 83: The checkout step in the sync job is missing
persist-credentials:false which risks leaking write-scoped GitHub token; update
the actions/checkout step (the one using
actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5) in the sync job to
include persist-credentials: false so the write-scoped credentials are not
persisted to the checked-out repository workspace.
---
Nitpick comments:
In @.github/workflows/pull-requests.yaml:
- Around line 128-133: The checkout step named "Checkout code" currently uses
actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 and should explicitly
disable credential persistence to avoid leaking tokens; update the step (the
"Checkout code" step that calls actions/checkout) to include
persist-credentials: false in its with: block so credentials are not left in the
checked-out repository.
In @.github/workflows/tags.yaml:
- Around line 307-336: The actions/setup-node step named "Setup Node.js"
currently uses actions/setup-node without explicitly disabling its built-in
caching; add a explicit with entry to turn off caching (e.g., add a with: cache:
'false' under the actions/setup-node usage) so the step does not enable
dependency/tool caching and avoids cache-poisoning warnings from Scorecard.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: b77f9431-4e71-4759-834d-fbf7a29b4216
📒 Files selected for processing (13)
.github/workflows/auto-release.yaml.github/workflows/backport.yaml.github/workflows/codegen-drift.yml.github/workflows/labels.yaml.github/workflows/pr-labeler.yaml.github/workflows/pr-size.yaml.github/workflows/pre-commit.yml.github/workflows/pull-requests-release.yaml.github/workflows/pull-requests.yaml.github/workflows/retest.yaml.github/workflows/stale.yaml.github/workflows/tags.yaml.github/workflows/update-releasenotes.yaml
| uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1 | ||
| with: | ||
| app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} | ||
| private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} | ||
| owner: cozystack |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate and print the relevant workflow section with line numbers
ls -la .github/workflows/auto-release.yaml
sed -n '1,120p' .github/workflows/auto-release.yaml | nl -baRepository: cozystack/cozystack
Length of output: 209
🌐 Web query:
actions/create-github-app-token repositories input scope behavior
💡 Result:
If you’re using the actions/create-github-app-token GitHub Action, the token’s repository access (“scope”) depends on whether you set the owner and repositories inputs: 1) Neither owner nor repositories set - The token is scoped to only the current repository. [1] 2) owner set, repositories empty - The token is scoped to all repositories in the provided owner’s GitHub App installation. [1] 3) owner not set, repositories set - The token is scoped to the specified repositories under the current repository owner. [1] 4) owner set, repositories set - The token is scoped to the specified repositories under the provided owner. [1] Additionally: - The repositories input accepts a comma-separated or newline-separated list of repository names. [1][2] - The token inherits all permissions granted to the GitHub App installation (you can still reduce permissions via the action’s permission-* inputs, but by default it mirrors the installation’s permissions). [2] - Under the hood, it creates a GitHub App installation access token via the POST /app/installations/{installation_id}/access_tokens endpoint; the REST API documentation notes you can specify individual repositories with repositories/repository_ids, and if you don’t specify repositories, the installation access token has access to all repositories the installation was granted. [3] Sources: [1][2][3]
Citations:
- 1: https://github.com/actions/create-github-app-token?tab=readme-ov-file
- 2: https://github.com/actions/create-github-app-token/blob/34c66235f6ccc38eb01b7aed860890bdf40db33c/README.md
- 3: https://docs.github.com/en/enterprise-server@3.9/apps/creating-github-apps/authenticating-with-a-github-app/generating-an-installation-access-token-for-a-github-app
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '1,120p' .github/workflows/auto-release.yaml | cat -nRepository: cozystack/cozystack
Length of output: 6248
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '1,120p' .github/workflows/auto-release.yaml | cat -nRepository: cozystack/cozystack
Length of output: 6248
🌐 Web query:
actions/create-github-app-token input repositories format github.event.repository.name
💡 Result:
The repositories input for the actions/create-github-app-token action accepts a list of repository names provided as a comma-separated or newline-separated string [1][2]. Regarding the format and use of github.event.repository.name (or similar expressions like github.repository): 1. Format Options: You can provide repository names as bare names (e.g., repo1) or as full owner/repository names (e.g., owner/repo1) [3][1]. 2. Owner Consistency: If you use the full owner/repository format, the owner portion must match the owner input (if provided) or the current repository owner (if the owner input is unset) [1][2]. 3. Using github.repository: It is valid to include the current repository using the context variable ${{ github.repository }} within your list [1][2]. The action is designed to normalize these inputs by parsing them and stripping the owner portion where necessary for token scoping, while still validating that the owner matches the expected target [3]. Example usage with a newline-separated list: repositories: | ${{ github.repository }} another-repo The action automatically handles trimming and parsing the entries, making it robust for both comma-separated and multi-line YAML formats [4].
Citations:
- 1: https://github.com/actions/create-github-app-token
- 2: https://p.rst.im/q/GitHub.Com/actions/create-github-app-token
- 3: feat: support full repository names in
repositoriesinput actions/create-github-app-token#372 - 4: https://deepwiki.com/actions/create-github-app-token/5.2-cross-repository-operations
Scope the GitHub App token to the current repository
With owner: cozystack but no repositories input, actions/create-github-app-token can mint an installation token covering all repositories granted to the GitHub App installation under that owner. Constrain it to the current repo.
Suggested patch
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1
with:
app-id: ${{ secrets.COZYSTACK_CI_APP_ID }}
private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }}
owner: cozystack
+ repositories: ${{ github.event.repository.name }}📝 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.
| uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1 | |
| with: | |
| app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} | |
| private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} | |
| owner: cozystack | |
| uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1 | |
| with: | |
| app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} | |
| private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} | |
| owner: cozystack | |
| repositories: ${{ github.event.repository.name }} |
🧰 Tools
🪛 zizmor (1.25.2)
[error] 33-33: dangerous use of GitHub App tokens (github-app): token granted access to all repositories for this owner's app installation
(github-app)
[error] 29-29: dangerous use of GitHub App tokens (github-app): app token inherits blanket installation permissions
(github-app)
🤖 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/auto-release.yaml around lines 29 - 33, The GitHub App
token is being minted with actions/create-github-app-token (uses:
actions/create-github-app-token@...) and owner: cozystack but no repository
restriction, so add the repositories input and set it to the current repo (use
the github.repository expression) to scope the installation token to this
repository only; update the action invocation that includes app-id and
private-key to also include repositories: ${{ github.repository }}.
Source: Linters/SAST tools
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - uses: EndBug/label-sync@v2 | ||
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE=".github/workflows/labels.yaml"
echo "== File = $FILE =="
ls -la "$FILE" || true
echo
echo "== Lines around 70-95 =="
nl -ba "$FILE" | sed -n '70,100p'
echo
echo "== Find all checkout steps in this workflow =="
rg -n "uses:\s*actions/checkout@" "$FILE" || true
echo
echo "== Show surrounding block for each checkout step =="
rg -n "uses:\s*actions/checkout@" "$FILE" | cut -d: -f1 | while read -r ln; do
start=$((ln-8))
end=$((ln+12))
echo
echo "--- checkout context at line $ln ($start-$end) ---"
nl -ba "$FILE" | sed -n "${start},${end}p"
done
echo
echo "== Check sync job permissions and checkout persist-credentials settings =="
python3 - <<'PY'
import re, pathlib
p = pathlib.Path(".github/workflows/labels.yaml")
txt = p.read_text()
# Very lightweight parse: find "sync:" job block region by indentation
lines = txt.splitlines()
# locate "sync:" line
for i,l in enumerate(lines, start=1):
if re.match(r'^\s*sync:\s*$', l):
start=i
# block ends when indentation <= that of 'sync:' (2 spaces typically for jobs: children)
indent=len(l)-len(l.lstrip(' '))
j=i
while j < len(lines):
nl=len(lines[j])-len(lines[j].lstrip(' '))
if nl<=indent and re.match(r'^\s*\w', lines[j]) and not re.match(r'^\s*sync:\s*$', lines[j]):
break
j+=1
block="\n".join(lines[start-1:j])
print("== sync job block (approx lines %d-%d) =="%(start,j))
print(block)
break
else:
print("sync job not found by exact 'sync:' match")
PYRepository: cozystack/cozystack
Length of output: 273
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE=".github/workflows/labels.yaml"
python3 - <<'PY'
import pathlib, re
p = pathlib.Path(".github/workflows/labels.yaml")
lines = p.read_text().splitlines()
def show(start, end):
for i in range(start, min(end, len(lines)) + 1):
print(f"{i:>4}: {lines[i-1]}")
print("== Lines 75-90 ==")
show(75, 90)
print("\n== All checkout steps ==");
pat = re.compile(r"^\s*-\s*uses:\s*actions/checkout@([0-9a-fA-F]{40})")
checkout_lines = [i for i,l in enumerate(lines, start=1) if pat.search(l)]
print("checkout line numbers:", checkout_lines)
for ln in checkout_lines:
start = max(ln-8, 1)
end = min(ln+12, len(lines))
print(f"\n--- checkout context at line {ln} (SHA={pat.search(lines[ln-1]).group(1)}) ---")
show(start, end)
print("\n== Attempt to extract `sync` job block & its permissions/checkout config ==");
# Simple indentation-based extraction:
sync_start = None
for i,l in enumerate(lines, start=1):
if re.match(r"^\s*sync:\s*$", l):
sync_start = i
sync_indent = len(l) - len(l.lstrip(' '))
break
if sync_start is None:
print("No `sync:` job found.")
raise SystemExit(0)
# Find end of block: first line with indentation <= sync_indent and starting a new top-level key
j = sync_start
while j <= len(lines):
l = lines[j-1]
indent = len(l) - len(l.lstrip(' '))
if j > sync_start and indent <= sync_indent and re.match(r"^\s*\w", l):
break
j += 1
block = lines[sync_start-1:j-1]
print(f"sync job approx lines {sync_start}-{j-1}")
# Extract permissions section lines within sync block
perm_block = []
in_perm = False
perm_indent = None
for idx, l in enumerate(block, start=sync_start):
if re.match(r"^\s*permissions:\s*$", l):
in_perm = True
perm_indent = len(l) - len(l.lstrip(' '))
perm_block.append((idx, l))
continue
if in_perm:
indent = len(l) - len(l.lstrip(' '))
if indent <= perm_indent and re.match(r"^\s*\w", l):
in_perm = False
continue
perm_block.append((idx,l))
if perm_block:
print("\n-- sync permissions block --")
for idx,l in perm_block:
print(f"{idx:>4}: {l}")
else:
print("\nNo `sync` permissions block found.")
# Find checkout inside sync block
sync_checkout = []
for idx in range(sync_start, j):
l = lines[idx-1]
if re.search(r"uses:\s*actions/checkout@", l):
sync_checkout.append(idx)
print("\ncheckout steps inside sync job (line numbers):", sync_checkout)
for ln in sync_checkout:
start=max(ln-6,1); end=min(ln+14,len(lines))
print(f"\n--- sync checkout context at line {ln} ---")
show(start,end)
# Check persist-credentials anywhere near checkout lines
for ln in sync_checkout:
window = lines[max(ln-2,1)-1:min(ln+8,len(lines))]
txt = "\n".join(window)
if "persist-credentials:" in txt:
print(f"persist-credentials present near line {ln}")
# show exact line(s)
for k in range(max(ln-2,1), min(ln+8,len(lines))+1):
if "persist-credentials" in lines[k-1]:
print(f" {k:>4}: {lines[k-1]}")
else:
print(f"persist-credentials NOT present near line {ln}")
PYRepository: cozystack/cozystack
Length of output: 2793
Disable credential persistence in the write-scoped sync job actions/checkout.
In .github/workflows/labels.yaml, the sync job grants issues: write and pull-requests: write but the actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 step at line 83 does not set persist-credentials: false.
Suggested patch
- - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+ with:
+ persist-credentials: false📝 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.
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| with: | |
| persist-credentials: false |
🧰 Tools
🪛 zizmor (1.25.2)
[warning] 83-83: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
🤖 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/labels.yaml at line 83, The checkout step in the sync job
is missing persist-credentials:false which risks leaking write-scoped GitHub
token; update the actions/checkout step (the one using
actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5) in the sync job to
include persist-credentials: false so the write-scoped credentials are not
persisted to the checked-out repository workspace.
Source: Linters/SAST tools
Aleksei Sviridkin (lexfrei)
left a comment
There was a problem hiding this comment.
LGTM — adds explicit minimal permissions: blocks and SHA-pins every action across the workflows, which is exactly what the targeted Scorecard Token-Permissions and Pinned-Dependencies checks score; no job graph or step logic changes.
Business context: raise the OpenSSF Scorecard Token-Permissions and Pinned-Dependencies checks (both 0/10) toward the ≥7.5 target by scoping GITHUB_TOKEN and pinning actions by commit SHA.
Verified: a top-level permissions: contents: read is added with per-job write scopes retained where needed (e.g. the labels.yaml sync job keeps issues: write + pull-requests: write), and actions are pinned to full commit SHAs with version comments. PR-triggered workflows stay green, so the tightened scopes do not break them; the release/tag/backport workflows only run on their own events, so it is worth confirming those once on the next release.
Non-blocking follow-ups
auto-release.yamlmints a GitHub App token withowner: cozystackand norepositories:input (pre-existing, not introduced here), so the token is scoped to every repository in the org installation rather than just this one. Constraining it withrepositories: ${{ github.event.repository.name }}would close the over-scope while this file is already being hardened.- No changed workflow sets
persist-credentials: falseonactions/checkout, including the write-scopedsyncjob (issues/pull-requests: write); that leaves the token in.git/configfor later steps, which is the Dangerous-Workflow surface. It is orthogonal to the two checks this PR targets, but adding it would complete the hardening.
eac7973 to
4feac5b
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.github/workflows/pull-requests-release.yaml (1)
30-36:⚠️ Potential issue | 🟠 Major | ⚡ Quick winScope the GitHub App token to the current repository.
The
finalizejob mints a GitHub App token withowner: cozystackbut norepositoriesinput. Addrepositories: ${{ github.event.repository.name }}to restrict the token to this repository only.Suggested patch
- name: Generate GitHub App token id: app-token uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1 with: app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} owner: cozystack + repositories: ${{ github.event.repository.name }}🤖 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/pull-requests-release.yaml around lines 30 - 36, The GitHub App token step (id: app-token) currently mints a token with owner: cozystack but no repository scope; update the step that uses actions/create-github-app-token (the app-token step in the finalize job) to include a repositories input set to ${{ github.event.repository.name }} so the generated token is limited to the current repository only.Source: Linters/SAST tools
🧹 Nitpick comments (2)
.github/workflows/tags.yaml (2)
336-338: 💤 Low valueOptional: Disable implicit caching on setup-node if strict security posture is desired.
Static analysis flags that
actions/setup-nodeenables caching by default when a lockfile is present, which could theoretically be exploited in cache poisoning scenarios. Given this runs on self-hosted runners and the job hascontinue-on-error: true, the practical risk is low.To explicitly disable caching if desired:
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 22 cache: ''🤖 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/tags.yaml around lines 336 - 338, The workflow uses actions/setup-node@... with node-version: 22 and currently relies on implicit caching; to disable implicit lockfile-based caching set the cache input to an empty string in the setup invocation (update the uses: actions/setup-node step where node-version: 22 is specified to include cache: ''), which will explicitly turn off setup-node's automatic caching behavior on that job.Source: Linters/SAST tools
34-38: 💤 Low valueInformational: GitHub App token permissions are app-installation scoped.
The static analysis tool flags that app tokens inherit "blanket installation permissions." This is expected behavior—the token's capabilities are bounded by the GitHub App's installation configuration, not this workflow. The workflow correctly demonstrates least-privilege awareness by minting a separate read-only token at line 275 for the AI changelog step where write access isn't needed.
Reducing the app installation's permissions (if broader than necessary) would be a separate infrastructure change outside this PR's scope.
🤖 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/tags.yaml around lines 34 - 38, Add a short inline comment above the actions/create-github-app-token step to state that GitHub App tokens are scoped to the App installation (permissions come from the App installation configuration) and that a separate least-privilege read-only token is minted later for steps that don’t need write access; reference the existing keys (app-id, private-key, owner) so reviewers understand this is intentional and not a workflow misconfiguration.Source: Linters/SAST tools
🤖 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/pre-commit.yml:
- Line 22: Update the actions/checkout pin in the pre-commit workflow so it
matches the repo standard: replace the current uses entry that references
actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 (v3) with the v4 SHA
used elsewhere (34e114876b0b11c390a56381ad16ebd13914f8d5) in the uses:
actions/checkout@... line, or alternatively add a short comment explaining why
this workflow must remain on v3 if you intentionally keep it; ensure the single
uses line is updated consistently.
In @.github/workflows/pull-requests.yaml:
- Around line 189-196: The "Generate GitHub App token" step (id: app-token,
uses: actions/create-github-app-token@...) currently issues a token scoped to
the app installation (all repos); restrict it to the current repo by adding the
repositories input: set repositories: ${{ github.event.repository.name }} under
the step's with: block so the generated token is limited to the current pull
request repository.
- Around line 120-126: The Generate GitHub App token step (id: app-token, uses:
actions/create-github-app-token@...) mints a token for owner: cozystack but
doesn’t restrict repositories; update that step to include the repositories
input and pass the current repo (e.g., repositories: ${{ github.repository }})
so the token is scoped to the current repository only.
---
Outside diff comments:
In @.github/workflows/pull-requests-release.yaml:
- Around line 30-36: The GitHub App token step (id: app-token) currently mints a
token with owner: cozystack but no repository scope; update the step that uses
actions/create-github-app-token (the app-token step in the finalize job) to
include a repositories input set to ${{ github.event.repository.name }} so the
generated token is limited to the current repository only.
---
Nitpick comments:
In @.github/workflows/tags.yaml:
- Around line 336-338: The workflow uses actions/setup-node@... with
node-version: 22 and currently relies on implicit caching; to disable implicit
lockfile-based caching set the cache input to an empty string in the setup
invocation (update the uses: actions/setup-node step where node-version: 22 is
specified to include cache: ''), which will explicitly turn off setup-node's
automatic caching behavior on that job.
- Around line 34-38: Add a short inline comment above the
actions/create-github-app-token step to state that GitHub App tokens are scoped
to the App installation (permissions come from the App installation
configuration) and that a separate least-privilege read-only token is minted
later for steps that don’t need write access; reference the existing keys
(app-id, private-key, owner) so reviewers understand this is intentional and not
a workflow misconfiguration.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 019b05a6-5cb4-4e2f-92d0-2f910bb8864c
📒 Files selected for processing (13)
.github/workflows/auto-release.yaml.github/workflows/backport.yaml.github/workflows/codegen-drift.yml.github/workflows/labels.yaml.github/workflows/pr-labeler.yaml.github/workflows/pr-size.yaml.github/workflows/pre-commit.yml.github/workflows/pull-requests-release.yaml.github/workflows/pull-requests.yaml.github/workflows/retest.yaml.github/workflows/stale.yaml.github/workflows/tags.yaml.github/workflows/update-releasenotes.yaml
🚧 Files skipped from review as they are similar to previous changes (4)
- .github/workflows/update-releasenotes.yaml
- .github/workflows/pr-labeler.yaml
- .github/workflows/stale.yaml
- .github/workflows/backport.yaml
There was a problem hiding this comment.
Caution
Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.github/workflows/pull-requests-release.yaml (1)
30-36:⚠️ Potential issue | 🟠 Major | ⚡ Quick winScope the GitHub App token to the current repository.
The
finalizejob mints a GitHub App token withowner: cozystackbut norepositoriesinput. Addrepositories: ${{ github.event.repository.name }}to restrict the token to this repository only.Suggested patch
- name: Generate GitHub App token id: app-token uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1 with: app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} owner: cozystack + repositories: ${{ github.event.repository.name }}🤖 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/pull-requests-release.yaml around lines 30 - 36, The GitHub App token step (id: app-token) currently mints a token with owner: cozystack but no repository scope; update the step that uses actions/create-github-app-token (the app-token step in the finalize job) to include a repositories input set to ${{ github.event.repository.name }} so the generated token is limited to the current repository only.Source: Linters/SAST tools
🧹 Nitpick comments (2)
.github/workflows/tags.yaml (2)
336-338: 💤 Low valueOptional: Disable implicit caching on setup-node if strict security posture is desired.
Static analysis flags that
actions/setup-nodeenables caching by default when a lockfile is present, which could theoretically be exploited in cache poisoning scenarios. Given this runs on self-hosted runners and the job hascontinue-on-error: true, the practical risk is low.To explicitly disable caching if desired:
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 22 cache: ''🤖 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/tags.yaml around lines 336 - 338, The workflow uses actions/setup-node@... with node-version: 22 and currently relies on implicit caching; to disable implicit lockfile-based caching set the cache input to an empty string in the setup invocation (update the uses: actions/setup-node step where node-version: 22 is specified to include cache: ''), which will explicitly turn off setup-node's automatic caching behavior on that job.Source: Linters/SAST tools
34-38: 💤 Low valueInformational: GitHub App token permissions are app-installation scoped.
The static analysis tool flags that app tokens inherit "blanket installation permissions." This is expected behavior—the token's capabilities are bounded by the GitHub App's installation configuration, not this workflow. The workflow correctly demonstrates least-privilege awareness by minting a separate read-only token at line 275 for the AI changelog step where write access isn't needed.
Reducing the app installation's permissions (if broader than necessary) would be a separate infrastructure change outside this PR's scope.
🤖 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/tags.yaml around lines 34 - 38, Add a short inline comment above the actions/create-github-app-token step to state that GitHub App tokens are scoped to the App installation (permissions come from the App installation configuration) and that a separate least-privilege read-only token is minted later for steps that don’t need write access; reference the existing keys (app-id, private-key, owner) so reviewers understand this is intentional and not a workflow misconfiguration.Source: Linters/SAST tools
🤖 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/pre-commit.yml:
- Line 22: Update the actions/checkout pin in the pre-commit workflow so it
matches the repo standard: replace the current uses entry that references
actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 (v3) with the v4 SHA
used elsewhere (34e114876b0b11c390a56381ad16ebd13914f8d5) in the uses:
actions/checkout@... line, or alternatively add a short comment explaining why
this workflow must remain on v3 if you intentionally keep it; ensure the single
uses line is updated consistently.
In @.github/workflows/pull-requests.yaml:
- Around line 189-196: The "Generate GitHub App token" step (id: app-token,
uses: actions/create-github-app-token@...) currently issues a token scoped to
the app installation (all repos); restrict it to the current repo by adding the
repositories input: set repositories: ${{ github.event.repository.name }} under
the step's with: block so the generated token is limited to the current pull
request repository.
- Around line 120-126: The Generate GitHub App token step (id: app-token, uses:
actions/create-github-app-token@...) mints a token for owner: cozystack but
doesn’t restrict repositories; update that step to include the repositories
input and pass the current repo (e.g., repositories: ${{ github.repository }})
so the token is scoped to the current repository only.
---
Outside diff comments:
In @.github/workflows/pull-requests-release.yaml:
- Around line 30-36: The GitHub App token step (id: app-token) currently mints a
token with owner: cozystack but no repository scope; update the step that uses
actions/create-github-app-token (the app-token step in the finalize job) to
include a repositories input set to ${{ github.event.repository.name }} so the
generated token is limited to the current repository only.
---
Nitpick comments:
In @.github/workflows/tags.yaml:
- Around line 336-338: The workflow uses actions/setup-node@... with
node-version: 22 and currently relies on implicit caching; to disable implicit
lockfile-based caching set the cache input to an empty string in the setup
invocation (update the uses: actions/setup-node step where node-version: 22 is
specified to include cache: ''), which will explicitly turn off setup-node's
automatic caching behavior on that job.
- Around line 34-38: Add a short inline comment above the
actions/create-github-app-token step to state that GitHub App tokens are scoped
to the App installation (permissions come from the App installation
configuration) and that a separate least-privilege read-only token is minted
later for steps that don’t need write access; reference the existing keys
(app-id, private-key, owner) so reviewers understand this is intentional and not
a workflow misconfiguration.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 019b05a6-5cb4-4e2f-92d0-2f910bb8864c
📒 Files selected for processing (13)
.github/workflows/auto-release.yaml.github/workflows/backport.yaml.github/workflows/codegen-drift.yml.github/workflows/labels.yaml.github/workflows/pr-labeler.yaml.github/workflows/pr-size.yaml.github/workflows/pre-commit.yml.github/workflows/pull-requests-release.yaml.github/workflows/pull-requests.yaml.github/workflows/retest.yaml.github/workflows/stale.yaml.github/workflows/tags.yaml.github/workflows/update-releasenotes.yaml
🚧 Files skipped from review as they are similar to previous changes (4)
- .github/workflows/update-releasenotes.yaml
- .github/workflows/pr-labeler.yaml
- .github/workflows/stale.yaml
- .github/workflows/backport.yaml
🛑 Comments failed to post (3)
.github/workflows/pre-commit.yml (1)
22-22:
⚠️ Potential issue | 🟡 Minor🧩 Analysis chain
🏁 Script executed:
#!/bin/bash # Check all checkout action versions in this PR's workflow files echo "=== Checkout action versions across workflows ===" rg -n "uses:\s*actions/checkout@" .github/workflows/ | sortRepository: cozystack/cozystack
Length of output: 1979
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "=== pre-commit.yml around line 22 ===" nl -ba .github/workflows/pre-commit.yml | sed -n '1,80p'Repository: cozystack/cozystack
Length of output: 162
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "=== pre-commit.yml ===" nl -ba .github/workflows/pre-commit.yml | sed -n '1,120p'Repository: cozystack/cozystack
Length of output: 147
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "=== .github/workflows/pre-commit.yml (lines 1-120) ===" nl -ba .github/workflows/pre-commit.yml | sed -n '1,120p'Repository: cozystack/cozystack
Length of output: 179
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "=== .github/workflows/pre-commit.yml (lines 1-60) ===" awk 'NR>=1 && NR<=60 {printf "%d:%s\n", NR, $0}' .github/workflows/pre-commit.yml echo "=== .github/workflows/pre-commit.yml (line 22 only) ===" awk 'NR==22 {printf "%d:%s\n", NR, $0}' .github/workflows/pre-commit.ymlRepository: cozystack/cozystack
Length of output: 2379
Align
actions/checkoutpin in.github/workflows/pre-commit.ymlwith the rest of the repo
.github/workflows/pre-commit.ymlpinsactions/checkouttov3(@f43a0e5ff2bd294095638e18286ca9a3d1956744) while other workflows pin to thev4SHA (@34e114876b0b11c390a56381ad16ebd13914f8d5). Updatepre-commit.ymlto match for consistency, or document whyv3must be kept.uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3🤖 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/pre-commit.yml at line 22, Update the actions/checkout pin in the pre-commit workflow so it matches the repo standard: replace the current uses entry that references actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 (v3) with the v4 SHA used elsewhere (34e114876b0b11c390a56381ad16ebd13914f8d5) in the uses: actions/checkout@... line, or alternatively add a short comment explaining why this workflow must remain on v3 if you intentionally keep it; ensure the single uses line is updated consistently..github/workflows/pull-requests.yaml (2)
120-126:
⚠️ Potential issue | 🟠 Major | ⚡ Quick winScope the GitHub App token to the current repository.
The
resolve_assetsjob mints a GitHub App token withowner: cozystackbut norepositoriesinput, granting access to all repositories in the installation. Add the repository restriction:Suggested patch
- name: Generate GitHub App token id: app-token uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1 with: app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} owner: cozystack + repositories: ${{ github.event.repository.name }}🧰 Tools
🪛 zizmor (1.25.2)
[error] 126-126: dangerous use of GitHub App tokens (github-app): token granted access to all repositories for this owner's app installation
(github-app)
[error] 122-122: dangerous use of GitHub App tokens (github-app): app token inherits blanket installation permissions
(github-app)
🤖 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/pull-requests.yaml around lines 120 - 126, The Generate GitHub App token step (id: app-token, uses: actions/create-github-app-token@...) mints a token for owner: cozystack but doesn’t restrict repositories; update that step to include the repositories input and pass the current repo (e.g., repositories: ${{ github.repository }}) so the token is scoped to the current repository only.Source: Linters/SAST tools
189-196:
⚠️ Potential issue | 🟠 Major | ⚡ Quick winScope the GitHub App token to the current repository in the e2e job.
Same issue as in
resolve_assets: the token is granted access to all repositories for the owner's app installation. Addrepositories: ${{ github.event.repository.name }}.Suggested patch
- name: Generate GitHub App token if: contains(github.event.pull_request.labels.*.name, 'release') id: app-token uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1 with: app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} owner: cozystack + repositories: ${{ github.event.repository.name }}📝 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.- name: Generate GitHub App token if: contains(github.event.pull_request.labels.*.name, 'release') id: app-token uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1 with: app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} owner: cozystack repositories: ${{ github.event.repository.name }}🧰 Tools
🪛 zizmor (1.25.2)
[error] 196-196: dangerous use of GitHub App tokens (github-app): token granted access to all repositories for this owner's app installation
(github-app)
[error] 192-192: dangerous use of GitHub App tokens (github-app): app token inherits blanket installation permissions
(github-app)
🤖 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/pull-requests.yaml around lines 189 - 196, The "Generate GitHub App token" step (id: app-token, uses: actions/create-github-app-token@...) currently issues a token scoped to the app installation (all repos); restrict it to the current repo by adding the repositories input: set repositories: ${{ github.event.repository.name }} under the step's with: block so the generated token is limited to the current pull request repository.Source: Linters/SAST tools
4feac5b to
716b4ea
Compare
Aleksei Sviridkin (lexfrei)
left a comment
There was a problem hiding this comment.
Re-approving after rebase onto current main (no content changes).
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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/pre-commit.yml:
- Line 22: The workflow is pinning actions/checkout to the v3 SHA (uses:
actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744) which is inconsistent
with other workflows; update the uses: entry to the v4 SHA (34e114...) to match
the majority of workflows (replace the current actions/checkout SHA with the v4
SHA), or if v3 is intentionally required keep the current pin but add a short
comment explaining why v3 is needed for this workflow.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 57eb9039-f318-43ca-9794-14a8d466d47d
📒 Files selected for processing (13)
.github/workflows/auto-release.yaml.github/workflows/backport.yaml.github/workflows/codegen-drift.yml.github/workflows/labels.yaml.github/workflows/pr-labeler.yaml.github/workflows/pr-size.yaml.github/workflows/pre-commit.yml.github/workflows/pull-requests-release.yaml.github/workflows/pull-requests.yaml.github/workflows/retest.yaml.github/workflows/stale.yaml.github/workflows/tags.yaml.github/workflows/update-releasenotes.yaml
🚧 Files skipped from review as they are similar to previous changes (5)
- .github/workflows/pr-labeler.yaml
- .github/workflows/stale.yaml
- .github/workflows/retest.yaml
- .github/workflows/update-releasenotes.yaml
- .github/workflows/backport.yaml
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check all checkout SHAs used across workflows
echo "=== actions/checkout versions in workflows ==="
rg -n "uses:\s*actions/checkout@" .github/workflows/ | sortRepository: cozystack/cozystack
Length of output: 1976
Align actions/checkout pin in pre-commit.yml (line 22).
.github/workflows/pre-commit.yml pins actions/checkout to the v3 SHA, while most other workflows use the v4 SHA (34e114...)—and a couple use @v4 or v6.0.2. Update to the v4 SHA for consistency unless v3 is required (then document why).
🤖 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/pre-commit.yml at line 22, The workflow is pinning
actions/checkout to the v3 SHA (uses:
actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744) which is inconsistent
with other workflows; update the uses: entry to the v4 SHA (34e114...) to match
the majority of workflows (replace the current actions/checkout SHA with the v4
SHA), or if v3 is intentionally required keep the current pin but add a short
comment explaining why v3 is needed for this workflow.
716b4ea to
710fe65
Compare
The build-main cache warmer is a privileged workflow (packages:write + an OCIR push token) and never pushes git, so set persist-credentials: false to keep the checkout's GITHUB_TOKEN out of .git/config where a later build step could read it. (SHA-pinning the actions is handled repo-wide in #2849.) Addresses non-blocking follow-up 7 on #2948. Assisted-By: Claude <noreply@anthropic.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
## What Consolidated landing branch for a set of interdependent platform/CI stabilization fixes. It began as the source PRs in the table below (in dependency order) and has since grown with review-driven fixes and a few production-behavior changes — the full current inventory is under **Scope** below. Landing them as one unit lets CI run against the real combined state instead of a fragile bottom-up merge train. ## Source PRs (dependency order) | # | Commit | Source PR | Addresses | |---|--------|-----------|-----------| | 1 | fix(capi): startupProbe on capi-controller-manager | #2946 | capi crashloop during cert provisioning | | 2 | test(e2e): bucket.bats port-forward + S3 client reliability | #2944 | flaky bucket test | | 3 | fix(seaweedfs): restore -lock BucketClass, s3 svc name, drop volumeSizeLimitMB | #2943 | missing bucket/access classes | | 4 | test(e2e): in-cluster Cilium endpoint-leak healer (install + apps) | #2874 | cilium "IP already in use" leak | | 5 | refactor(build): mode=max registry cache + main-only warmer | #2938 | build cache | | 6 | ci(build): isolate each PR build on its own ephemeral runner VM | #2939 | shared-buildkit contention | | 7 | fix(e2e): LINSTOR post-install waits on a single 15m deadline | #2928 | LINSTOR provisioning timeouts | | 8 | test(metallb): assert digest-pinned image form, not version literal | #2873 | brittle metallb assertion | ## Why consolidated These form a dependency DAG (verified from CI logs): e.g. 2943 needs 2946, 2938 needs 2874, 2928 needs 2938/2939, 2873 needs 2928. Tested bottom-up, each lower PR runs with none of the fixes above it and can't go green alone. This branch carries all of them, so CI runs against the real combined state. ## Verification status CI is green on the latest head (`5653c30`): full-suite E2E passes end-to-end and is reproducible (2 of 3 runs on this SHA green). The one red run was a LINSTOR tie-breaker / DRBD-metadata infra flake on the sandbox, unrelated to the diff — a different environmental subsystem failed each run (details in the comments below). The earlier 3-hour crust-gather snapshot hang is fixed in `5653c30`. ## Scope beyond the original 8 The branch has grown past the 8 source PRs above with review-driven fixes and a few production-behavior changes. For reviewer transparency, the full set: **Review fixes (@lexfrei review):** - **B1 (blocker)** — `8f41910` converts the SeaweedFS `-lock`/`-readonly` BucketClasses and the s3 service-name override into `patches/`, wired into `make update`, so a re-vendor no longer drops them. - **FU1** — `cc99230` grants the cilium leak-healer `delete` on pods (both delete remedies were RBAC-forbidden). - **FU3** — `014de3f` adds a unit test for the HelmRelease update conflict-retry path. - **FU4** — `6deddc6` makes the leak-healer refuse a disconnect for any non-terminal owner phase, not just `Running`. - **FU7** — `f3914d2` sets `persist-credentials: false` on the build-cache checkout (SHA-pinning is handled repo-wide in #2849). **Production-behavior changes (not in the table above):** - VPA `updateMode: Auto → Initial` for etcd (`6e9ff90`) and monitoring (`0997105`), plus `vmselect`/`vmstorage` `minAllowed` floors — stops install-time eviction churn. - cozystack-api: `retry.RetryOnConflict` on the Application→HelmRelease update path (`728f676`). **E2E robustness follow-ups:** per-test crust-gather snapshots (`50e5f94`), EtcdBackupSchedule wait (`763b85e`), tenant-node single-deadline wait (`9e43d45`), harbor BucketClaim 10m budget (`d7f244f`), tenant API via LoadBalancer (`9beda4e`), crust-gather pin (`95f42aa`). **Not addressed (by decision):** FU2 — the s3 Service keeps `seaweedfs.name`-based naming via patch (rendered output unchanged; cozystack renders `fullname == seaweedfs`, so it matches the `componentName`/`fullname` siblings in practice). FU6 — fork PR build push is handled by the existing mirror-to-same-repo-branch workflow. ## Relates to #2946 #2944 #2943 #2874 #2938 #2939 #2928 #2873 — if this lands, those can be closed; otherwise they remain the granular per-PR review path. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added CI build cache warming for main branch builds. * Added a best-effort in-cluster Cilium endpoint self-heal watchdog for e2e installs. * Extended SeaweedFS COSI with object-lock support plus separate readonly access. * **Improvements** * Reduced e2e install flakiness with a shared readiness deadline, safer waits, and improved cleanup/diagnostics capture. * Prevented install-time churn by switching VPA update mode to **Initial**. * Added container startup probes and updated SeaweedFS volume sizing. * **Tests** * Improved e2e robustness (etcd backup schedule waiting, digest-pinned image checks, and corrected S3 port-forwarding). <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Raise the OpenSSF Scorecard Token-Permissions and Pinned-Dependencies checks (both currently 0/10) ahead of CNCF Incubation due diligence: - Declare a top-level read-only default (permissions: contents: read) in every workflow, plus an explicit per-job permissions: block that grants only the writes that job actually needs. Workflows that previously held write scopes at the workflow level (backport, pr-labeler, pr-size, stale) now hold them at job level instead. - Pin every GitHub-owned and third-party action to a full commit SHA with a version comment. scorecard.yml was already pinned in #2721. No triggers, job graph, or step logic change; only token scopes and action refs. Self-hosted release jobs keep the exact write scopes they already declared. Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com> Assisted-By: Claude <noreply@anthropic.com>
710fe65 to
76ad921
Compare
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
.github/workflows/tags.yaml (2)
467-492: 🔒 Security & Privacy | 🟠 MajorLimit the website App token to the website repository.
This job only checks out and opens a PR in
cozystack/website; withowner: cozystackand norepositoriesparameter, the token has access to all repositories in the App installation.Suggested patch
with: app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} owner: cozystack + repositories: website + permission-contents: write + permission-pull-requests: write + permission-metadata: read🤖 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/tags.yaml around lines 467 - 492, The `create-github-app-token` action in the workflow is configured with `owner: cozystack` but lacks a `repositories` parameter, which grants the token access to all repositories in the organization. Since this job only accesses the `cozystack/website` repository for checkout and PR operations, add a `repositories` parameter to the `create-github-app-token` action step to explicitly limit the token scope to just the website repository, restricting the token's access from the entire organization to only what is needed.Source: Linters/SAST tools
307-312: 🔒 Security & Privacy | 🟠 MajorUse the read-only token for checkout and omit unnecessary write credentials.
The workflow explicitly creates a read-only token (
app-token-read) to constrain the AI step, but the checkout at lines 307-312 uses the full write token (steps.app-token) instead. Checkout only requires read access to fetch the tag; using the write token unnecessarily persists elevated credentials. Apply the suggested fix to useapp-token-readwithpersist-credentials: false.Suggested patch
- name: Checkout release tag uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: ref: ${{ steps.tag.outputs.tag }} fetch-depth: 0 fetch-tags: true - token: ${{ steps.app-token.outputs.token }} + token: ${{ steps.app-token-read.outputs.token }} + persist-credentials: false🤖 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/tags.yaml around lines 307 - 312, The checkout action in the workflow is using the full write token (steps.app-token.outputs.token) when it should use the read-only token (app-token-read) since checkout only needs read access to fetch the tag. Replace the token reference in the checkout step's token parameter with the read-only app-token-read token, and add persist-credentials: false to ensure elevated credentials are not unnecessarily persisted to the runner environment..github/workflows/pull-requests-release.yaml (1)
32-36: 🔒 Security & Privacy | 🟠 MajorConstrain the release App token to only required permissions.
This job only needs write access to repository contents (for tags and branches) and read access to metadata (for releases). Without explicit permission parameters, the token inherits all permissions granted to the GitHub App installation, violating the principle of least privilege.
Suggested patch
with: app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} owner: cozystack + repositories: ${{ github.event.repository.name }} + permission-contents: write + permission-metadata: read🤖 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/pull-requests-release.yaml around lines 32 - 36, The create-github-app-token action is not constraining the generated token to only the required permissions, which violates the principle of least privilege. Add a permissions parameter to the action configuration that explicitly grants only write access to repository contents (for managing tags and branches) and read access to metadata (for releases). This ensures the token has minimal necessary permissions rather than inheriting all permissions from the GitHub App installation.Source: Linters/SAST tools
🤖 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/pull-requests-release.yaml:
- Around line 56-58: The actions/checkout action is persisting the GITHUB_TOKEN
via git configuration, which prevents the APP_TOKEN from being used in
subsequent git operations. In the
actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 step's with section
(where fetch-depth is already configured), add persist-credentials: false to
disable automatic token persistence and allow the APP_TOKEN set in earlier steps
to be used for git operations like the remote set-url call that follows.
In @.github/workflows/pull-requests.yaml:
- Around line 62-65: The actions/checkout step in the Build job (line 62-65)
stores the GITHUB_TOKEN in git config by default when elevated permissions are
present, creating a security risk. Add persist-credentials: false to the with
section of the checkout action in the Build job to disable credential
persistence. Additionally, apply the same change to the E2E job's checkout
action (mentioned at line 207) which has checks: write permission, ensuring both
elevated-permission checkout operations prevent credential storage.
- Around line 73-79: The "Set up build toolchain" step installs helm-unittest
plugin and Flux CLI without pinning to specific versions, which results in
non-reproducible builds. Modify the helm plugin install command to specify an
exact version tag for the helm-unittest plugin (e.g., appending a version
constraint to the GitHub URL) and update the Flux installation curl command to
download a specific release version instead of the latest. Alternatively,
consider baking these pre-built tools into the oracle-vm runner image as a more
robust solution to ensure consistency across all builds.
- Around line 143-149: The "Generate GitHub App token" step in the
pull-requests.yaml workflow currently specifies only owner: cozystack without
limiting the repositories, which grants the token access to all repositories in
the organization. To scope this token only to the current repository as needed
for listing and downloading draft release assets, add a repositories field to
the with: section of the actions/create-github-app-token action that specifies
the current repository name. This change should be applied to both occurrences
of the token generation step (the one shown and the one at lines 212-219).
---
Outside diff comments:
In @.github/workflows/pull-requests-release.yaml:
- Around line 32-36: The create-github-app-token action is not constraining the
generated token to only the required permissions, which violates the principle
of least privilege. Add a permissions parameter to the action configuration that
explicitly grants only write access to repository contents (for managing tags
and branches) and read access to metadata (for releases). This ensures the token
has minimal necessary permissions rather than inheriting all permissions from
the GitHub App installation.
In @.github/workflows/tags.yaml:
- Around line 467-492: The `create-github-app-token` action in the workflow is
configured with `owner: cozystack` but lacks a `repositories` parameter, which
grants the token access to all repositories in the organization. Since this job
only accesses the `cozystack/website` repository for checkout and PR operations,
add a `repositories` parameter to the `create-github-app-token` action step to
explicitly limit the token scope to just the website repository, restricting the
token's access from the entire organization to only what is needed.
- Around line 307-312: The checkout action in the workflow is using the full
write token (steps.app-token.outputs.token) when it should use the read-only
token (app-token-read) since checkout only needs read access to fetch the tag.
Replace the token reference in the checkout step's token parameter with the
read-only app-token-read token, and add persist-credentials: false to ensure
elevated credentials are not unnecessarily persisted to the runner environment.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: fc6a8cd5-8734-4ec7-a433-2b75f399b96d
📒 Files selected for processing (13)
.github/workflows/auto-release.yaml.github/workflows/backport.yaml.github/workflows/codegen-drift.yml.github/workflows/labels.yaml.github/workflows/pr-labeler.yaml.github/workflows/pr-size.yaml.github/workflows/pre-commit.yml.github/workflows/pull-requests-release.yaml.github/workflows/pull-requests.yaml.github/workflows/retest.yaml.github/workflows/stale.yaml.github/workflows/tags.yaml.github/workflows/update-releasenotes.yaml
🚧 Files skipped from review as they are similar to previous changes (5)
- .github/workflows/retest.yaml
- .github/workflows/update-releasenotes.yaml
- .github/workflows/stale.yaml
- .github/workflows/pr-labeler.yaml
- .github/workflows/backport.yaml
There was a problem hiding this comment.
Caution
Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
.github/workflows/tags.yaml (2)
467-492: 🔒 Security & Privacy | 🟠 MajorLimit the website App token to the website repository.
This job only checks out and opens a PR in
cozystack/website; withowner: cozystackand norepositoriesparameter, the token has access to all repositories in the App installation.Suggested patch
with: app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} owner: cozystack + repositories: website + permission-contents: write + permission-pull-requests: write + permission-metadata: read🤖 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/tags.yaml around lines 467 - 492, The `create-github-app-token` action in the workflow is configured with `owner: cozystack` but lacks a `repositories` parameter, which grants the token access to all repositories in the organization. Since this job only accesses the `cozystack/website` repository for checkout and PR operations, add a `repositories` parameter to the `create-github-app-token` action step to explicitly limit the token scope to just the website repository, restricting the token's access from the entire organization to only what is needed.Source: Linters/SAST tools
307-312: 🔒 Security & Privacy | 🟠 MajorUse the read-only token for checkout and omit unnecessary write credentials.
The workflow explicitly creates a read-only token (
app-token-read) to constrain the AI step, but the checkout at lines 307-312 uses the full write token (steps.app-token) instead. Checkout only requires read access to fetch the tag; using the write token unnecessarily persists elevated credentials. Apply the suggested fix to useapp-token-readwithpersist-credentials: false.Suggested patch
- name: Checkout release tag uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: ref: ${{ steps.tag.outputs.tag }} fetch-depth: 0 fetch-tags: true - token: ${{ steps.app-token.outputs.token }} + token: ${{ steps.app-token-read.outputs.token }} + persist-credentials: false🤖 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/tags.yaml around lines 307 - 312, The checkout action in the workflow is using the full write token (steps.app-token.outputs.token) when it should use the read-only token (app-token-read) since checkout only needs read access to fetch the tag. Replace the token reference in the checkout step's token parameter with the read-only app-token-read token, and add persist-credentials: false to ensure elevated credentials are not unnecessarily persisted to the runner environment..github/workflows/pull-requests-release.yaml (1)
32-36: 🔒 Security & Privacy | 🟠 MajorConstrain the release App token to only required permissions.
This job only needs write access to repository contents (for tags and branches) and read access to metadata (for releases). Without explicit permission parameters, the token inherits all permissions granted to the GitHub App installation, violating the principle of least privilege.
Suggested patch
with: app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} owner: cozystack + repositories: ${{ github.event.repository.name }} + permission-contents: write + permission-metadata: read🤖 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/pull-requests-release.yaml around lines 32 - 36, The create-github-app-token action is not constraining the generated token to only the required permissions, which violates the principle of least privilege. Add a permissions parameter to the action configuration that explicitly grants only write access to repository contents (for managing tags and branches) and read access to metadata (for releases). This ensures the token has minimal necessary permissions rather than inheriting all permissions from the GitHub App installation.Source: Linters/SAST tools
🤖 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/pull-requests-release.yaml:
- Around line 56-58: The actions/checkout action is persisting the GITHUB_TOKEN
via git configuration, which prevents the APP_TOKEN from being used in
subsequent git operations. In the
actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 step's with section
(where fetch-depth is already configured), add persist-credentials: false to
disable automatic token persistence and allow the APP_TOKEN set in earlier steps
to be used for git operations like the remote set-url call that follows.
In @.github/workflows/pull-requests.yaml:
- Around line 62-65: The actions/checkout step in the Build job (line 62-65)
stores the GITHUB_TOKEN in git config by default when elevated permissions are
present, creating a security risk. Add persist-credentials: false to the with
section of the checkout action in the Build job to disable credential
persistence. Additionally, apply the same change to the E2E job's checkout
action (mentioned at line 207) which has checks: write permission, ensuring both
elevated-permission checkout operations prevent credential storage.
- Around line 73-79: The "Set up build toolchain" step installs helm-unittest
plugin and Flux CLI without pinning to specific versions, which results in
non-reproducible builds. Modify the helm plugin install command to specify an
exact version tag for the helm-unittest plugin (e.g., appending a version
constraint to the GitHub URL) and update the Flux installation curl command to
download a specific release version instead of the latest. Alternatively,
consider baking these pre-built tools into the oracle-vm runner image as a more
robust solution to ensure consistency across all builds.
- Around line 143-149: The "Generate GitHub App token" step in the
pull-requests.yaml workflow currently specifies only owner: cozystack without
limiting the repositories, which grants the token access to all repositories in
the organization. To scope this token only to the current repository as needed
for listing and downloading draft release assets, add a repositories field to
the with: section of the actions/create-github-app-token action that specifies
the current repository name. This change should be applied to both occurrences
of the token generation step (the one shown and the one at lines 212-219).
---
Outside diff comments:
In @.github/workflows/pull-requests-release.yaml:
- Around line 32-36: The create-github-app-token action is not constraining the
generated token to only the required permissions, which violates the principle
of least privilege. Add a permissions parameter to the action configuration that
explicitly grants only write access to repository contents (for managing tags
and branches) and read access to metadata (for releases). This ensures the token
has minimal necessary permissions rather than inheriting all permissions from
the GitHub App installation.
In @.github/workflows/tags.yaml:
- Around line 467-492: The `create-github-app-token` action in the workflow is
configured with `owner: cozystack` but lacks a `repositories` parameter, which
grants the token access to all repositories in the organization. Since this job
only accesses the `cozystack/website` repository for checkout and PR operations,
add a `repositories` parameter to the `create-github-app-token` action step to
explicitly limit the token scope to just the website repository, restricting the
token's access from the entire organization to only what is needed.
- Around line 307-312: The checkout action in the workflow is using the full
write token (steps.app-token.outputs.token) when it should use the read-only
token (app-token-read) since checkout only needs read access to fetch the tag.
Replace the token reference in the checkout step's token parameter with the
read-only app-token-read token, and add persist-credentials: false to ensure
elevated credentials are not unnecessarily persisted to the runner environment.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: fc6a8cd5-8734-4ec7-a433-2b75f399b96d
📒 Files selected for processing (13)
.github/workflows/auto-release.yaml.github/workflows/backport.yaml.github/workflows/codegen-drift.yml.github/workflows/labels.yaml.github/workflows/pr-labeler.yaml.github/workflows/pr-size.yaml.github/workflows/pre-commit.yml.github/workflows/pull-requests-release.yaml.github/workflows/pull-requests.yaml.github/workflows/retest.yaml.github/workflows/stale.yaml.github/workflows/tags.yaml.github/workflows/update-releasenotes.yaml
🚧 Files skipped from review as they are similar to previous changes (5)
- .github/workflows/retest.yaml
- .github/workflows/update-releasenotes.yaml
- .github/workflows/stale.yaml
- .github/workflows/pr-labeler.yaml
- .github/workflows/backport.yaml
🛑 Comments failed to post (4)
.github/workflows/pull-requests-release.yaml (1)
56-58: 🔒 Security & Privacy | 🟠 Major
🧩 Analysis chain
🏁 Script executed:
cd .github/workflows && cat -n pull-requests-release.yaml | head -100Repository: cozystack/cozystack
Length of output: 4364
🌐 Web query:
actions/checkout persist-credentials default behavior github💡 Result:
The default behavior for the
persist-credentialsinput in theactions/checkoutGitHub Action istrue[1][2][3]. Whenpersist-credentialsis set totrue(the default), the action configures the Git repository using the provided token or SSH key [1][4]. This allows subsequent steps in your workflow to execute authenticated Git commands (such asgit fetchorgit push) without needing to manually re-authenticate [1][5]. Key details regarding this behavior include: - Security Implementation: The action stores the credentials in a separate file (typically under$RUNNER_TEMP) rather than directly inside the.git/configfile to improve security [1][6]. - Post-Job Cleanup: The action includes a post-job cleanup step that removes these persisted credentials once the job completes [1][6]. - Opting Out: If you wish to prevent the action from persisting credentials, you can explicitly setpersist-credentials: falsein your workflow configuration [1][2]. While some users have expressed security concerns regarding the default beingtrue[7][8], it remains the established default to ensure seamless functionality for common Git workflows in GitHub Actions [1][4].Citations:
- 1: https://github.com/actions/checkout/?tab=readme-ov-file
- 2: https://github.com/actions/checkout/blob/main/README.md
- 3: https://github.com/actions/checkout/blob/34e114876b0b11c390a56381ad16ebd13914f8d5/action.yml
- 4: https://github.com/actions/checkout/blob/main/action.yml
- 5: https://github.com/marketplace/actions/checkout?version=v3.6.0
- 6: https://github.com/actions/checkout/tree/refs/heads/main
- 7: actions/checkout#485
- 8: actions/checkout#2312
🌐 Web query:
git remote set-url with credentials persist-credentials actions/checkout precedence💡 Result:
In GitHub Actions, the
actions/checkoutaction handles authentication by injecting a persistent credential—typically aGITHUB_TOKEN—into the local Git configuration [1][2]. Specifically, it sets anhttp.<url>.extraheaderconfiguration entry [3][4]. Because thisextraheaderis applied at the local Git configuration level, it takes precedence over many other credential sources, often making it difficult to override with standard methods likegit remote set-urlor external credential helpers [3][4]. Whenpersist-credentialsis enabled (the default),actions/checkoutensures this authentication configuration persists for the duration of the job [1][2]. If you attempt to usegit remote set-urlto inject different credentials, Git may continue to prefer the injectedextraheaderconfiguration, causing the new remote URL to be ignored for authentication purposes [3][4]. To successfully use different credentials, you have two primary approaches: 1. Disable persistence: Setpersist-credentials: falsein youractions/checkoutstep [1][2][5]. This prevents the action from injecting theextraheader[3]. You can then configure your desired credentials (e.g., using a personal access token) viagit remote set-urlor other authentication commands [6][5]. 2. Clear the extraheader: If you cannot disablepersist-credentials, you must manually unset theextraheaderconfiguration before applying your own credentials [3][4]. You can do this by running: git config --unset http.https://github.com/.extraheader (Adjust the URL host if necessary to match the configured remote) [4]. Note that newer versions ofactions/checkouthave improved security by storing these credentials in a separate file under$RUNNER_TEMPrather than directly in.git/config, but the precedence behavior regardingextraheaderconfiguration remains a significant factor in how subsequent Git operations resolve authentication [1][7].Citations:
- 1: https://github.com/actions/checkout/?tab=readme-ov-file
- 2: https://github.com/actions/checkout/blob/main/README.md
- 3: cli/cli#10905
- 4: actions/checkout#162
- 5: stefanzweifel/git-auto-commit-action#356
- 6: github/gh-aw#2664
- 7: actions/checkout@v5.0.1...v6.0.0
Disable credential persistence to allow APP_TOKEN to be used for git operations.
actions/checkoutpersists the job'sGITHUB_TOKENvia git'shttp.<url>.extraheaderconfiguration. This configuration takes precedence over credentials embedded in the remote URL, which means thegit remote set-urlcall in the next step will not override the persisted token. Addpersist-credentials: falseto allow the APP_TOKEN to be used as intended.- name: Checkout repo uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 + persist-credentials: false📝 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.uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 persist-credentials: false🧰 Tools
🪛 zizmor (1.26.1)
[warning] 55-58: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
🤖 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/pull-requests-release.yaml around lines 56 - 58, The actions/checkout action is persisting the GITHUB_TOKEN via git configuration, which prevents the APP_TOKEN from being used in subsequent git operations. In the actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 step's with section (where fetch-depth is already configured), add persist-credentials: false to disable automatic token persistence and allow the APP_TOKEN set in earlier steps to be used for git operations like the remote set-url call that follows..github/workflows/pull-requests.yaml (3)
62-65: 🔒 Security & Privacy | 🟠 Major
🧩 Analysis chain
🏁 Script executed:
cat -n .github/workflows/pull-requests.yaml | head -300Repository: cozystack/cozystack
Length of output: 14281
Add
persist-credentials: falseto checkout actions in build and e2e jobs.The Build job has
packages: writepermission (line 52), and E2E haschecks: writepermission (line 207). Whenactions/checkoutruns with these elevated scopes, it stores the GITHUB_TOKEN in git config by default. This allows subsequent PR-controlled code to potentially access or misuse the token via commands likegit config --list. Disable credential persistence on both checkouts.Suggested patch
- name: Checkout code uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 fetch-tags: true + persist-credentials: false @@ - name: Checkout code uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 + persist-credentials: false🤖 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/pull-requests.yaml around lines 62 - 65, The actions/checkout step in the Build job (line 62-65) stores the GITHUB_TOKEN in git config by default when elevated permissions are present, creating a security risk. Add persist-credentials: false to the with section of the checkout action in the Build job to disable credential persistence. Additionally, apply the same change to the E2E job's checkout action (mentioned at line 207) which has checks: write permission, ensuring both elevated-permission checkout operations prevent credential storage.
73-79: 🔒 Security & Privacy | 🟠 Major
🧩 Analysis chain
🏁 Script executed:
cat -n .github/workflows/pull-requests.yaml | head -100Repository: cozystack/cozystack
Length of output: 4553
🏁 Script executed:
# Check the full context of the problematic section and surrounding lines sed -n '60,90p' .github/workflows/pull-requests.yamlRepository: cozystack/cozystack
Length of output: 1378
🏁 Script executed:
# Search for other version pins or tool configurations in the workflow rg -i "helm|flux" .github/workflows/pull-requests.yaml -B 2 -A 2Repository: cozystack/cozystack
Length of output: 1482
🏁 Script executed:
# Check for any TODO or issue references about this known limitation rg -i "todo|fixme|issue|pin.*helm|pin.*flux" .github/workflows/pull-requests.yaml -B 2 -A 2Repository: cozystack/cozystack
Length of output: 240
🏁 Script executed:
# Check if there are any version constraints or pins elsewhere in the codebase for these tools fd -type f \( -name "*.yaml" -o -name "*.yml" -o -name "Dockerfile*" -o -name "*.sh" \) -path "./.github/*" -o -path "./Dockerfile*" | head -20 rg "helm-unittest|fluxcd" .github/ --type yaml -lRepository: cozystack/cozystack
Length of output: 399
🏁 Script executed:
# Check the git history to see if there were recent changes related to tool versioning git log --oneline -20 -- .github/workflows/pull-requests.yamlRepository: cozystack/cozystack
Length of output: 1689
Pin Helm and Flux tool versions.
This hardening PR pins actions, but the "Set up build toolchain" step installs the latest helm-unittest plugin and Flux at runtime without version constraints, creating non-reproducible and unverified builds. Either pin exact versions using release tags/SHAs (e.g.,
helm plugin install https://github.com/helm-unittest/helm-unittest@v1.x.x) or bake these tools into the oracle-vm runner image as mentioned in the existing comment.🤖 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/pull-requests.yaml around lines 73 - 79, The "Set up build toolchain" step installs helm-unittest plugin and Flux CLI without pinning to specific versions, which results in non-reproducible builds. Modify the helm plugin install command to specify an exact version tag for the helm-unittest plugin (e.g., appending a version constraint to the GitHub URL) and update the Flux installation curl command to download a specific release version instead of the latest. Alternatively, consider baking these pre-built tools into the oracle-vm runner image as a more robust solution to ensure consistency across all builds.
143-149: 🔒 Security & Privacy | 🟠 Major
🧩 Analysis chain
🏁 Script executed:
# First, let's look at the complete workflow file structure find . -name "pull-requests.yaml" -type f | head -20Repository: cozystack/cozystack
Length of output: 196
🏁 Script executed:
# Once we find the file, let's examine the relevant sections cat -n .github/workflows/pull-requests.yaml | sed -n '140,155p'Repository: cozystack/cozystack
Length of output: 847
🏁 Script executed:
# Also check the second location mentioned (lines 212-219) cat -n .github/workflows/pull-requests.yaml | sed -n '209,225p'Repository: cozystack/cozystack
Length of output: 1072
🌐 Web query:
actions/create-github-app-token action documentation parameters repositories permission-contents💡 Result:
The actions/create-github-app-token action allows for granular control over the GitHub App installation access token it generates using specific input parameters [1][2]. Repositories Parameter The repositories parameter is an optional input that accepts a comma-separated or newline-separated list of repository names to which the token should be granted access [3][4][5]. - Scoping Behavior: If both the owner and repositories inputs are empty, the token is scoped only to the current repository [3][4]. If an owner is set but repositories is empty, the token is scoped to all repositories within that owner's installation [3][4][5]. - Formatting: It supports bare repository names (e.g., repo) as well as full repository names (e.g., owner/repo), provided the owner matches the specified owner input or the current repository owner if the owner is unset [4][6]. Permission-contents Parameter The action supports granular permissions by providing inputs prefixed with permission- [1][2]. The permission-contents parameter is one of these dynamically generated inputs [7]. - Purpose: It specifies the level of permission to grant the access token for repository contents, including commits, branches, downloads, releases, and merges [7]. - Usage: It can be set to either read or write [7]. - Default Behavior: If no specific permission inputs are provided, the generated token inherits all permissions granted to the GitHub App installation [1][2]. It is recommended to explicitly list required permissions for better security [2]. Note that the requested permissions must be granted to the App installation; requesting a permission the App does not possess will cause the action to fail [1][2].
Citations:
- 1: https://deepwiki.com/actions/create-github-app-token/4.1-action-inputs
- 2: https://github.com/actions/create-github-app-token/blob/5c1e00d1af39c515564da2ae21cc9dedf0793346/README.md
- 3: https://github.com/actions/create-github-app-token/blob/34c66235f6ccc38eb01b7aed860890bdf40db33c/README.md
- 4: https://github.com/actions/create-github-app-token
- 5: https://deepwiki.com/actions/create-github-app-token/5.2-cross-repository-operations
- 6: actions/create-github-app-token#372
- 7: actions/create-github-app-token@0e0aa99
🏁 Script executed:
# Let's see what these tokens are used for in the workflow cat -n .github/workflows/pull-requests.yaml | sed -n '143,175p'Repository: cozystack/cozystack
Length of output: 1790
🏁 Script executed:
# Check the second instance and its usage cat -n .github/workflows/pull-requests.yaml | sed -n '212,235p'Repository: cozystack/cozystack
Length of output: 1401
🏁 Script executed:
# Let's search for all references to the app-token to understand its usage rg "steps\.app-token|needs\..+\.outputs\.token" .github/workflows/pull-requests.yaml -A 3 -B 1Repository: cozystack/cozystack
Length of output: 638
🏁 Script executed:
# Get the broader context of both job sections to understand their purpose cat -n .github/workflows/pull-requests.yaml | sed -n '125,160p'Repository: cozystack/cozystack
Length of output: 1631
🏁 Script executed:
# And the second job context cat -n .github/workflows/pull-requests.yaml | sed -n '190,240p'Repository: cozystack/cozystack
Length of output: 2587
🏁 Script executed:
# Let's search for where APP_TOKEN is used in the workflow rg "APP_TOKEN" .github/workflows/pull-requests.yaml -B 2 -A 2Repository: cozystack/cozystack
Length of output: 577
🏁 Script executed:
# Get the complete context of how the e2e job uses the token cat -n .github/workflows/pull-requests.yaml | sed -n '235,300p'Repository: cozystack/cozystack
Length of output: 3636
🏁 Script executed:
# Let's see the full workflow to understand the token usage patterns wc -l .github/workflows/pull-requests.yamlRepository: cozystack/cozystack
Length of output: 198
🏁 Script executed:
# Check the rest of the e2e job and see where APP_TOKEN is used cat -n .github/workflows/pull-requests.yaml | sed -n '250,350p'Repository: cozystack/cozystack
Length of output: 5393
Scope release-asset app tokens to the current repository.
The token generation currently specifies
owner: cozystackwithoutrepositoriesor explicit permission limits. This mints a token with access to all repositories in the cozystack organization and all permissions granted to the GitHub App installation. The tokens are only used to list and download draft release assets from the current repository, so they should be scoped accordingly.Suggested patch
with: app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} owner: cozystack + repositories: ${{ github.event.repository.name }} + permission-contents: read + permission-metadata: readAlso applies to: lines 212-219
🧰 Tools
🪛 zizmor (1.26.1)
[error] 149-149: dangerous use of GitHub App tokens (github-app): token granted access to all repositories for this owner's app installation
(github-app)
[error] 145-145: dangerous use of GitHub App tokens (github-app): app token inherits blanket installation permissions
(github-app)
🤖 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/pull-requests.yaml around lines 143 - 149, The "Generate GitHub App token" step in the pull-requests.yaml workflow currently specifies only owner: cozystack without limiting the repositories, which grants the token access to all repositories in the organization. To scope this token only to the current repository as needed for listing and downloading draft release assets, add a repositories field to the with: section of the actions/create-github-app-token action that specifies the current repository name. This change should be applied to both occurrences of the token generation step (the one shown and the one at lines 212-219).Source: Linters/SAST tools
## What this PR does Raises OpenSSF Scorecard **Pinned-Dependencies** (currently **1/10**) by having Renovate manage and pin container base images and GitHub Actions to immutable digests. [PR #2849](#2849) SHA-pinned actions in 13 workflows, but the Scorecard check also scores **container base images** — 58 unpinned `FROM` lines across **27 distinct images** — which dominate the score and keep it at 1/10. #2849 also left `build-main.yaml` and `release-e2e.yaml` actions unpinned, and nothing in the Renovate config kept the newly-added action SHAs updated (they were set to rot). ### Changes - **`.github/renovate.json`** - Add `dockerfile` and `github-actions` to `enabledManagers` (was `gomod`-only). - `pinDigests: true` for both managers — Renovate opens the initial "pin to `@sha256:`" PR (including the two workflows #2849 missed) and keeps digests fresh thereafter. - Batch the initial pin + all digest-only refreshes into a **single weekly PR** (`matchUpdateTypes: ["digest", "pinDigest"]`, scheduled Monday). Frequently-rebuilt bases (alpine, debian, golang, distroless) would otherwise trickle in one rebuild-triggering PR each and load the shared CI runner. Real tag bumps (major/minor/patch) are intentionally excluded from the group so they get individual review. - Existing `do-not-merge/hold` label + `automerge: false` are unchanged, so every PR still requires a manual merge. - **`packages/system/bucket/images/s3manager/Dockerfile`** — pin floating tags to concrete versions so digest tracking doesn't churn endlessly: `golang:1` → `golang:1.26`, `alpine:latest` → `alpine:3.24`. ### Notes - The bulk digest pin of the 27 images is left to Renovate's first run (one grouped PR) rather than hand-edited here, keeping this PR to the config + tag-hygiene prerequisites. - Expected effect once the follow-up pin PR merges: Pinned-Dependencies **1 → ~7–8**. The remaining `downloadThenRun` / pip / npm items cap it below 10. ### Release note ```release-note ci(renovate): enable Renovate digest pinning for Dockerfile base images and GitHub Actions to improve the OpenSSF Scorecard Pinned-Dependencies score ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Improved automated dependency management for container images and GitHub Actions, including clearer update grouping and digest pinning. * Updated container base images to newer, fixed versions for more predictable builds and deployments. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Enable Renovate's dockerfile and github-actions managers with pinDigests so OpenSSF Scorecard Pinned-Dependencies (currently 1/10) can pass and supply-chain refs stay reproducible. PR cozystack#2849 SHA-pinned actions in 13 workflows, but the check also scores container base images -- 58 unpinned FROM lines across 27 distinct images -- and left build-main.yaml / release-e2e.yaml unpinned. Nothing kept the new action SHAs updated either, so they would silently stop receiving security patches. Enabling the managers lets Renovate open the initial pin PR (and pin the two missed workflows) and keep digests fresh thereafter. Digest-only refreshes and the initial pin are batched into a single weekly PR to avoid a trickle of rebuild-triggering PRs on the shared CI runner; real tag bumps stay individual for review. Also pin s3manager's floating tags (golang:1, alpine:latest) to concrete versions first, otherwise digest tracking churns endlessly. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>

What this PR does
Hardens GitHub Actions security posture to raise two OpenSSF Scorecard checks that currently score 0/10, as part of the push to ≥7.5 ahead of CNCF Incubation due diligence. No workflow triggers, job graphs, or step logic change — only
GITHUB_TOKENscopes and action pin refs.Token-Permissions (was 0/10)
The check failed because several workflows (
codegen-drift.yml,pre-commit.yml,retest.yaml,tags.yaml, …) declared nopermissions:block at all, so their jobs inherited the repository default token — typically read/write across all scopes.This PR applies the OpenSSF-recommended pattern to every workflow:
permissions: { contents: read }.permissions:block granting only the writes that job needs. Workflows that previously held write scopes at the workflow level (backport,pr-labeler,pr-size,stale) now hold them at job level, so the read-only default applies everywhere else.Per-job scopes were derived from what each job actually calls:
contents: write, pull-requests: read(unchanged)contents: readcontents: write, pull-requests: writecontents: readcontents: readcontents: read, issues: write, pull-requests: writecontents: readpull-requests: writepull-requests: writeactions: write, pull-requests: read(unchanged)issues: write, pull-requests: writecontents: write(unchanged)contents: read, pull-requests: readcontents: read, packages: write(unchanged)contents: readcontents: read, packages: read, checks: write(unchanged)contents: write(unchanged)contents/packages/pull-requests/actions: write(unchanged)contents: write, pull-requests: write(unchanged)contents: read(unchanged)Self-hosted release jobs that push tags/branches/releases authenticate via the
cozystack-ciGitHub App token, so reducing the workflowGITHUB_TOKENdoes not affect them; the job-level write scopes they already declared are preserved verbatim.Pinned-Dependencies (was 0/10)
Every GitHub-owned and third-party action is now pinned to a full commit SHA with a human-readable version comment, e.g.
actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.scorecard.ymlwas already SHA-pinned in #2721;breakpoint-actionwas already pinned. SHAs were resolved from each tag's current commit at authoring time, so behavior is identical to the previously-referenced tag.Verification
actionlintover all workflows: exit 0.permissions:blocks and action@refs changed.Release note
Summary by CodeRabbit
contents: read), with select jobs requesting write or additional scopes only when needed.