Skip to content
Open
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
78 changes: 78 additions & 0 deletions .github/workflows/node-suite-guard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Node Suite Regression Guard

# Wires scripts/node_suite_regression_check.py (roadmap I-02) into CI. That
# guard runs the full print-and-diff node-suite and FAILS if any baselined
# module's pass count drops below its floor (test-parity/node_suite_baseline.json,
# oracle node 26). It was written verbatim because node:dns once silently went
# 83% -> 0% behind a green build, yet until now it ran in ZERO workflows.
#
# Decoupled from the (not-yet-enabled) merge queue on purpose: it runs nightly
# and on demand today, and the `merge_group` trigger below is INERT until a
# maintainer turns the merge queue on in branch protection — at which point this
# guard automatically gates every merge with no further workflow change.
on:
workflow_dispatch:
schedule:
# Nightly, offset from the Node Core Subset Radar (17 3) to avoid overlap.
- cron: "37 4 * * *"
# Inert until the merge queue is enabled in branch protection; then this guard
# runs once per merge against the actual merged tree.
merge_group:

permissions:
contents: read

concurrency:
group: node-suite-guard-${{ github.ref }}
cancel-in-progress: false

env:
RUSTC_WRAPPER: sccache
SCCACHE_GHA_ENABLED: "true"
SCCACHE_CACHE_SIZE: "2G"
CARGO_INCREMENTAL: "0"

jobs:
node-suite-guard:
runs-on: ubuntu-latest
timeout-minutes: 120
steps:
- uses: actions/checkout@v6

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 workflow actions are pinned to full SHAs (non-matching lines are violations).
rg -n --iglob '*.yml' --iglob '*.yaml' '^\s*uses:\s*[^@]+@[^[:space:]]+' .github/workflows \
  | rg -n -v '@[0-9a-fA-F]{40}$'

Repository: PerryTS/perry

Length of output: 6511


🏁 Script executed:

cat -n .github/workflows/node-suite-guard.yml | sed -n '35,60p'

Repository: PerryTS/perry

Length of output: 998


Pin all uses: actions to full commit SHAs.

Lines 40, 43, 46, 48, and 57 use movable tags that weaken workflow supply-chain guarantees and conflict with the stated unpinned-action policy.

Suggested hardening patch
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@<40-char-commit-sha>

-        uses: dtolnay/rust-toolchain@stable
+        uses: dtolnay/rust-toolchain@<40-char-commit-sha>

-        uses: mozilla-actions/sccache-action@v0.0.10
+        uses: mozilla-actions/sccache-action@<40-char-commit-sha>

-      - uses: Swatinem/rust-cache@v2
+      - uses: Swatinem/rust-cache@<40-char-commit-sha>

-        uses: actions/setup-node@v6
+        uses: actions/setup-node@<40-char-commit-sha>
🧰 Tools
🪛 zizmor (1.25.2)

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

(artipacked)


[error] 40-40: 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/node-suite-guard.yml at line 40, The workflow uses movable
action tags (such as `@v6`) in multiple `uses:` directives, which weakens supply
chain security guarantees. Replace each movable tag reference with a full commit
SHA to pin the exact version of each action. This applies to the
actions/checkout action and any other actions referenced with version tags
throughout the workflow file, ensuring reproducibility and security by pinning
to specific, immutable commit hashes instead of floating tags.

Source: Linters/SAST tools


⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/node-suite-guard.yml

Repository: PerryTS/perry

Length of output: 3335


🌐 Web query:

GitHub Actions checkout persist-credentials false security best practice

💡 Result:

Setting persist-credentials: false is a recommended security best practice for GitHub Actions workflows that do not require the ability to perform authenticated Git operations (such as pushing commits or tags) [1][2][3]. By default, the actions/checkout action sets persist-credentials to true, which configures the local Git repository with the authentication token (e.g., GITHUB_TOKEN) used to perform the checkout [4][5]. This makes the token accessible to any subsequent step or third-party action in the same job by reading the.git/config file [6][2][3]. Key security considerations: - Principle of Least Privilege: By setting persist-credentials: false, you prevent unnecessary exposure of your authentication token to subsequent workflow steps, reducing the risk of token theft if a step or dependency is compromised [2][3][7]. - When to use: You should set persist-credentials: false for any workflow that only performs read-only operations, such as running tests, building artifacts, or scanning code [3]. - When to avoid: You should only leave persist-credentials as true (or omit it) if your workflow explicitly requires the ability to run authenticated git commands like git push or git tag against the repository [1][2][3]. - Mitigation: Because the default is true, it must be explicitly set to false in your workflow YAML [2][7]: steps: - uses: actions/checkout@v4 with: persist-credentials: false While modern versions of actions/checkout have improved how credentials are stored (using a separate file in $RUNNER_TEMP rather than directly in.git/config in some cases), explicitly disabling persistence remains a standard security recommendation to minimize the attack surface [4][2][8].

Citations:


Add persist-credentials: false to the checkout action.

The workflow only performs read-only operations (building and testing). Explicitly disabling credential persistence follows the principle of least privilege and is a security best practice recommended by OWASP and security tooling for workflows that don't require authenticated Git operations.

Suggested hardening patch
-      - uses: actions/checkout@v6
+      - uses: actions/checkout@v6
+        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.

Suggested change
- uses: actions/checkout@v6
- uses: actions/checkout@v6
with:
persist-credentials: false
🧰 Tools
🪛 zizmor (1.25.2)

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

(artipacked)


[error] 40-40: 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/node-suite-guard.yml at line 40, The actions/checkout@v6
step in the workflow should explicitly disable credential persistence since the
workflow only performs read-only operations (building and testing) that do not
require authenticated Git operations. Add the persist-credentials property set
to false in the checkout action configuration to follow the principle of least
privilege and improve the security posture of the workflow.

Source: Linters/SAST tools

with:
# Read-only job (build + test); don't leave the GITHUB_TOKEN in the
# local git config (least privilege — OWASP / CodeRabbit).
persist-credentials: false

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable

- name: Start sccache
uses: mozilla-actions/sccache-action@v0.0.10

- uses: Swatinem/rust-cache@v2
with:
shared-key: "${{ runner.os }}-perry"
save-if: ${{ github.ref == 'refs/heads/main' }}

- name: Setup Node.js
# Node 26 is the oracle the node_suite_baseline.json floors were
# captured on; running any other major would compare against the
# wrong reference and produce spurious regressions.
uses: actions/setup-node@v6
with:
node-version: "26"

- name: Build Perry release binary
run: cargo build --release -p perry -p perry-runtime -p perry-stdlib

- name: Node-suite regression guard (floor baseline, node 26)
# Fails (exit 1) if any baselined module drops below its floor;
# improvements are accepted and reported as +N. pipefail propagates the
# script's exit through the tee into the step.
run: |
set -euo pipefail
echo '### Node-suite regression guard (node 26)' >> "$GITHUB_STEP_SUMMARY"
echo '```' >> "$GITHUB_STEP_SUMMARY"
python3 scripts/node_suite_regression_check.py target/release/perry . \
| tee -a "$GITHUB_STEP_SUMMARY"
echo '```' >> "$GITHUB_STEP_SUMMARY"
Loading