Conversation
app-ci.yml: - Add type check step (tsc --noEmit) before build - Reduce matrix from 9 to 5 jobs: ubuntu (node 22,23,24) + macos/windows (node 22) - Use setup-node cache for pnpm instead of manual cache step - Clean up path triggers (remove .agents/, .claude/) - Add concurrency group with cancel-in-progress release.yml: - Add required check job: type check, build, test, audit before publish - Add build verification with size output - Add dry-run publish before actual publish - Add workflow_dispatch with dry-run option for manual validation subtrack/package.json: - Add lint:types script (tsc --noEmit) for local type checking
|
Warning Review limit reached
More reviews will be available in 44 minutes and 30 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (6)
📝 WalkthroughWalkthroughAdds a ChangesType-check script and CI/release workflow updates
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
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: 3
🧹 Nitpick comments (1)
.github/workflows/app-ci.yml (1)
65-67: ⚡ Quick winRun spell-check once per matrix to avoid redundant CI work.
if: runner.os == 'Linux'runstyposon all Ubuntu matrix jobs (Node 22/23/24), so the same scan executes three times.Suggested change
- - name: Spell check - if: runner.os == 'Linux' + - name: Spell check + if: runner.os == 'Linux' && matrix.node-version == 22 uses: crate-ci/typos@v1.47.2🤖 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/app-ci.yml around lines 65 - 67, The spell-check step with the "Spell check" name currently runs on all Ubuntu matrix jobs because the condition only checks runner.os == 'Linux' without accounting for the matrix strategy. To avoid redundant CI work, update the if condition to also check for a specific matrix value (such as a specific Node version like matrix.node-version == '22') in addition to the runner.os check, so the step executes only once per workflow run instead of once per matrix combination.
🤖 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/release.yml:
- Around line 6-11: The workflow_dispatch dry-run input defined in the inputs
section is unreachable because the job gating condition for the publish job
blocks execution on manual dispatch. Modify the condition that gates the publish
job (around line 41-42) to allow the job to run when the workflow is manually
triggered via workflow_dispatch, rather than blocking it entirely. This will
make the dry-run input accessible and usable during manual workflow execution.
- Around line 17-21: Replace all tag-pinned GitHub Actions references in the
release.yml workflow with full commit SHAs for security. For each action using
`@v4` format (actions/checkout@v4, pnpm/action-setup@v4, actions/setup-node@v4,
and any others in lines 47-51), replace the tag with the corresponding
full-length commit SHA and add an inline comment with the version tag for
reference. This prevents tag mutation attacks by pinning to immutable commit
hashes.
- Around line 13-17: The `check` job in the release workflow lacks explicit
minimal permissions and the checkout actions do not prevent Git credential
persistence. Add `permissions: contents: read` at the job level for the `check`
job to enforce least-privilege access, and add `persist-credentials: false` to
both the checkout@v4 action calls (one at line 17 and another around line 47) to
prevent Git credentials from persisting in the runner and being available to
later steps.
---
Nitpick comments:
In @.github/workflows/app-ci.yml:
- Around line 65-67: The spell-check step with the "Spell check" name currently
runs on all Ubuntu matrix jobs because the condition only checks runner.os ==
'Linux' without accounting for the matrix strategy. To avoid redundant CI work,
update the if condition to also check for a specific matrix value (such as a
specific Node version like matrix.node-version == '22') in addition to the
runner.os check, so the step executes only once per workflow run instead of once
per matrix combination.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 25d5037b-bd2e-4226-b341-eab459032bb8
📒 Files selected for processing (4)
.agents/skills/subtrack-rules/SKILL.md.github/workflows/app-ci.yml.github/workflows/release.ymlsubtrack/package.json
| jobs: | ||
| publish: | ||
| check: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name "release.yml" -path "*/.github/workflows/*" | head -20Repository: nazozokc/subtrack
Length of output: 93
🏁 Script executed:
cat -n .github/workflows/release.ymlRepository: nazozokc/subtrack
Length of output: 2765
🌐 Web query:
GitHub Actions checkout action persist-credentials security best practice
💡 Result:
Best-practice answer (2026-06-21): 1) Set persist-credentials: false on actions/checkout unless you truly need authenticated git operations (push, authenticated fetch, writing tags/branches, etc.). This reduces the chance Git credentials/token are persisted in the runner’s local git configuration/environment for later steps. [1][2] Example: uses: actions/checkout@v4 with: persist-credentials: false 2) Reduce GITHUB_TOKEN permissions to the minimum required for each workflow/job. Even if you disable credential persistence, actions can still access GITHUB_TOKEN via the github.token context; least-privilege permissions limits impact of compromise. [3][4] 3) Do not check out and execute untrusted code in a more-privileged/trusted context (e.g., avoid unsafe pull_request_target patterns). Credential persistence is one layer; broader workflow trigger/context hardening matters too. [1] Why persist-credentials: false: - The actions/checkout documentation explains that the auth token is persisted in the local git config so scripts can run authenticated git commands, and that you can opt out by setting persist-credentials: false. [2][5] - OWASP’s GitHub Actions security guidance explicitly recommends using actions/checkout with persist-credentials: false unless needed. [1] Concrete hardening checklist: - For read-only jobs (build/test/lint): set persist-credentials: false and grant the job only contents: read (or similarly minimal permissions). [1][3][4] - For jobs that must push: you may need authenticated git operations; keep persist-credentials enabled only for that job, and still scope GITHUB_TOKEN permissions tightly to what the job needs. [2][3][4] - For workflows that run code from forks/untrusted PRs: avoid executing untrusted code in a privileged context. [1]
Citations:
- 1: https://cheatsheetseries.owasp.org/cheatsheets/GitHub_Actions_Security_Cheat_Sheet.html
- 2: https://github.com/actions/checkout/?tab=readme-ov-file
- 3: https://github.com/github/docs/blob/main/content/actions/tutorials/authenticate-with-github_token.md
- 4: https://docs.github.com/en/actions/concepts/security/github_token
- 5: https://github.com/actions/checkout/blob/main/README.md
🌐 Web query:
GitHub Actions workflow permissions token scope hardening
💡 Result:
Hardening GitHub Actions workflow permissions is a critical security practice to minimize the blast radius of potential compromises [1][2]. The primary mechanism for this is the explicit control of the GITHUB_TOKEN, an automatically generated, short-lived installation access token provided to every workflow run [3][4]. Key strategies for hardening token permissions include: 1. Follow the Principle of Least Privilege: By default, workflows may inherit broad read/write permissions [5]. You should always define the minimum required permissions explicitly within your workflow files [1][6]. Start by setting all permissions to none at the top level, then grant only the specific scopes required for the task [1][2]. Example: permissions: {} # Disables all default permissions jobs: build: runs-on: ubuntu-latest permissions: contents: read # Grant only what is necessary for this job steps: - uses: actions/checkout@v4 2. Configure Repository/Organization Defaults: To prevent accidental over-permissioning, configure your repository or organization settings to use the restricted default (read-only for contents and packages) rather than the permissive default (read/write for all) [5][7]. Navigate to Settings > Actions > General > Workflow permissions to apply this [7]. 3. Use Job-Level Granularity: Permissions can be set at both the workflow level and the job level [6]. To maximize security, define permissions at the job level [5]. This ensures that if a workflow contains multiple jobs, a compromise in one job does not grant that job's token unnecessary access to resources required only by other jobs [1][8]. 4. Harden OIDC Permissions: When using OpenID Connect (OIDC) to authenticate with external cloud providers (e.g., AWS, GCP, Azure), you must explicitly grant the id-token: write permission [9][10]. This permission does not grant access to repository resources; it specifically enables the workflow to request a short-lived JSON Web Token (JWT) from GitHub's OIDC provider to exchange for cloud credentials [10][11]. Apply this permission only to the specific job that performs the authentication [8]. 5. Avoid Risky Triggers: Be cautious with triggers such as pull_request_target and workflow_run [1]. These can execute with high privileges, even when triggered by untrusted sources (e.g., external pull requests), and may be exploited to exfiltrate secrets or manipulate the repository [1][12]. Avoid checking out untrusted code when using these triggers [1][5]. By implementing these practices—explicitly defining permissions, defaulting to read-only or no access, and using granular job-level overrides—you significantly improve your CI/CD pipeline's security posture [2][5].
Citations:
- 1: https://cheatsheetseries.owasp.org/cheatsheets/GitHub_Actions_Security_Cheat_Sheet.html
- 2: https://secure-pipelines.com/ci-cd-security/github-actions-security-cheat-sheet/
- 3: https://docs.github.com/en/actions/concepts/security/github_token
- 4: https://github.blog/changelog/2021-04-20-github-actions-control-permissions-for-github_token/
- 5: https://secure-pipelines.com/ci-cd-security/github-actions-security-definitive-guide/
- 6: https://docs.github.com/actions/reference/authentication-in-a-workflow
- 7: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository
- 8: https://developer.hashicorp.com/well-architected-framework/secure-systems/secure-applications/ci-cd-secrets/github-actions
- 9: https://docs.github.com/en/actions/concepts/security/openid-connect
- 10: https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-aws
- 11: https://github.com/github/docs/blob/main/content/actions/reference/security/oidc.md
- 12: https://docs.github.com/en/actions/reference/security/secure-use
Harden token scope and checkout credential persistence.
The check job lacks explicit minimal permissions. Both checkout steps (lines 17 and 47) should set persist-credentials: false to prevent Git credentials from persisting in the runner for later steps. Additionally, the check job should explicitly declare permissions: contents: read for least-privilege access.
Suggested change
+permissions:
+ contents: read
+
jobs:
check:
+ permissions:
+ contents: read
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v4
+ with:
+ persist-credentials: false
@@
publish:
@@
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v4
+ with:
+ persist-credentials: false🧰 Tools
🪛 zizmor (1.25.2)
[warning] 17-17: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 17-17: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🤖 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/release.yml around lines 13 - 17, The `check` job in the
release workflow lacks explicit minimal permissions and the checkout actions do
not prevent Git credential persistence. Add `permissions: contents: read` at the
job level for the `check` job to enforce least-privilege access, and add
`persist-credentials: false` to both the checkout@v4 action calls (one at line
17 and another around line 47) to prevent Git credentials from persisting in the
runner and being available to later steps.
Source: Linters/SAST tools
| - uses: actions/checkout@v4 | ||
|
|
||
| - uses: pnpm/action-setup@v4 | ||
|
|
||
| - uses: actions/setup-node@v4 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n .github/workflows/release.yml | head -60Repository: nazozokc/subtrack
Length of output: 1690
🌐 Web query:
GitHub Actions SHA pinning vs tag pinning security best practices official
💡 Result:
GitHub strongly recommends pinning actions to a full-length commit SHA as the primary method to ensure security, immutability, and reproducibility in your workflows [1][2][3]. The fundamental difference between pinning to a tag and pinning to a SHA lies in mutability: Tags are mutable, meaning they can be moved, deleted, or re-pointed to different commits by anyone with write access to the action's repository [1][4][5]. If an attacker gains control of a repository, they can update existing tags to point to malicious code, which will then execute in any workflow referencing that tag [6][7][8]. SHAs are immutable, meaning they represent a specific, unique commit in the repository history [4][9]. When you pin to a full-length commit SHA, you guarantee that your workflow will only ever run the exact code you have reviewed and verified, protecting you from "tag-retargeting" supply chain attacks [6][4][5]. Key best practices for GitHub Actions security include: 1. Use SHA Pinning: Pin all third-party actions to their full-length (40-character) commit SHA [1][9][5]. 2. Maintain Visibility with Comments: Since commit SHAs are not human-readable, include the original version tag in a comment after the SHA to help you track which version you are using (e.g., uses: actions/checkout@a824008 # v4.2.2) [6][10]. 3. Automate Updates: Do not avoid updates; use automated dependency management tools like Dependabot or Renovate to keep your pinned SHAs current [6][11][8]. These tools are capable of parsing the version tag in your comments and will open pull requests to bump the SHA when a new version is released [6][10][8]. 4. Enforce Policies: Use GitHub’s organization or repository-level security policies to require full-length commit SHA pinning [1][2][7]. When this policy is enabled, any workflow attempting to use a tag or branch reference will fail, preventing accidental or intentional deviations from your security standards [2][4][7]. While tag pinning is more convenient and widely used, it is recommended only if you explicitly trust the action's creators and are aware of the risks associated with mutable references [1]. In contrast, SHA pinning is widely considered the industry standard for production-grade security, as it effectively closes the window for malicious actors to swap code out from under your workflows [6][4][10].
Citations:
- 1: https://docs.github.com/en/actions/reference/security/secure-use
- 2: https://github.blog/changelog/2025-08-15-github-actions-policy-now-supports-blocking-and-sha-pinning-actions/
- 3: https://codeql.github.com/codeql-query-help/actions/actions-unpinned-tag/
- 4: https://www.romainlespinasse.dev/posts/github-actions-commit-sha-pinning/
- 5: https://docs.ozarksecuritylabs.com/supply-chain/tier-1-baseline/sha-pin-actions/
- 6: https://safeguard.sh/resources/blog/github-actions-pinning-sha-vs-tag
- 7: https://mikael.barbero.tech/blog/post/2026-03-24-stop-trusting-mutable-references/
- 8: https://emmer.dev/blog/pin-your-github-actions-to-protect-against-mutability/
- 9: https://docs.github.com/en/actions/how-tos/create-and-publish-actions/manage-custom-actions
- 10: https://nearform.com/insights/why-you-should-pin-your-github-actions-by-commit-hash/
- 11: https://safeguard.sh/resources/blog/how-to-pin-github-actions-to-shas-correctly
Pin GitHub Actions to full commit SHAs.
These uses: references are tag-pinned (@v4) instead of SHA-pinned. Tags are mutable and can be retargeted to malicious code; use full-length commit SHAs to ensure immutability and protect against supply-chain attacks. Include a comment with the version tag for reference (e.g., uses: actions/checkout@a824008085750b8e136effc585c3cd6082bd575f # v4.2.2).
Also applies to: 47-51
🧰 Tools
🪛 zizmor (1.25.2)
[warning] 17-17: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 17-17: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 19-19: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 21-21: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 21-21: runtime artifacts potentially vulnerable to a cache poisoning attack (cache-poisoning): this step
(cache-poisoning)
🤖 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/release.yml around lines 17 - 21, Replace all tag-pinned
GitHub Actions references in the release.yml workflow with full commit SHAs for
security. For each action using `@v4` format (actions/checkout@v4,
pnpm/action-setup@v4, actions/setup-node@v4, and any others in lines 47-51),
replace the tag with the corresponding full-length commit SHA and add an inline
comment with the version tag for reference. This prevents tag mutation attacks
by pinning to immutable commit hashes.
Source: Linters/SAST tools
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
Extract shared type check + build + test into check.yml (workflow_call). app-ci.yml now calls check.yml + runs OS/Node matrix for compatibility. release.yml: - Calls the same check.yml (identical gate as app-ci) - Validates version tag (semver + matches package.json) - Uploads dist/index.mjs as release asset - Dry-run before publish
- Disable noUncheckedIndexedAccess (codebase not compatible) - Create tsconfig.check.json excluding test files - Add BindParams to sql.js import in db.ts - Remove conflicting GetLlmUsageOptions import - Fix Cycle import path (types.ts, not db.ts) - Cast flags.cycle to Cycle type in commands.ts - Parse edit command id as number - Add missing minCost field to GetLlmUsageOptions
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 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/check.yml:
- Around line 10-14: Replace the mutable version tags (`@v4`) for the three
actions (actions/checkout, pnpm/action-setup, and actions/setup-node) with
immutable commit SHAs to reduce supply-chain risk. Additionally, add
persist-credentials: false to the actions/checkout configuration to disable
default credential persistence since the workflow only performs read-only
operations. Finally, add a permissions block at the top level of the workflow
(after the name field) with minimal read-only permissions to further harden
token access.
In @.github/workflows/codeql.yml:
- Around line 23-29: The GitHub Actions references in the workflow are using
version tags (`@v4` and `@v3`) which are mutable and vulnerable to tag retargeting
attacks. Replace each of the three uses directives for actions/checkout,
github/codeql-action/init, and github/codeql-action/analyze with their
full-length commit SHAs instead of the tag references. Look up the commit SHA
for each action version and replace the `@vX` references with @<full-commit-sha>
to ensure workflow integrity and security.
In @.github/workflows/dependency-review.yml:
- Around line 14-15: The actions/checkout@v4 and
actions/dependency-review-action@v4 are using mutable version tags that present
a supply-chain security risk. Replace the version tags (v4) with full
40-character commit SHAs for both actions. Include the original version tag as
an inline comment next to each action for readability and maintainability. After
making these changes, consider setting up Dependabot or Renovate to
automatically keep these commit SHAs updated when new versions are released.
In @.github/workflows/labeler.yml:
- Line 15: The actions/labeler action on line 15 is using a mutable tag (`@v5`)
which creates a security risk through potential upstream tag retargeting.
Replace the tag reference with a full commit SHA to pin the action to a specific
immutable version. Change the uses line from actions/labeler@v5 to
actions/labeler@<full-commit-sha> where the commit SHA corresponds to the
desired release version, ensuring the workflow uses a fixed version that cannot
be altered upstream.
In @.github/workflows/release.yml:
- Around line 44-45: The semver validation regex pattern for TAG_VERSION on line
44 only checks for a prefix match using ^[0-9]+\.[0-9]+\.[0-9]+ which allows
invalid suffixes like "-malicious" to pass validation. This creates a security
risk because the validated TAG_VERSION is later injected into a node -e command
at lines 61-65, enabling potential code injection. Tighten the regex pattern by
adding a $ anchor at the end to match the complete string, ensuring only valid
full semver versions (with no suffix) pass validation before being used in the
node command.
In @.github/workflows/renovate-approve.yml:
- Line 16: The `actions/github-script@v7` uses a mutable version tag that can
change between workflow runs, creating supply-chain drift risk. Replace the
`@v7` tag with a specific commit SHA (in the format `@<commit-sha>`) to pin the
action to a fixed version and prevent unintended updates.
In @.github/workflows/scheduled-ci.yml:
- Line 21: The pnpm install command in the scheduled-ci.yml workflow is missing
the --frozen-lockfile flag, which other CI workflows in the repository already
use. Add the --frozen-lockfile flag to the pnpm install command to ensure
dependency graph consistency and improve reproducibility of scheduled checks,
matching the pattern used in release.yml, check.yml, app-ci.yml, and pages.yml.
- Around line 12-16: Replace the mutable version tag references (`@v4`) for all
GitHub actions in the workflow file with immutable full-length commit SHAs.
Specifically, update the three action references: actions/checkout@v4,
pnpm/action-setup@v4, and actions/setup-node@v4 by replacing their version tags
with their corresponding commit SHAs. This prevents unexpected updates and
mitigates supply-chain security risks by pinning to specific, immutable commits
rather than mutable tags.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: e51a7a1e-6ff6-4b91-84e8-c31caf37fb92
📒 Files selected for processing (15)
.github/labeler.yml.github/workflows/app-ci.yml.github/workflows/check.yml.github/workflows/codeql.yml.github/workflows/dependency-review.yml.github/workflows/labeler.yml.github/workflows/release.yml.github/workflows/renovate-approve.yml.github/workflows/scheduled-ci.ymlsubtrack/package.jsonsubtrack/src/commands.tssubtrack/src/db.tssubtrack/src/index.tssubtrack/tsconfig.check.jsonsubtrack/tsconfig.json
💤 Files with no reviewable changes (1)
- subtrack/tsconfig.json
✅ Files skipped from review due to trivial changes (2)
- subtrack/tsconfig.check.json
- subtrack/src/commands.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- subtrack/package.json
| - uses: actions/checkout@v4 | ||
|
|
||
| - uses: pnpm/action-setup@v4 | ||
|
|
||
| - uses: actions/setup-node@v4 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n .github/workflows/check.ymlRepository: nazozokc/subtrack
Length of output: 695
🏁 Script executed:
# Check the file size first to avoid reading truncated output
wc -l .github/workflows/check.ymlRepository: nazozokc/subtrack
Length of output: 92
🌐 Web query:
GitHub Actions security best practices tag vs SHA pinning immutable reference
💡 Result:
For GitHub Actions, pinning to a full-length commit SHA is the recommended security best practice, whereas using tags (e.g., v4) is considered a mutable, less secure reference [1][2][3]. Why SHA Pinning is the Security Standard: - Immutability: Git tags can be moved, deleted, or recreated to point to different commits [4][5]. If a repository is compromised, an attacker can update an existing tag to point to malicious code, and your workflows will automatically run that new code without any changes to your workflow file [4][6][5]. - Protection against Retargeting: Pinning to a full-length commit SHA (e.g., @a1b2c3d4...) ensures your workflow always executes the exact, immutable code you originally reviewed and trusted, regardless of what happens to tags or branches in the upstream repository [7][4][5]. - Policy Enforcement: GitHub supports organization and repository-level policies that mandate SHA pinning [1][8][4]. When enforced, these policies cause workflows to fail if they use tags or branches, forcing adherence to immutable references [4][2]. Best Practices for Managing Pins: - Use Automation Tools: Manually updating SHAs is inefficient. Tools like Renovate or Dependabot can be configured to automatically open pull requests that bump SHAs while keeping a human-readable version tag in a comment (e.g., uses: owner/action@a1b2c3d4... # v4.2.0) [7][6]. Other tools like pinact can also automate the initial conversion of existing workflows to SHA-pinned references [2]. - Maintain Human-Readable Context: Always include the original tag or version in a trailing comment within the workflow file [7][6]. This allows automated tools to correlate the pinned SHA back to a semantic version for easier tracking [7]. - Consider the Full Dependency Tree: Remember that pinning a top-level action does not protect against "nested" dependencies [2]. Some actions may internally execute other actions, scripts, or Docker images that are not pinned [2]. - Beyond Pinning: While SHA pinning prevents tag-retargeting attacks, it does not protect against malicious code that is already present at the chosen SHA [7][6]. Always vet the actions you use and consider using GitHub’s policy features to explicitly allow or block specific actions across your organization [8][2][6]. As of 2026, GitHub is continuing to evolve its security roadmap to make workflows more deterministic, including plans to introduce a native dependencies section in workflow YAML to lock both direct and transitive dependencies [9].
Citations:
- 1: https://docs.github.com/en/actions/reference/security/secure-use
- 2: https://mikael.barbero.tech/blog/post/2026-03-24-stop-trusting-mutable-references/
- 3: https://github.com/github/docs/blob/962a1c8dccb8c0f66548b324e5b921b5e4fbc3d6/content/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions.md
- 4: https://www.romainlespinasse.dev/posts/github-actions-commit-sha-pinning/
- 5: https://nearform.com/insights/why-you-should-pin-your-github-actions-by-commit-hash/
- 6: https://emmer.dev/blog/pin-your-github-actions-to-protect-against-mutability/
- 7: https://safeguard.sh/resources/blog/github-actions-pinning-sha-vs-tag
- 8: https://github.blog/changelog/2025-08-15-github-actions-policy-now-supports-blocking-and-sha-pinning-actions/
- 9: https://github.blog/news-insights/product-news/whats-coming-to-our-github-actions-2026-security-roadmap/
🌐 Web query:
GitHub Actions checkout persist-credentials security implications
💡 Result:
The persist-credentials setting in the GitHub Actions checkout action controls whether the authentication token (typically GITHUB_TOKEN) used for the checkout process is stored in the runner's local Git configuration [1][2]. By default, this is set to true [1][3]. Security Implications: - Credential Exposure: When enabled (the default), the token is persisted in the environment, making it potentially accessible to subsequent steps or third-party actions within the same workflow [3][4]. If a workflow creates and uploads build artifacts that include the repository directory (e.g., using actions/upload-artifact), there is a risk that these credentials could be inadvertently leaked if not properly excluded [4]. - Improved Security Mechanisms: Recent versions of the checkout action have improved credential security by storing tokens in a separate file under $RUNNER_TEMP rather than directly in.git/config [1][5]. While this reduces the risk of direct leakage through basic file operations, the underlying credential remains accessible to processes running within the job [1][6]. - Best Practices: Security guidance, including the OWASP GitHub Actions Security Cheat Sheet, recommends setting persist-credentials: false explicitly unless the workflow specifically requires the ability to perform authenticated Git operations (like git push) back to the repository [7][3]. If push access is needed, ensure the GITHUB_TOKEN has the minimum required permissions, and avoid relying on persistence if those operations can be performed via other authorized means [3]. For most workflows that only need to download code, disabling this setting is a recommended hardening step to adhere to the principle of least privilege [7][3].
Citations:
- 1: https://github.com/actions/checkout/blob/main/README.md
- 2: https://github.com/actions/checkout/?tab=readme-ov-file
- 3: https://actsense.dev/vulnerabilities/unsafe_checkout/
- 4: https://yossarian.net/til/post/actions-checkout-can-leak-github-credentials/
- 5: https://github.com/marketplace/actions/checkout
- 6: [security] Escalate concerning default
persist-credentials=trueplease actions/checkout#2312 - 7: https://cheatsheetseries.owasp.org/cheatsheets/GitHub_Actions_Security_Cheat_Sheet.html
Harden action execution and token handling in CI.
Lines 10, 12, and 14 use mutable tag pins (@v4) instead of immutable commit SHAs, increasing supply-chain risk. Line 10's checkout action persists credentials by default and should explicitly disable this since the workflow only reads code. Add an explicit minimal permissions block scoped to read-only.
Suggested patch
+permissions:
+ contents: read
+
jobs:
check:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0 # v4
+ with:
+ persist-credentials: false
- - uses: pnpm/action-setup@v4
+ - uses: pnpm/action-setup@c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0 # v4
- - uses: actions/setup-node@v4
+ - uses: actions/setup-node@b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0 # v4🧰 Tools
🪛 zizmor (1.25.2)
[warning] 10-10: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 10-10: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 12-12: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 14-14: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🤖 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/check.yml around lines 10 - 14, Replace the mutable
version tags (`@v4`) for the three actions (actions/checkout, pnpm/action-setup,
and actions/setup-node) with immutable commit SHAs to reduce supply-chain risk.
Additionally, add persist-credentials: false to the actions/checkout
configuration to disable default credential persistence since the workflow only
performs read-only operations. Finally, add a permissions block at the top level
of the workflow (after the name field) with minimal read-only permissions to
further harden token access.
Source: Linters/SAST tools
| - uses: actions/checkout@v4 | ||
|
|
||
| - uses: github/codeql-action/init@v3 | ||
| with: | ||
| languages: ${{ matrix.language }} | ||
|
|
||
| - uses: github/codeql-action/analyze@v3 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify unpinned actions across workflows
rg -nP '^\s*-\s*uses:\s*[^@]+@(?![0-9a-f]{40}$)[^ \n]+' .github/workflowsRepository: nazozokc/subtrack
Length of output: 1836
🏁 Script executed:
#!/bin/bash
# Check for security policy or pinning requirements
find . -maxdepth 2 -type f \( -name "*SECURITY*" -o -name "*POLICY*" -o -name "*security*" -o -name "*policy*" \) 2>/dev/null | head -20Repository: nazozokc/subtrack
Length of output: 43
🏁 Script executed:
#!/bin/bash
# Check codeql.yml file content to see exact state
cat -n .github/workflows/codeql.ymlRepository: nazozokc/subtrack
Length of output: 772
🌐 Web query:
GitHub Actions best practices pinning commit SHA security risk tag retargeting
💡 Result:
The primary security risk of using tags or branch names (e.g., @v4, @main) to reference GitHub Actions is that these references are mutable [1][2][3]. Because a tag in Git is simply a movable pointer, an attacker who compromises an action's repository can retarget that tag to point to a malicious commit [4][5][6]. Downstream users who reference the action via that tag will then automatically pull and execute the malicious code without any changes to their own workflow files, as the resolution happens at runtime [5][7][6]. This "tag retargeting" or "tag poisoning" attack has been observed in several real-world incidents, including compromises affecting tj-actions (2025), xygeni-action (2026), and actions-cool (2026) [8][5][6][9]. Best Practices and Mitigation: 1. Pin to Full Commit SHAs: The only way to ensure an action is immutable is to reference it by its full-length (40-character) commit SHA [1][10]. This guarantees the exact code is executed every time, regardless of what happens to the tags in the source repository [2][8][11]. 2. Enforce via Organization Policy: Administrators can enable an organization-level policy in GitHub that mandates SHA pinning [12]. When active, any workflow attempting to use a non-pinned action will fail, effectively preventing the use of mutable references across the organization [12][2]. 3. Automate Maintenance: To manage the maintenance overhead of SHA pinning, use tools like Renovate or Dependabot [12][8][4]. For instance, Renovate offers presets (e.g., helpers:pinGitHubActionDigests) that automatically keep commit SHAs updated while allowing you to include the corresponding version tag as a comment for readability [8][4]. 4. Audit Sub-actions: Be aware that some actions internally reference other actions [2]. If you maintain an action, you should pin those internal references to full SHAs as well, as your users may have enforced organization-wide policies that will cause tag-based sub-references to fail [2]. 5. Defense in Depth: SHA pinning is a critical hardening step but should be part of a broader strategy. Continue to follow the principle of least privilege by limiting the secrets and permissions granted to workflows, and monitor for unexpected changes in runner behavior, as pinning does not protect against a malicious commit that you intentionally (but mistakenly) choose to pin [11][10][3].
Citations:
- 1: https://docs.github.com/en/actions/reference/security/secure-use
- 2: https://www.romainlespinasse.dev/posts/github-actions-commit-sha-pinning/
- 3: https://samsond.github.io/posts/why-tags-fail/
- 4: https://emmer.dev/blog/pin-your-github-actions-to-protect-against-mutability/
- 5: https://safeguard.sh/resources/blog/github-action-tag-redirect-imposter-commit-may-2026
- 6: https://lorikeetsecurity.com/blog/github-supply-chain-attack-tj-actions
- 7: https://sebastion.dev/intelligence/2026-03-12-poc-supply-chain-compromise-via-mutable-git-tag-poisoning
- 8: https://architecture.lullabot.com/adr/20260505-pin-github-actions-to-hash/
- 9: https://www.sentinelone.com/vulnerability-database/cve-2026-31976/
- 10: https://mikael.barbero.tech/blog/post/2026-03-24-stop-trusting-mutable-references/
- 11: https://safeguard.sh/resources/blog/github-actions-pinning-sha-vs-tag
- 12: https://github.blog/changelog/2025-08-15-github-actions-policy-now-supports-blocking-and-sha-pinning-actions/
Pin all GitHub Actions to immutable commit SHAs.
These uses: references are tag-pinned only (@v4/@v3), which leaves the workflow open to upstream tag retargeting attacks. Best practice requires pinning to full-length commit SHAs.
Suggested hardening
- - uses: actions/checkout@v4
+ - uses: actions/checkout@<full-length-commit-sha> # v4
- - uses: github/codeql-action/init@v3
+ - uses: github/codeql-action/init@<full-length-commit-sha> # v3
- - uses: github/codeql-action/analyze@v3
+ - uses: github/codeql-action/analyze@<full-length-commit-sha> # v3🧰 Tools
🪛 zizmor (1.25.2)
[warning] 23-23: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 23-23: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 25-25: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 29-29: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🤖 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/codeql.yml around lines 23 - 29, The GitHub Actions
references in the workflow are using version tags (`@v4` and `@v3`) which are
mutable and vulnerable to tag retargeting attacks. Replace each of the three
uses directives for actions/checkout, github/codeql-action/init, and
github/codeql-action/analyze with their full-length commit SHAs instead of the
tag references. Look up the commit SHA for each action version and replace the
`@vX` references with @<full-commit-sha> to ensure workflow integrity and
security.
Source: Linters/SAST tools
| - uses: actions/checkout@v4 | ||
| - uses: actions/dependency-review-action@v4 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, examine the actual workflow file to confirm current state
cat -n .github/workflows/dependency-review.yml | head -20Repository: nazozokc/subtrack
Length of output: 463
🌐 Web query:
GitHub Actions security best practices pinning actions by commit SHA
💡 Result:
Pinning GitHub Actions to a full-length commit SHA is a critical security best practice designed to mitigate supply chain risks by ensuring that the code executed in your workflows is immutable [1][2][3]. Why Pin to a Commit SHA Unlike version tags (e.g., @v4) or branch names (e.g., @main), which are mutable and can be updated by maintainers or malicious actors to point to different code at any time, a full-length commit SHA is content-addressed and immutable [4][5][3]. If a repository is compromised, an attacker can move an existing tag to point to malicious code, causing every workflow using that tag to automatically execute the attacker's changes [6][2]. Pinning to a SHA prevents this, as the workflow will continue to use the specific, verified commit regardless of any changes made to tags in the upstream repository [1][4]. Implementation Best Practices To maintain security while minimizing maintenance overhead, use the following approach: 1. Use Full SHAs: Always use the full 40-character commit SHA, not the short version, to ensure uniqueness and security [1][5]. 2. Include Human-Readable Comments: When pinning an action, include the version tag in a trailing comment [2][5]. This makes the workflow file readable and allows automated tools to identify which version the SHA corresponds to [2][3]. Example: - uses: actions/checkout@3df4ab1 # v4.0.0 3. Automate Updates: Use dependency management tools like Dependabot or Renovate to keep your pinned SHAs up to date [4][6][2]. These tools can be configured to automatically open pull requests when new versions of the action are released, ensuring you benefit from security patches without sacrificing the safety of pinned dependencies [6][2]. Organizational Policy GitHub now supports organization-level policies that mandate SHA pinning [7][4][2]. Administrators can enforce this requirement in the allowed actions policy; if enabled, any workflow attempting to use a tag or branch reference for an action will fail [7][4]. It is recommended to enable this policy to proactively secure your CI/CD environment [7][2]. Note for Action Maintainers If you maintain your own GitHub Actions, you should also pin any sub-actions or dependencies you reference internally to full commit SHAs [4]. This ensures that your action remains compatible with organizations that enforce strict SHA pinning policies [4]. Top Results: [1][7][4][6][2]
Citations:
- 1: https://docs.github.com/en/actions/reference/security/secure-use
- 2: https://architecture.lullabot.com/adr/20260505-pin-github-actions-to-hash/
- 3: https://nearform.com/insights/why-you-should-pin-your-github-actions-by-commit-hash/
- 4: https://www.romainlespinasse.dev/posts/github-actions-commit-sha-pinning/
- 5: https://safeguard.sh/resources/blog/how-to-pin-github-actions-to-shas-correctly
- 6: https://emmer.dev/blog/pin-your-github-actions-to-protect-against-mutability/
- 7: https://github.blog/changelog/2025-08-15-github-actions-policy-now-supports-blocking-and-sha-pinning-actions/
🌐 Web query:
actions/checkout v4 recommended pinning practice GitHub security
💡 Result:
The recommended security practice for using actions/checkout (and all third-party GitHub Actions) is to pin them to a full-length, 40-character commit SHA rather than a version tag (e.g., @v4) or branch name [1][2][3]. Why Pin to a Commit SHA: Tags and branches are mutable references in Git, meaning they can be deleted, moved, or updated to point to different code at any time [4][5][6]. If an attacker compromises the action's repository or the maintainer's account, they could modify an existing tag to include malicious code, which would then automatically run in any workflow using that tag [5][7][3]. Pinning to an immutable, full-length commit SHA ensures that your workflow always executes the exact same code, mitigating the risk of supply chain attacks [1][8][6]. Recommended Implementation: To maintain both security and readability, use the commit SHA in your workflow configuration and include the version tag as an inline comment [4][6][3]. This allows you to benefit from immutability while still knowing which version is being used [5][8]. Example: - uses: actions/checkout@692973e # v4.1.7 Maintenance: Because pinned SHAs do not update automatically, they require maintenance to stay current [9][6]. It is highly recommended to use automated dependency management tools like Dependabot or Renovate [10][6][3]. These tools can be configured to monitor the action's repository and open pull requests to update your SHAs whenever a new tagged version is released, ensuring you receive security patches and feature updates while maintaining control over the upgrade process [9][6]. Organizational Policy: GitHub allows administrators to enforce this practice at the organization or repository level [1][11]. When such a policy is enabled, any workflow that references an action by a mutable tag will fail, requiring all actions (including nested dependencies) to be pinned to full commit SHAs [11]. Top Results: [1], [2], [6], [3]
Citations:
- 1: https://docs.github.com/en/actions/reference/security/secure-use
- 2: https://github.com/github/docs/blob/962a1c8dccb8c0f66548b324e5b921b5e4fbc3d6/content/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions.md
- 3: https://www.decryptiondigest.com/blog/github-actions-security-hardening
- 4: https://spin.atomicobject.com/github-actions-risk/
- 5: https://carlosbecker.com/posts/pinning-github-actions/
- 6: https://architecture.lullabot.com/adr/20260505-pin-github-actions-to-hash/
- 7: https://actsense.dev/vulnerabilities/no_hash_pinning/
- 8: https://www.stepsecurity.io/blog/pinning-github-actions-for-enhanced-security-a-complete-guide
- 9: https://docs.ozarksecuritylabs.com/supply-chain/tier-1-baseline/sha-pin-actions/
- 10: http://jonasbn.github.io/til/github_actions/pin_your_action_dependencies.html
- 11: https://www.romainlespinasse.dev/posts/github-actions-commit-sha-pinning/
Pin workflow actions to full commit SHAs instead of version tags.
The actions actions/checkout@v4 and actions/dependency-review-action@v4 use mutable version tags that can be compromised. Pinning to full 40-character commit SHAs ensures supply-chain integrity by preventing tag-hijacking attacks. Include the version tag as an inline comment for readability and use Dependabot or Renovate to keep SHAs updated automatically.
Suggested hardening
- - uses: actions/checkout@v4
+ - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- - uses: actions/dependency-review-action@v4
+ - uses: actions/dependency-review-action@c9b6f9d9f36f5e5c5e5c5e5c5e5c5e5c5e5c5e5c # v4.1.0🧰 Tools
🪛 zizmor (1.25.2)
[warning] 14-14: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 14-14: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 15-15: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🤖 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/dependency-review.yml around lines 14 - 15, The
actions/checkout@v4 and actions/dependency-review-action@v4 are using mutable
version tags that present a supply-chain security risk. Replace the version tags
(v4) with full 40-character commit SHAs for both actions. Include the original
version tag as an inline comment next to each action for readability and
maintainability. After making these changes, consider setting up Dependabot or
Renovate to automatically keep these commit SHAs updated when new versions are
released.
Source: Linters/SAST tools
| label: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/labeler@v5 |
There was a problem hiding this comment.
Pin GitHub Action to a commit SHA
Line 15 uses a mutable tag (@v5). Pin to a full commit SHA to prevent upstream tag retargeting/supply-chain drift.
Suggested hardening
- - uses: actions/labeler@v5
+ - uses: actions/labeler@<full-length-commit-sha>🧰 Tools
🪛 zizmor (1.25.2)
[error] 15-15: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🤖 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/labeler.yml at line 15, The actions/labeler action on line
15 is using a mutable tag (`@v5`) which creates a security risk through potential
upstream tag retargeting. Replace the tag reference with a full commit SHA to
pin the action to a specific immutable version. Change the uses line from
actions/labeler@v5 to actions/labeler@<full-commit-sha> where the commit SHA
corresponds to the desired release version, ensuring the workflow uses a fixed
version that cannot be altered upstream.
Source: Linters/SAST tools
| if ! echo "$TAG_VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+'; then | ||
| echo "❌ Invalid semver: $TAG_VERSION" |
There was a problem hiding this comment.
Tighten tag validation before injecting into node -e source.
Line 44 accepts prefixed matches only, so a crafted suffix can pass validation and be injected at Line 64. Validate the full string and avoid inline JS template injection.
Suggested patch
- if ! echo "$TAG_VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+'; then
+ if ! echo "$TAG_VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "❌ Invalid semver: $TAG_VERSION"
exit 1
fi
@@
- node -e "
- const fs = require('fs')
- const pkg = require('./package.json')
- pkg.version = '${{ steps.version.outputs.version }}'
- fs.writeFileSync('./package.json', JSON.stringify(pkg, null, 2) + '\n')
- "
+ VERSION='${{ steps.version.outputs.version }}' node -e "
+ const fs = require('node:fs')
+ const pkg = JSON.parse(fs.readFileSync('./package.json', 'utf8'))
+ pkg.version = process.env.VERSION
+ fs.writeFileSync('./package.json', JSON.stringify(pkg, null, 2) + '\n')
+ "Also applies to: 61-65
🤖 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/release.yml around lines 44 - 45, The semver validation
regex pattern for TAG_VERSION on line 44 only checks for a prefix match using
^[0-9]+\.[0-9]+\.[0-9]+ which allows invalid suffixes like "-malicious" to pass
validation. This creates a security risk because the validated TAG_VERSION is
later injected into a node -e command at lines 61-65, enabling potential code
injection. Tighten the regex pattern by adding a $ anchor at the end to match
the complete string, ensuring only valid full semver versions (with no suffix)
pass validation before being used in the node command.
Source: Linters/SAST tools
| runs-on: ubuntu-latest | ||
| if: github.actor == 'renovate[bot]' | ||
| steps: | ||
| - uses: actions/github-script@v7 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n .github/workflows/renovate-approve.yml | head -20Repository: nazozokc/subtrack
Length of output: 608
🏁 Script executed:
rg "actions/github-script" -A 2 -B 2Repository: nazozokc/subtrack
Length of output: 43
🏁 Script executed:
find . -type f \( -name "SECURITY.md" -o -name ".github/settings.yml" -o -name ".github/workflows/*" \) | head -20Repository: nazozokc/subtrack
Length of output: 43
🏁 Script executed:
rg "actions/" .github/workflows/ --no-filename | grep "uses:" | sort -uRepository: nazozokc/subtrack
Length of output: 379
Pin actions/github-script to a commit SHA.
The action uses @v7, a mutable tag that can change between workflow runs. Pin to a specific commit SHA to prevent unintended updates and reduce supply-chain drift risk.
Suggested hardening
- - uses: actions/github-script@v7
+ - uses: actions/github-script@<full-length-commit-sha> # v7🧰 Tools
🪛 zizmor (1.25.2)
[error] 16-16: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🤖 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/renovate-approve.yml at line 16, The
`actions/github-script@v7` uses a mutable version tag that can change between
workflow runs, creating supply-chain drift risk. Replace the `@v7` tag with a
specific commit SHA (in the format `@<commit-sha>`) to pin the action to a fixed
version and prevent unintended updates.
Source: Linters/SAST tools
| - uses: actions/checkout@v4 | ||
|
|
||
| - uses: pnpm/action-setup@v4 | ||
|
|
||
| - uses: actions/setup-node@v4 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's find and examine the scheduled-ci.yml workflow
find . -name "scheduled-ci.yml" -o -name "*.yml" -path "*/.github/workflows/*" | head -20Repository: nazozokc/subtrack
Length of output: 367
🏁 Script executed:
# Let's read the full scheduled-ci.yml file
cat -n .github/workflows/scheduled-ci.ymlRepository: nazozokc/subtrack
Length of output: 737
🏁 Script executed:
# Check if there are other workflows to understand the pattern
ls -la .github/workflows/Repository: nazozokc/subtrack
Length of output: 740
🏁 Script executed:
# Check a few other workflows to see the pattern used across the repository
cat -n .github/workflows/app-ci.yml | head -30Repository: nazozokc/subtrack
Length of output: 863
🏁 Script executed:
# Check the release workflow as well
cat -n .github/workflows/release.yml | head -40Repository: nazozokc/subtrack
Length of output: 1154
🏁 Script executed:
# Check dependency-review and codeql to see if there's any pinning pattern
cat -n .github/workflows/dependency-review.ymlRepository: nazozokc/subtrack
Length of output: 463
🏁 Script executed:
# Check codeql
cat -n .github/workflows/codeql.ymlRepository: nazozokc/subtrack
Length of output: 772
Pin all action dependencies to immutable commit SHAs for supply-chain hardening.
This workflow currently uses mutable tag refs (@v4, @v3) for all actions. Pinning to full-length commit SHAs is the recommended approach to prevent unexpected updates and mitigate the risk of malicious action modifications.
Note: This pattern is used consistently across the repository; consider applying this change repository-wide.
🧰 Tools
🪛 zizmor (1.25.2)
[warning] 12-12: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 12-12: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 14-14: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 16-16: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🤖 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/scheduled-ci.yml around lines 12 - 16, Replace the mutable
version tag references (`@v4`) for all GitHub actions in the workflow file with
immutable full-length commit SHAs. Specifically, update the three action
references: actions/checkout@v4, pnpm/action-setup@v4, and actions/setup-node@v4
by replacing their version tags with their corresponding commit SHAs. This
prevents unexpected updates and mitigates supply-chain security risks by pinning
to specific, immutable commits rather than mutable tags.
Source: Linters/SAST tools
| node-version: 22 | ||
| cache: pnpm | ||
|
|
||
| - run: pnpm install |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Check if the file exists and examine its contents
cat -n .github/workflows/scheduled-ci.ymlRepository: nazozokc/subtrack
Length of output: 737
🏁 Script executed:
# Search for other pnpm install usages in CI/workflow files
rg "pnpm install" .github/workflows/ -nRepository: nazozokc/subtrack
Length of output: 428
🏁 Script executed:
# Check if there's a pnpm-lock.yaml or lockfile in the repo
fd -e lock.yaml | head -20Repository: nazozokc/subtrack
Length of output: 43
Use frozen lockfile mode in CI installs.
pnpm install without --frozen-lockfile allows dependency graph drift during CI, reducing reproducibility of scheduled checks. All other CI workflows in this repository (release.yml, check.yml, app-ci.yml, pages.yml) already use this flag.
Suggested fix
- - run: pnpm install
+ - run: pnpm install --frozen-lockfile📝 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.
| - run: pnpm install | |
| - run: pnpm install --frozen-lockfile |
🤖 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/scheduled-ci.yml at line 21, The pnpm install command in
the scheduled-ci.yml workflow is missing the --frozen-lockfile flag, which other
CI workflows in the repository already use. Add the --frozen-lockfile flag to
the pnpm install command to ensure dependency graph consistency and improve
reproducibility of scheduled checks, matching the pattern used in release.yml,
check.yml, app-ci.yml, and pages.yml.
Remove separate tsconfig.check.json and add exclude directly to main tsconfig. The separate config file caused CI failure (extends resolution issue on some Node versions).
CI type check failed because @types/node was not in lockfile. tsconfig.json has 'types: ["node"]' which requires the package to be present.
release.yml: - Allow publish job to run on workflow_dispatch (was gated to release only) - Gate version validation, tag setting, publish, and asset upload with appropriate conditions - Add persist-credentials: false to checkout check.yml: - Add permissions: contents: read - Add persist-credentials: false to checkout app-ci.yml: - Run spell check only once per matrix (node-version == 22)
Summary
Redesigned CI pipeline. The main focus is the release workflow which previously had no quality gates before publish. Also cleaned up the app-ci matrix and added type checking everywhere.
Changes
release.yml(major improvement)release: publishedworkflow_dispatchwith dry-run option--dry-runbefore actual publish--no-git-checksunexplainedapp-ci.yml(cleaned up)tsc --noEmit) before buildsetup-nodecache instead of manual cache steps.agents/,.claude/subtrack/package.jsonlint:typesscript (tsc --noEmit) for local useCommits
108e25bdocs: update AGENTS.md and CLAUDE.md with accurate project infoa768b8dci: strengthen CI workflows with type checking and release safeguardsSummary by CodeRabbit
pnpm lint:types/tsc --noEmit) to CI and scheduled checks