Skip to content
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
4693ef8
feat(js-pr-validation): add socket.dev supply chain gate
bedatty Aug 5, 2026
cfe360f
fix(js-pr-validation): enforce sfw inspection and purge package cache
bedatty Aug 5, 2026
f75d2fd
fix(js-pr-validation): pin the socketsecurity CLI release
bedatty Aug 5, 2026
ee22bc5
test(js-pr-validation): point socket composites at this branch
bedatty Aug 5, 2026
77b3ad2
feat(js-pr-validation): guard every install and gate on the Socket App
bedatty Aug 5, 2026
5b9ecc6
fix(js-pr-validation): set result-encoding on the socket reporter
bedatty Aug 5, 2026
54f3c4d
fix(js-pr-validation): grant checks:read and stop swallowing API errors
bedatty Aug 5, 2026
bb8ca83
feat(js-pr-validation): declare SOCKET_SECURITY_API_KEY as optional
bedatty Aug 5, 2026
cde744a
test(js-pr-validation): add temporary socket token reachability probe
bedatty Aug 5, 2026
7a33a1e
test(js-pr-validation): drop the socket token reachability probe
bedatty Aug 5, 2026
ef1c887
feat(js-pr-validation): report per-package Socket Firewall findings
bedatty Aug 5, 2026
a778bc2
feat(js-pr-validation): report per-package vulnerabilities via the So…
bedatty Aug 5, 2026
13d8d48
fix(js-pr-validation): surface the Socket API error payload
bedatty Aug 6, 2026
4a53572
fix(js-pr-validation): tell a Cloudflare challenge apart from a scope…
bedatty Aug 6, 2026
4f08039
fix(js-pr-validation): fetch the Socket API with python, not curl
bedatty Aug 6, 2026
de9c860
test(js-pr-validation): widen the socket alert debug sample
bedatty Aug 6, 2026
43ac207
test(js-pr-validation): log the socket alert action distribution
bedatty Aug 6, 2026
b9f61ce
feat(js-pr-validation): filter socket findings by action and own the …
bedatty Aug 6, 2026
52c6a81
feat(js-pr-validation): expose the socket findings policy on the umbr…
bedatty Aug 6, 2026
651aa00
fix(js-pr-validation): render the socket fix object instead of [objec…
bedatty Aug 6, 2026
0f1afd5
feat(js-pr-validation): separate introduced findings from pre-existin…
bedatty Aug 6, 2026
e190d16
test(js-pr-validation): log the socket baseline scan identity
bedatty Aug 6, 2026
d5fa617
fix(js-pr-validation): reject incomplete socket baselines
bedatty Aug 6, 2026
eacae6a
test(js-pr-validation): log the head scan's own scan_state
bedatty Aug 6, 2026
a301f93
fix(js-pr-validation): select the socket baseline by package overlap
bedatty Aug 6, 2026
817e47d
fix(js-pr-validation): attribute findings via Socket's diff scan
bedatty Aug 6, 2026
3ce2df2
feat(js-pr-validation): green header with no new findings, and dashbo…
bedatty Aug 6, 2026
b6365a2
style(js-pr-validation): split the diff-scan lookup across lines
bedatty Aug 6, 2026
6137cc4
feat(js-pr-validation): give the pre-existing section shape
bedatty Aug 6, 2026
ce54891
fix(js-pr-validation): label the scan link as this PR's scan
bedatty Aug 6, 2026
b38f781
feat(js-pr-validation): show which direct dependency reaches a finding
bedatty Aug 6, 2026
87fffd0
fix(js-pr-validation): restore the suggested fixes block
bedatty Aug 7, 2026
b38a179
docs(js-pr-validation): correct the Socket documentation
bedatty Aug 7, 2026
c7ad918
fix(js-pr-validation): detect a stale diff scan instead of trusting it
bedatty Aug 7, 2026
f850c85
fix(js-pr-validation): build the diff scan instead of waiting for the…
bedatty Aug 7, 2026
7d39f39
test(js-pr-validation): diagnose a diff scan reporting added=0
bedatty Aug 7, 2026
10b45f7
fix(js-pr-validation): drop omit_unchanged from the diff scan read
bedatty Aug 7, 2026
95c6f70
fix(js-pr-validation): read the diff buckets from diff_scan.artifacts
bedatty Aug 7, 2026
aaf144c
fix(js-pr-validation): print dashboard URLs instead of bare scan ids
bedatty Aug 7, 2026
c807994
refactor(js-pr-validation): drop the resolved diagnostics
bedatty Aug 7, 2026
b1aa4f4
chore(js-pr-validation): pin the socket composites back to @v1
bedatty Aug 7, 2026
81cc6bf
Merge branch 'develop' into feat/js-pr-validation-socket
bedatty Aug 7, 2026
7b3255f
fix(js-pr-validation): address the CodeRabbit security and correctnes…
bedatty Aug 7, 2026
9f96d77
fix(js-pr-validation): rename anc so the spell check passes
bedatty Aug 7, 2026
cbaa29e
fix(js-pr-validation): close four more silent-pass paths from the review
bedatty Aug 7, 2026
471eb23
fix: remove the typos binary committed by accident
bedatty Aug 7, 2026
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
4 changes: 4 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ updates:
- "trufflesecurity/trufflehog"
- "anchore/sbom-action"
- "sigstore/cosign-installer"
# Only reachable if SocketDev/action is ever referenced from a workflow;
# its current use is in src/security/socket-firewall, which the
# github-actions ecosystem does not scan (see note at the top).
- "SocketDev/action"
Comment on lines +77 to +80

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- Socket action reference and Dependabot pattern ---'
rg -n -C 3 'SocketDev/action' \
  .github/dependabot.yml \
  src/security/socket-firewall/action.yml

printf '%s\n' '--- Candidate composite-action drift checks ---'
rg -n -i -C 3 \
  'SocketDev/action|dependency[ -]drift|action[ -]drift|composite.*update' \
  .

Repository: LerianStudio/github-actions-shared-workflows

Length of output: 8631


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- Repository automation files ---'
git ls-files '.github' | sort

printf '%s\n' '--- All SocketDev/action references ---'
rg -n -i -C 4 'SocketDev/action' --glob '!CHANGELOG.md' .

printf '%s\n' '--- Drift and dependency automation ---'
rg -n -i -C 5 \
  'dependabot|dependency|drift|renovate|update.*action|action.*update|pin.*sha|sha.*pin' \
  .github Makefile package.json .pre-commit-config.yaml 2>/dev/null || true

printf '%s\n' '--- Dependabot configuration ---'
cat -n .github/dependabot.yml

Repository: LerianStudio/github-actions-shared-workflows

Length of output: 35084


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- Repository files that could implement action pin updates ---'
git ls-files | rg -i \
  '(^|/)(dependabot|renovate|pinact|actionlint|update|drift|dependency|deps|renov).*(yml|yaml|sh|py|js|ts|go|mk|json)$|(^|/)(Makefile|Taskfile(\.ya?ml)?|package\.json)$' \
  || true

printf '%s\n' '--- Exact update-check tool references ---'
rg -n -i -C 3 \
  'pinact|renovate|dependabot.*(?:composite|src/)|(?:composite|src/).*dependabot|check[-_ ]actions|update[-_ ]actions|actions[-_ ]update|dependency[-_ ]drift|action[-_ ]drift' \
  --glob '!CHANGELOG.md' . \
  || true

printf '%s\n' '--- Workflow steps that execute repository-maintenance checks ---'
rg -n -i -C 4 \
  'run:|uses:|schedule:|workflow_dispatch:' \
  .github/workflows \
  | rg -i 'run:|uses:|schedule:|workflow_dispatch:|dependabot|renovate|pinact|drift|dependency|actionlint|update' \
  || true

Repository: LerianStudio/github-actions-shared-workflows

Length of output: 50400


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- Pinned-actions validator ---'
git ls-files 'src/lint/pinned-actions' '.github/workflows/self-pr-validation.yml'
find src/lint/pinned-actions -maxdepth 2 -type f -print -exec sh -c 'echo "--- $1"; cat -n "$1"' _ {} \;

printf '%s\n' '--- Makefile maintenance targets ---'
rg -n -C 5 -i 'action|depend|pin|drift|update' Makefile

Repository: LerianStudio/github-actions-shared-workflows

Length of output: 9610


Add an active update path for SocketDev/action.

Dependabot does not scan composite actions under src/**/action.yml. The existing pinned-actions validator checks pin format but does not update action versions. Both src/security/socket-firewall/action.yml and src/setup/setup-node-guarded/action.yml reference SocketDev/action. Add a drift check that covers both files.

🤖 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/dependabot.yml around lines 77 - 80, Add an active Dependabot update
or drift-check configuration for SocketDev/action that explicitly covers both
src/security/socket-firewall/action.yml and
src/setup/setup-node-guarded/action.yml. Keep the existing pinned-actions
validation, but ensure this new path detects version changes for references in
both composite action files rather than relying on workflow scanning.

update-types:
- "minor"
- "patch"
Expand Down
352 changes: 99 additions & 253 deletions .github/workflows/frontend-pr-analysis.yml

Large diffs are not rendered by default.

257 changes: 257 additions & 0 deletions .github/workflows/js-pr-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ on:
description: 'Run the security scan pipeline (Trivy, CodeQL, prerelease checks)'
type: boolean
default: true
run_socket:
description: 'Run the Socket supply-chain pipeline (Socket Firewall and, when enabled, the Socket CLI scan)'
type: boolean
default: true
Comment on lines +40 to +43

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Wire the paid Socket scan or remove the public claim.

The socket job has no socket-scan step. It runs Firewall, App Gate, API Report, and Reporter steps only. Therefore, run_socket does not run the promised Socket CLI report.

  • .github/workflows/js-pr-validation.yml#L30-L33: add the intended scan action and its caller contract, or describe the implemented App/API pipeline.
  • docs/js-pr-validation.md#L14-L14: remove the socket-scan and CLI-report claim unless the workflow invokes that composite.
📍 Affects 2 files
  • .github/workflows/js-pr-validation.yml#L30-L33 (this comment)
  • docs/js-pr-validation.md#L14-L14
🤖 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/js-pr-validation.yml around lines 30 - 33, Align the
documented Socket behavior with the implementation: in
.github/workflows/js-pr-validation.yml lines 30-33, either wire the intended
socket-scan composite action and its caller contract into the run_socket flow or
update the description to accurately identify the existing Firewall, App Gate,
API Report, and Reporter pipeline; in docs/js-pr-validation.md line 14, remove
the socket-scan and CLI-report claim unless that composite action is invoked.


# ----------------- Change gate -----------------
ignore_globs:
Expand Down Expand Up @@ -272,14 +276,111 @@ on:
description: 'Comma-separated directories to skip in every Trivy filesystem scan (appended to the built-in skip list).'
type: string
default: ''

# ----------------- Socket supply chain (src/security/socket-*) -----------------
socket_enable_firewall:
description: 'Run Socket Firewall (free tier, no token) and install dependencies through it, blocking malicious packages at install time.'
type: boolean
default: true
socket_working_dir:
description: 'Directory holding the package.json and lockfile scanned by the Socket jobs'
type: string
default: '.'
socket_firewall_version:
description: 'Socket Firewall binary version. Empty or "latest" tracks the newest release.'
type: string
default: 'latest'
socket_job_summary:
description: 'Socket Firewall job summary verbosity (all, errors, none)'
type: string
default: 'all'
socket_use_cache:
description: 'Cache the sfw binary between runs. Unrelated to the package-manager cache, which is always purged before the guarded install.'
type: boolean
default: true
socket_fail_on_block:
description: 'Fail the Socket job when Socket Firewall blocks a package. Set to false to report the block as a warning instead.'
type: boolean
default: true
socket_enable_app_gate:
description: >-
Turn the Socket GitHub App checks into an enforceable gate. The App analyses the dependency graph and
posts advisory checks; this makes an adverse verdict block the pull request. Needs no token.
type: boolean
default: true
socket_app_slug:
description: 'GitHub App slug whose checks the gate reads'
type: string
default: 'socket-security'
socket_app_timeout:
description: 'Seconds to wait for the Socket App checks to complete before treating the result as inconclusive'
type: number
default: 300
Comment thread
bedatty marked this conversation as resolved.
socket_app_fail_on_findings:
description: 'Fail the Socket job when the App reports adverse checks'
type: boolean
default: true
socket_app_on_inconclusive:
description: >-
What to do when the App ran but reached no verdict (neutral/skipped/timeout): "block" (default) or "warn".
A conflicted pull request is the common cause, and it must not read as clean.
type: string
default: 'block'
socket_enable_api_report:
description: >-
Read the full scan the Socket App already computed and report per-package alerts, vulnerabilities and
scores in the pull request comment. Requires SOCKET_SECURITY_API_KEY with the full-scans:list scope.
Advisory only — it never gates the merge.
type: boolean
default: true
socket_api_max_rows:
description: 'Maximum package rows kept in the dependency findings table'
type: number
default: 25
socket_api_include_actions:
description: >-
Comma-separated Socket alert actions reported as findings. Socket marks roughly 99% of alerts as "ignore"
(capability observations such as envVars), so reporting unfiltered buries a handful of findings in
thousands of lines.
type: string
default: 'error,warn,monitor'
socket_comment_when:
description: >-
"findings" (the default) posts the Socket comment only when there is something to act on. "always" posts
every run. Operational state — whether the scan ran, which checks passed — is never in the comment; it
lives in the job log and the Socket status check.
type: string
default: 'findings'
socket_api_fail_on_actions:
description: >-
Comma-separated Socket alert actions that block the pull request. Empty (the default) reports without
blocking. Set to e.g. "error" to own the merge decision in this workflow rather than deferring it to the
Socket App's verdict.
type: string
default: ''
Comment on lines +364 to +370

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Document configured API findings as blocking.

A non-empty socket_api_fail_on_actions reaches the final gate and can fail the workflow. The documentation omits this input and states that API reporting is always advisory.

  • .github/workflows/js-pr-validation.yml#L347-L353: preserve the existing blocking contract.
  • docs/js-pr-validation.md#L95-L96: add rows for socket_api_include_actions and socket_api_fail_on_actions.
  • docs/js-pr-validation.md#L223-L231: state that API lookup failures remain advisory, but configured matching alert actions can block.
📍 Affects 2 files
  • .github/workflows/js-pr-validation.yml#L347-L353 (this comment)
  • docs/js-pr-validation.md#L95-L96
  • docs/js-pr-validation.md#L223-L231
🤖 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/js-pr-validation.yml around lines 347 - 353, Preserve the
existing blocking behavior of socket_api_fail_on_actions in the workflow. In
docs/js-pr-validation.md lines 95-96, document both socket_api_include_actions
and socket_api_fail_on_actions with their configured behavior; in lines 223-231,
clarify that API lookup failures are advisory, while matching configured alert
actions can block the workflow.

socket_app_on_missing:
description: >-
What to do when the App published no checks, which is what a repository without it installed looks like:
"warn" (default) keeps those repositories green, "block" requires the App.
type: string
default: 'warn'
secrets:
MANAGE_TOKEN:
required: false
SLACK_WEBHOOK_URL:
required: false
# Declared but not consumed by any job today: the Socket layers here run
# token-free (the firewall inspects traffic locally, the App gate reads the
# GitHub checks API). It is declared so an organization secret reaches this
# workflow through `secrets: inherit` without a release, which a reusable
# workflow cannot do for an undeclared secret. Do not delete as dead —
# Socket Firewall enterprise is the intended consumer.
SOCKET_SECURITY_API_KEY:
Comment thread
coderabbitai[bot] marked this conversation as resolved.
required: false

permissions:
actions: read
checks: read
Comment on lines 391 to +393

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Restore contents: read for the nested frontend workflow.

The workflow-level block removes contents permission. The frontend-analysis reusable workflow checks out repository code in every analysis job, so its default github.token cannot read the repository. Add contents: read at this level, or grant it only on the frontend-analysis call.

Proposed fix
 permissions:
   actions: read
   checks: read
+  contents: read
📝 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
permissions:
actions: read
checks: read
permissions:
actions: read
checks: read
contents: 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/js-pr-validation.yml around lines 374 - 376, Add contents:
read to the workflow-level permissions block containing actions and checks, or
grant it on the frontend-analysis reusable workflow invocation, so checkout
steps can read repository contents while preserving the existing permission
restrictions.

contents: read
id-token: write
issues: write
Expand Down Expand Up @@ -341,6 +442,9 @@ jobs:
path_level: ${{ inputs.path_level }}
normalize_to_filter: ${{ inputs.normalize_to_filter }}
app_name_prefix: ${{ inputs.app_name_prefix }}
enable_socket_firewall: ${{ inputs.socket_enable_firewall }}
socket_firewall_version: ${{ inputs.socket_firewall_version }}
socket_fail_on_block: ${{ inputs.socket_fail_on_block }}
enable_lint: ${{ inputs.enable_lint }}
enable_typecheck: ${{ inputs.enable_typecheck }}
enable_security: ${{ inputs.enable_security }}
Expand Down Expand Up @@ -417,6 +521,159 @@ jobs:
result: ${{ needs.changes.result != 'success' && needs.changes.result || needs.security.result }}
label: Security

# ----------------- Socket Supply Chain -----------------
# TEMPORARY: the two composite refs below point at this feature branch so the
# new actions resolve during end-to-end validation. Revert to @v1 before merge
# — the tag does not carry them yet, and the internal pinning policy requires
# a floating major tag for composites.
socket:
name: Socket (checks)
needs: changes
if: inputs.run_socket && needs.changes.outputs.code == 'true'
runs-on: ${{ vars.GENERAL_RUNNERS || inputs.runner_type }}
permissions:
contents: read
checks: read
issues: write
pull-requests: write
env:
SOCKET_APP_NAME: ${{ inputs.app_name_prefix != '' && inputs.app_name_prefix || github.event.repository.name }}
steps:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
with:
persist-credentials: false

# This install is the reporting source of truth for the Socket Firewall
# row below. Enforcement itself is broader: every install in
# frontend-pr-analysis.yml also runs through the firewall, so a malicious
# package cannot execute install scripts in any analysis job either.
- name: Socket Firewall
id: firewall
if: inputs.socket_enable_firewall
continue-on-error: true
uses: LerianStudio/github-actions-shared-workflows/src/security/socket-firewall@feat/js-pr-validation-socket
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
with:
package-manager: ${{ inputs.package_manager }}
node-version: ${{ inputs.node_version }}
working-dir: ${{ inputs.socket_working_dir }}
firewall-version: ${{ inputs.socket_firewall_version }}
job-summary: ${{ inputs.socket_job_summary }}
use-cache: ${{ inputs.socket_use_cache }}
fail-on-block: ${{ inputs.socket_fail_on_block }}
dry-run: ${{ inputs.dry_run }}

- name: Socket App Gate
id: app-gate
if: inputs.socket_enable_app_gate && github.event_name == 'pull_request'
continue-on-error: true
uses: LerianStudio/github-actions-shared-workflows/src/security/socket-app-gate@feat/js-pr-validation-socket
with:
github-token: ${{ secrets.MANAGE_TOKEN || github.token }}
# The App reports against the pull request head, not the merge commit.
commit-sha: ${{ github.event.pull_request.head.sha }}
app-slug: ${{ inputs.socket_app_slug }}
timeout-seconds: ${{ inputs.socket_app_timeout }}
fail-on-findings: ${{ inputs.socket_app_fail_on_findings }}
on-inconclusive: ${{ inputs.socket_app_on_inconclusive }}
on-missing-app: ${{ inputs.socket_app_on_missing }}

# Reads the scan the App already produced, addressed by the dashboard URL the
# gate captured — no new scan, one quota unit, no duplicate analysis.
# The App publishes the diff scan id in its own comment. Looking it up by
# after_full_scan_id does not work: the App diffs against a different full
# scan than the one its Project Report check links to.
- name: Resolve Socket diff scan id
id: diff-scan
if: always() && inputs.socket_enable_api_report && github.event_name == 'pull_request'
continue-on-error: true
env:
GH_TOKEN: ${{ secrets.MANAGE_TOKEN || github.token }}
PR: ${{ github.event.pull_request.number }}
REPO: ${{ github.repository }}
run: |
JQ='[.[] | select(.user.login == "socket-security[bot]") | .body] | last // ""'
BODY=$(gh api "repos/$REPO/issues/$PR/comments" --paginate --jq "$JQ")
ID=$(printf '%s' "$BODY" \
| grep -oE 'diff-scan/[0-9a-fA-F-]{36}' | head -1 | cut -d/ -f2 || true)
if [ -n "$ID" ]; then
echo "Resolved diff scan $ID from the Socket App comment."
else
echo "No diff scan id in the Socket App comment — it only posts one when dependencies change."
fi
echo "id=$ID" >> "$GITHUB_OUTPUT"
Comment thread
coderabbitai[bot] marked this conversation as resolved.

- name: Socket API Report
id: api-report
if: always() && inputs.socket_enable_api_report && github.event_name == 'pull_request'
continue-on-error: true
uses: LerianStudio/github-actions-shared-workflows/src/security/socket-api-report@feat/js-pr-validation-socket
with:
socket-api-key: ${{ secrets.SOCKET_SECURITY_API_KEY }}
report-url: ${{ steps.app-gate.outputs.report-url }}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
max-rows: ${{ inputs.socket_api_max_rows }}
include-actions: ${{ inputs.socket_api_include_actions }}
fail-on-actions: ${{ inputs.socket_api_fail_on_actions }}
# The baseline: findings already on the target branch are reported as
# pre-existing and never block, so a repository carrying debt does not
# fail every pull request for something none of them caused.
base-branch: ${{ github.base_ref }}
head-sha: ${{ github.event.pull_request.head.sha }}
diff-scan-id: ${{ steps.diff-scan.outputs.id }}

- name: Post Socket report to PR
if: always() && github.event_name == 'pull_request' && !inputs.dry_run
Comment thread
coderabbitai[bot] marked this conversation as resolved.
uses: LerianStudio/github-actions-shared-workflows/src/security/socket-reporter@feat/js-pr-validation-socket
with:
github-token: ${{ secrets.MANAGE_TOKEN || github.token }}
app-name: ${{ env.SOCKET_APP_NAME }}
comment-when: ${{ inputs.socket_comment_when }}
firewall-blocked: ${{ steps.firewall.outputs.blocked || 'false' }}
firewall-fail-on-block: ${{ inputs.socket_fail_on_block }}
firewall-findings-file: ${{ steps.firewall.outputs.findings-file }}
api-findings-file: ${{ steps.api-report.outputs.findings-file }}
api-blocking-count: ${{ steps.api-report.outputs.blocking-count || '0' }}
# yamllint disable-line rule:line-length
run-url: ${{ format('{0}/{1}/actions/runs/{2}', github.server_url, github.repository, github.run_id) }}

# continue-on-error above keeps the report reachable even when a layer
# fails, so the verdict is re-applied here.
- name: Gate - Fail on Socket findings
if: always()
env:
FIREWALL_OUTCOME: ${{ steps.firewall.outcome }}
APP_GATE_OUTCOME: ${{ steps.app-gate.outcome }}
API_BLOCKING: ${{ steps.api-report.outputs.blocking-count }}
run: |
FAILED=""
[ "$FIREWALL_OUTCOME" = "failure" ] && FAILED="$FAILED Socket-Firewall"
[ "$APP_GATE_OUTCOME" = "failure" ] && FAILED="$FAILED Socket-App-Gate"
# Only real findings from the API layer block. Its API-failure paths
# report zero here by construction, so an unreachable Socket cannot
# fail a pull request.
if [ "${API_BLOCKING:-0}" -gt 0 ] 2>/dev/null; then
FAILED="$FAILED Socket-Dependency-Findings"
fi
if [ -n "$FAILED" ]; then
echo "::error::Socket supply chain gate failed:$FAILED. See the Socket comment on the pull request."
exit 1
fi
echo "Socket supply chain gate passed."

socket-gate:
name: Socket
needs: [changes, socket]
if: always()
runs-on: ${{ vars.GENERAL_RUNNERS || inputs.runner_type }}
permissions:
contents: read
steps:
- name: Aggregate Socket result
uses: LerianStudio/github-actions-shared-workflows/src/validate/result-gate@v1
with:
result: ${{ needs.changes.result != 'success' && needs.changes.result || needs.socket.result }}
label: Socket

# ----------------- Org ruleset compatibility stubs -----------------
# Go Analysis and Lib Version are required status checks in the Lerian org
# branch-protection ruleset (designed for Go repos). These stubs are
Expand Down
11 changes: 11 additions & 0 deletions docs/frontend-pr-analysis-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,14 @@ jobs:
secrets: inherit
```

## Guarded dependency installs

Every job that installs dependencies does so through [`setup-node-guarded`](../src/setup/setup-node-guarded/README.md), which runs `sfw npm ci` (or the `yarn`/`pnpm` equivalent) under [Socket Firewall](https://github.com/SocketDev/sfw-free) instead of a bare install. A malicious package is refused mid-fetch, so it never reaches disk and its install scripts never execute — in **any** of these jobs, not just one.

Guarded installs deliberately run **without a package-manager cache**: Socket Firewall only inspects what crosses the network, and a cached tarball produces no request. The cache is also purged before each install, since runner images can arrive pre-warmed. Measured cost is roughly 20s for a cold install of ~2000 packages.

Set `enable_socket_firewall: false` to restore the previous behaviour (cached, unguarded) — necessary for repositories that install from a private registry, which the free edition does not support.
Comment thread
coderabbitai[bot] marked this conversation as resolved.

## Inputs

| Input | Description | Required | Default |
Expand All @@ -152,6 +160,9 @@ jobs:
| `app_name_prefix` | Prefix for app names in matrix output | No | `''` |
| `node_version` | Node.js version to use | No | `22` |
| `package_manager` | Package manager (npm, yarn, pnpm) | No | `npm` |
| `enable_socket_firewall` | Route every dependency install through Socket Firewall (free tier, no token) so a malicious package is refused before any install script runs. `false` restores the previous behaviour, package-manager cache included | No | `true` |
| `socket_firewall_version` | Socket Firewall binary version | No | `latest` |
| `socket_fail_on_block` | Fail the job when Socket Firewall blocks a package | No | `true` |
| `eslint_args` | Additional ESLint arguments | No | `''` |
| `audit_level` | npm audit severity level (low, moderate, high, critical) | No | `high` |
| `coverage_threshold` | Minimum coverage percentage (0-100) | No | `80` |
Expand Down
Loading