Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions .github/workflows/react-doctor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# React Doctor — finds security, performance, correctness, accessibility,
# bundle-size, and architecture issues in React codebases.
#
# Docs: https://www.react.doctor/ci
# Source: https://github.com/millionco/react-doctor

name: React Doctor

on:
# Scans the PR's changed files and posts a sticky summary comment listing only the new issues introduced relative to the merge base of the target branch.
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
# Scans `main` on every push to track the health-score trend and catch regressions that slipped past PR review.
push:
branches: ["main"]

permissions:
contents: read
pull-requests: write
issues: write
statuses: write

# Cancels any in-flight scan for the same PR (or branch, on push) the moment a new commit arrives, so reviewers only ever see the latest run.
concurrency:
group: react-doctor-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
react-doctor:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- uses: millionco/react-doctor@v2
Comment on lines +32 to +34

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify all workflow actions are SHA-pinned and checkout disables persisted credentials.

set -euo pipefail

echo "== Action references in workflows =="
rg -n '^\s*-\s*uses:\s*' .github/workflows || true

echo
echo "== Non-SHA-pinned actions (should be empty after fix) =="
rg -nP '^\s*-\s*uses:\s*[^@\s]+@(?![0-9a-fA-F]{40}\b)' .github/workflows || true

echo
echo "== checkout steps missing persist-credentials: false (should be empty after fix) =="
python - <<'PY'
from pathlib import Path
import re

for path in Path(".github/workflows").glob("*.y*ml"):
    text = path.read_text(encoding="utf-8")
    for m in re.finditer(r'(^\s*-\s*uses:\s*actions/checkout@[^\n]+\n(?:^\s+.*\n)*)', text, re.M):
        block = m.group(1)
        if "persist-credentials: false" not in block:
            line = text[:m.start()].count("\n") + 1
            print(f"{path}:{line}")
PY

Repository: ametel01/okf-dashboard

Length of output: 584


Pin third-party actions by commit SHA and disable credential persistence in checkout.

Lines 32–34 use mutable action tags (@v5, @v2), which creates supply-chain risk. Additionally, actions/checkout@v5 leaves credentials persisted by default, unnecessarily exposing the workflow token to later steps.

Suggested hardening patch
-      - uses: actions/checkout@v5
+      - uses: actions/checkout@<PINNED_SHA_FOR_V5>
+        with:
+          persist-credentials: false

-      - uses: millionco/react-doctor@v2
+      - uses: millionco/react-doctor@<PINNED_SHA_FOR_V2>
🧰 Tools
🪛 zizmor (1.25.2)

[warning] 32-32: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 32-32: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 34-34: 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/react-doctor.yml around lines 32 - 34, The GitHub Actions
workflow uses mutable action tags which creates supply-chain risk and leaves
credentials persisted in the checkout step. Replace the mutable tags `@v5` for
actions/checkout and `@v2` for millionco/react-doctor with pinned commit SHAs to
lock these dependencies to specific versions. Additionally, add
`persist-credentials: false` as a configuration option to the actions/checkout
action to disable credential persistence and prevent unnecessary exposure of the
workflow token to subsequent steps.

Source: Linters/SAST tools

# Advisory by default: React Doctor reports findings on every PR — a
# sticky summary comment, inline review comments, and a commit status
# with the health score — but never fails the check, so it won't red-X
# a teammate's PR on day one. When your team trusts the signal, graduate
# the gate: uncomment the block below and set blocking to "error" (fail
# on new error-severity findings) or "warning" (fail on any finding).
# Full reference: https://www.react.doctor/ci
# with:
# blocking: error # Gate level: "none" (advisory, the default) | "warning" | "error"
# scope: full # On PRs, scan the whole project instead of just changed files
# comment: false # Disable the sticky PR summary comment
# review-comments: false # Disable inline review comments on changed lines
# commit-status: false # Disable the commit status (score + counts, links to the run)
# version: "0.4.0" # Pin to a specific react-doctor version instead of "latest"
# directory: apps/web # Scan a sub-directory (default: ".")
# project: "web,admin" # In a monorepo, scan specific workspace project(s)