Skip to content

feat: add sfw input to wrap vp install with Socket Firewall Free#72

Open
fengmk2 wants to merge 21 commits into
mainfrom
feat/sfw-input
Open

feat: add sfw input to wrap vp install with Socket Firewall Free#72
fengmk2 wants to merge 21 commits into
mainfrom
feat/sfw-input

Conversation

@fengmk2
Copy link
Copy Markdown
Member

@fengmk2 fengmk2 commented May 26, 2026

Summary

  • Adds a boolean sfw input. When true and run-install is enabled, the action downloads the matching sfw binary from the upstream releases (auto-detected per OS/arch, with musl support on Alpine) and runs sfw vp install … so the underlying package manager's network fetches are inspected before install.
  • Default is false — no behavior change for existing consumers.
  • sfw only wraps vp install. Other vp invocations (vp env use, vp --version) stay unwrapped.
- uses: voidzero-dev/setup-vp@v1
  with:
    sfw: true
    run-install: true

Why

Lets open-source projects opt into Socket Firewall Free protection for CI installs with a single input — no need to compose a separate socketdev/action@v1 step. See https://docs.socket.dev/docs/socket-firewall-free.

Implementation notes

  • src/install-sfw.ts — downloads sfw-free-<asset> from releases/latest/download/, chmod +x on POSIX, then addPath. Mirrors the retry pattern in install-viteplus.ts.
  • musl detection: process.report.getReport().header.glibcVersionRuntime with fs.existsSync('/etc/alpine-release') as a fallback. Selects sfw-free-musl-linux-{arm64,x86_64} on Alpine.
  • src/run-install.ts — execs sfw with ["vp", "install", …] instead of vp with ["install", …] when inputs.sfw is true.

Test plan

  • Unit tests: vp run test — 133 passed (13 new in install-sfw.test.ts covering all 8 platform/arch/libc combos + error cases; 1 new in inputs.test.ts).
  • vp run typecheck clean.
  • vp run check:fix clean.
  • vp run build regenerated dist/index.mjs.
  • New test-sfw job (Ubuntu/macOS/Windows × latest/alpha) — installs is-odd under sfw vp install and verifies sfw --version resolves on PATH.
  • New test-sfw-alpine job (alpine:3.23 container) — proves the musl asset is selected (a glibc binary would fail to exec inside Alpine).
  • All existing test jobs continue to pass with sfw: false default (no behavior change).

Note

Medium Risk
Changes the install execution path and downloads a third-party binary when enabled; default false preserves existing behavior, but misconfiguration or upstream sfw/TLS issues could break CI installs on Linux.

Overview
Adds an optional sfw input (default false) so CI can run sfw vp install instead of plain vp install when run-install is enabled, using Socket Firewall Free to inspect dependency fetches. On Linux, the action downloads the matching sfw release asset (glibc or musl on Alpine), puts it on PATH, and only wraps install—not other vp commands. On macOS/Windows, it warns and falls back to unwrapped install without downloading sfw (documented Linux-only limitation).

README and action.yml document the input and behavior. CI adds test-sfw (Linux × pnpm/npm/yarn/bun; non-Linux fallback checks), test-sfw-alpine (musl), and test-sfw-blocks-malicious (typosquat lodahs must fail with an sfw marker in output).

Reviewed by Cursor Bugbot for commit b6a100f. Configure here.

When `sfw: true`, the action downloads the matching `sfw` binary from
github.com/SocketDev/sfw-free/releases (auto-detected per OS/arch, with
musl support on Alpine) and runs `sfw vp install ...` so the underlying
package manager's network fetches are inspected before install. Other
`vp` commands run unwrapped.

CI: new `test-sfw` (Ubuntu/macOS/Windows x latest/alpha) and
`test-sfw-alpine` (alpine:3.23, musl branch) jobs exercise the new
input end-to-end.
@fengmk2 fengmk2 self-assigned this May 26, 2026
fengmk2 added 3 commits May 26, 2026 15:19
New job installs `is-odd` benignly to put sfw on PATH, then runs
`sfw vp install lodahs` (lodash typosquat) and asserts the install
exits non-zero. `lodahs` is the same canary Socket uses in their
bun-security-scanner workflow:
https://github.com/SocketDev/bun-security-scanner/blob/main/.github/workflows/test.yml

Verifies sfw actually intercepts malicious packages end-to-end, not
just that the wrapping plumbing is wired.
sfw v1.10.0 issues a CA cert with a present-but-empty EKU extension.
OpenSSL accepts it; rustls (vp's TLS stack), Go crypto/x509, and other
strict implementations reject it as UnknownIssuer. So `vp install`
through sfw works on Ubuntu only because pnpm is preinstalled and vp
skips the bootstrap fetch. On macOS / Windows, vp must fetch
`https://registry.npmjs.org/pnpm/latest` and the handshake fails before
sfw can inspect the install.

Action still installs the sfw binary on all OSes (asset mapping unit-
tested) so users can call `sfw npm ci` directly; only setup-vp's own
run-install path is Linux-verified for now.

Tracking upstream:
  SocketDev/sfw-free#30
  SocketDev/sfw-free#43
sfw v1.10.0 issues a TLS cert with an empty EKU extension that vp's
rustls rejects (UnknownIssuer). To keep `sfw: true` safe to set in
cross-platform workflows, the action now:

  - Checks process.platform === 'linux' via isSfwSupported()
  - On non-Linux: emits a warning, skips the sfw binary download, and
    runs plain `vp install` (no sfw wrap)
  - On Linux: behavior unchanged — downloads sfw and runs `sfw vp install`

CI: test-sfw matrix is restored to Linux/macOS/Windows. Linux asserts
sfw is on PATH; macOS/Windows assert sfw is NOT on PATH (fallback) and
the plain install still completes.

Tracking upstream:
  SocketDev/sfw-free#30
  SocketDev/sfw-free#43
fengmk2 added 3 commits May 26, 2026 16:31
The warning now links to #73 (the consolidated
follow-up tracker) instead of SocketDev/sfw-free#30, since #73 is the
single place that aggregates both the upstream sfw fix and the vp-side
work needed to lift the Linux-only restriction.
Replace the direct SocketDev/sfw-free#30 / #43 references with a link
to the consolidated #73 tracker, which already
links out to both upstream issues plus the vp-side work needed.
The test-sfw job header now points to #73 (which
already fans out to SocketDev/sfw-free#30 / #43 and the vp-side work)
instead of duplicating the upstream links.

The lodahs canary citation to SocketDev/bun-security-scanner is left
in place — it's a pattern reference, not an upstream tracking link.
@fengmk2 fengmk2 marked this pull request as ready for review May 26, 2026 08:41
Copilot AI review requested due to automatic review settings May 26, 2026 08:41
The comment used to enumerate the specific sfw v1.10.0 EKU symptoms and
the SocketDev/sfw-free#30/#43 upstream issues. Those details belong on
the tracker — the source comment just needs to point readers to it.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds an optional sfw input to the action to wrap vp install with Socket Firewall Free, enabling dependency-fetch inspection during installs while preserving existing behavior by default.

Changes:

  • Introduces a new sfw boolean input (wired through action.yml, README, and getInputs()/Inputs typing).
  • Adds installSfw() to download and place the sfw binary on PATH, and updates install execution to run sfw vp install ... when enabled.
  • Extends CI workflows with new test-sfw jobs (including Alpine/musl validation and a “blocks malicious” canary test).

Reviewed changes

Copilot reviewed 12 out of 13 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/utils.test.ts Updates test fixtures to include the new sfw input field.
src/types.ts Extends Inputs with sfw: boolean.
src/run-install.ts Switches install execution to sfw vp install ... when inputs.sfw is enabled.
src/install-viteplus.test.ts Updates base Inputs fixture to include sfw.
src/install-sfw.ts Adds SFW download/install logic and platform/musl detection helpers.
src/install-sfw.test.ts Adds unit coverage for asset selection and platform support gating.
src/inputs.ts Parses sfw via getBooleanInput("sfw").
src/inputs.test.ts Adds coverage for parsing the sfw input.
src/index.ts Installs sfw before running installs (Linux-only fallback behavior) and passes an effective sfw flag to runViteInstall.
README.md Documents sfw usage, including Linux-only fallback rationale.
action.yml Exposes the sfw input for action consumers.
.github/workflows/test.yml Adds new CI jobs validating sfw behavior across OSes and on Alpine/musl.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread action.yml Outdated
Comment thread src/install-sfw.ts Outdated
Comment thread src/index.ts Outdated
Comment thread .github/workflows/test.yml
fengmk2 added 2 commits May 26, 2026 16:47
New Linux-only job iterates over each package manager vp auto-detects
via lockfile and verifies `sfw vp install` succeeds end-to-end with
each. bun is marked experimental (continue-on-error) since sfw does
not officially list it as a supported PM.
- yarn: set YARN_ENABLE_IMMUTABLE_INSTALLS=false so Yarn Berry can
  regenerate the empty yarn.lock under CI (the previous failure was
  YN0028 — sfw itself worked fine, fetching 1 package successfully).
- bun: drop the experimental/continue-on-error flag — bun installs
  through sfw cleanly in the first run, so failures should gate CI.
Copilot AI review requested due to automatic review settings May 26, 2026 08:49
Yarn Berry's default Plug'n'Play linker means a plain `node -e
require('is-odd')` from the verify step can't resolve the module
(it's in .yarn/cache, not node_modules). Add a .yarnrc.yml only for
the yarn matrix entry so all four package managers produce the same
node_modules layout for the test.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 12 out of 13 changed files in this pull request and generated 4 comments.

Comment thread src/index.ts Outdated
Comment thread src/install-sfw.ts
Comment thread action.yml Outdated
Comment thread .github/workflows/test.yml Outdated
The split was over-engineering — they test orthogonal axes (platform
fallback × package-manager diversity) that compose naturally in a
single matrix.

Merged: os × version × package-manager with excludes so non-Linux
only runs the default PM (pnpm). 12 jobs total instead of 14:
  - Linux × {pnpm,npm,yarn,bun} × {latest,alpha} = 8 (sfw wrap)
  - {macos,windows} × pnpm × {latest,alpha}      = 4 (sfw fallback)

Failure isolation improves too — a yellow check now reads
`test-sfw (windows-latest, latest, pnpm)` so you see which exact
combo broke.
@fengmk2
Copy link
Copy Markdown
Member Author

fengmk2 commented May 26, 2026

@cursor review

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit e6024b3. Configure here.

- case statement: add `*)` default branch so future axis additions fail
  loudly with a clear message instead of opaquely at the redirect.
- yarn config: move `enableImmutableInstalls: false` from the action's
  env block into the same `.yarnrc.yml` that already sets `nodeLinker`.
  Survives any future env-sanitization vp might apply to spawned
  subprocesses.
- yarn config step: add explicit `runner.os == 'Linux'` gate so a
  future PR that broadens cross-OS coverage doesn't accidentally run
  it on Windows where Yarn-Berry-on-bash has historically been flaky.
- non-Linux fallback assert: check `$RUNNER_TEMP/sfw-bin/sfw[.exe]`
  doesn't exist (the exact path the action would have created) rather
  than `command -v sfw` so a runner image that pre-installs sfw
  globally doesn't false-fail the assertion.
- isSfwSupported comment: restore the in-tree technical breadcrumb
  (empty-EKU + rustls) so future maintainers have context when
  setup-vp#73 eventually closes.
Copilot AI review requested due to automatic review settings May 26, 2026 09:04
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 12 out of 13 changed files in this pull request and generated 2 comments.

Comment thread action.yml Outdated
Comment thread src/install-sfw.ts Outdated
fengmk2 added 2 commits May 26, 2026 19:35
Addresses the Copilot review threads on PR #72:

- action.yml: input description now documents Linux-only behavior and
  the macOS/Windows fallback so Marketplace/IDE listings don't imply
  cross-platform support.
- isSfwSupported(): also returns false when getSfwAssetName can't
  resolve an asset for the current arch (e.g. Linux self-hosted runner
  on riscv64). Previously installSfw would throw; now we fall back to
  plain vp install like we do on macOS/Windows.
- index.ts: fallback warning only fires when run-install is actually
  enabled — workflows that set sfw:true but install separately no
  longer see noise.
- test-sfw-blocks-malicious: grep stdout/stderr for an sfw-specific
  block marker in addition to checking exit code, so npm 404 / network
  / vp crash can't silently masquerade as "sfw blocked it".

Explicitly NOT pinning the sfw version (per maintainer guidance):
keeping releases/latest so users automatically pick up upstream
malware-detection updates. Added a comment explaining the tradeoff.
Drop the [latest, alpha] axis from test-sfw — sfw is decoupled from
vp's release channel, and the OS × package-manager matrix is already
6 cells. Other test jobs (test, test-node-version, test-cache-*)
still cover the alpha channel for vp itself.

Cuts test-sfw from 12 jobs to 6.
Copilot AI review requested due to automatic review settings May 26, 2026 11:39
fengmk2 added 2 commits May 26, 2026 19:39
Consistent with the test-sfw slim-down: sfw's musl asset selection and
block behavior are both decoupled from vp's release channel, so testing
both vp versions adds no signal — only doubles CI cost. Other test jobs
still cover the alpha channel for vp itself.
A one-value matrix is dead weight — let vp version fall to the action's
default (`latest` per action.yml) and remove the matrix axis from
test-sfw, test-sfw-alpine, and test-sfw-blocks-malicious.

test-sfw-alpine and test-sfw-blocks-malicious had `version` as their
ONLY matrix axis, so they drop the `strategy.matrix` block entirely
and become plain single-cell jobs.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 12 out of 13 changed files in this pull request and generated 1 comment.

Comment thread src/install-sfw.test.ts
@fengmk2
Copy link
Copy Markdown
Member Author

fengmk2 commented May 26, 2026

@cursor review

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit b6a100f. Configure here.

Headline fix: lodahs block-marker grep was functionally broken — sfw
prints `Protected by Socket Firewall` and `=== Socket Firewall ===` on
EVERY invocation, not just real blocks. The previous regex
`(socket firewall|blocked|malware|sfw)` matched those banner lines, so
any non-zero exit from `sfw vp install lodahs` (npm 404, network blip,
canary delisting, vp crash) would silently pass as "sfw blocked it".

Confirmed against the actual CI log of test-sfw-blocks-malicious: the
banner is printed even on a clean install of `is-odd`. The unique
block-line is:
  " - blocked npm package: name: lodahs; version: ...; reason: ..."

Switched the assertion to a literal-string `grep -qF` on that line.

Other findings addressed:
- src/index.ts diagnostic now includes process.arch and isMuslLinux()
  so the message doesn't claim "only supported on Linux" on a Linux
  runner with an unsupported arch (riscv64, ppc64, ia32).
- Added an info() log for `sfw: true` + (unsupported || run-install:
  false) so the no-op is visible — previously the gating change
  silenced the only signal in that combo.
- isSfwSupported() defensive `!!asset` check: if getSfwAssetName is
  ever refactored from throw → return undefined, the predicate stays
  correct instead of silently flipping to always-true.
- Stale comment about "non-Linux platforms" updated — isSfwSupported
  now also returns false on Linux+unsupported-arch.
- TODO comments near test-sfw-alpine and test-sfw-blocks-malicious so
  a future re-matrixing restores `strategy.fail-fast: false`.
Comment thread src/install-sfw.ts Outdated
Addresses serhalp's review (#72 thread r3306983615) about the
meta-supply-chain risk of pulling sfw from releases/latest. Three
changes ship together:

1. Pin sfw to v1.10.0 via SFW_VERSION constant. Renovate's custom
   regex manager (added to .github/renovate.json) watches that
   constant and opens a PR whenever SocketDev publishes a new
   sfw-free release, so the bump is mechanical.

2. Auto-detect an existing sfw on PATH (via `which` / `where`) before
   downloading. When the user composes `socketdev/action@<sha>` ahead
   of this action, that step puts sfw on PATH; setup-vp now detects
   it, logs "Using existing sfw on PATH: …", and skips the bundled
   download entirely. Lets users SHA-pin sfw via Renovate against the
   upstream action repo for stricter supply-chain hygiene.

3. Centralize sfw decision logic in setupSfw(inputs). Covers all
   four branches (run-install disabled, sfw already on PATH,
   supported platform, unsupported platform) with one log line per
   branch.

Docs: new "Advanced: stricter supply chain via socketdev/action"
section in README with the composition example.

CI: new test-sfw-with-socketdev-action job exercises the composition
path end-to-end (socketdev/action@<sha> → setup-vp with sfw:true →
verify install).
Copilot AI review requested due to automatic review settings May 27, 2026 02:56
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 14 changed files in this pull request and generated 3 comments.

Comment thread src/install-sfw.ts Outdated
Comment thread src/install-sfw.test.ts
Comment thread .github/workflows/test.yml
fengmk2 added 2 commits May 27, 2026 13:55
…ssert

Addresses the two remaining Copilot review threads on PR #72.

setupSfw():
  Order was: PATH-detect → platform gate. So a macOS/Windows workflow that
  composes `socketdev/action@<sha>` (which works fine on those platforms
  and puts sfw on PATH) would skip the platform-fallback warning and run
  `sfw vp install`, hitting the rustls TLS handshake bug (#73).
  New order: platform gate FIRST, then on Linux prefer PATH, then on
  unsupported-arch Linux fall back with a more specific message.
  Pulled the unsupported-arch suggestion out of the macOS/Windows warning
  since composing socketdev/action wouldn't help there.

test-sfw-with-socketdev-action:
  The job comment claimed an assertion that wasn't actually in the
  workflow. Added a negative check that `$RUNNER_TEMP/sfw-bin/sfw[.exe]`
  was NOT created — proves setup-vp took the PATH-detection branch
  instead of downloading. If the branch ever regresses (e.g. someone
  reorders setupSfw), this catches it.
Saves ~130 MB and ~5-15s per run, and gives us a fallback when the
GitHub releases CDN flakes (we've hit that class of incident before
for the vp install scripts in #67).

Implementation:
- restoreCache at the start of installSfw with key
    sfw-${SFW_VERSION}-${platform}-${arch}-${libc}
  No restoreKeys: we never accept a different version's binary as a
  fallback. The version is in the key so a Renovate bump to
  SFW_VERSION naturally evicts stale entries (GHA also auto-evicts
  after 7 days).
- On cache hit: chmod+addPath and return — skip the download entirely.
- On cache miss: existing download/retry path runs, then saveCache
  publishes to GHA cache for future runs.
- All cache calls wrapped in try/catch so any cache-service failure
  (network blip, 5xx, ReserveCacheError on duplicate key) falls
  through cleanly to the download path; cache is never load-bearing.
- The composition path (socketdev/action@<sha>) is untouched —
  findSfwOnPath() still wins and we don't double-cache what
  @actions/tool-cache (which socketdev/action uses) already manages.

CI: existing test-sfw matrix exercises both the cache-miss (first
push on a branch) and cache-hit (subsequent pushes) paths; no new
job needed.
Copilot AI review requested due to automatic review settings May 27, 2026 13:56
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 14 changed files in this pull request and generated 2 comments.

Comment thread src/install-sfw.test.ts
Comment on lines +63 to +64
it("returns true on Linux, false elsewhere (matches current platform)", () => {
expect(isSfwSupported()).toBe(process.platform === "linux");
Comment thread src/install-sfw.ts
Comment on lines +187 to +191
export async function setupSfw(inputs: Inputs): Promise<boolean> {
if (!inputs.sfw) return false;

if (inputs.runInstall.length === 0) {
info("sfw was requested but `run-install` is disabled; sfw will not be invoked.");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants