Skip to content

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

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

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

Workflow file for this run

name: Test
on:
push:
branches: [main]
pull_request:
branches: [main]
merge_group:
jobs:
test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
version: [latest, alpha]
runs-on: ${{ matrix.os }}
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2
- name: Setup Vite+ (${{ matrix.version }})
uses: ./
with:
version: ${{ matrix.version }}
run-install: false
cache: false
- name: Verify installation
run: vp --version
test-node-version:
strategy:
fail-fast: false
matrix:
node-version: ["lts", "22", "24"]
version: [latest, alpha]
runs-on: ubuntu-latest
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2
- name: Setup Vite+ (${{ matrix.version }}) with Node.js ${{ matrix.node-version }}
uses: ./
with:
version: ${{ matrix.version }}
node-version: ${{ matrix.node-version }}
run-install: false
cache: false
- name: Verify installation
run: vp --version
- name: Verify Node.js version
shell: bash
run: |
ACTUAL=$(node --version)
echo "Node.js version: $ACTUAL"
if [ "${{ matrix.node-version }}" != "lts" ]; then
echo "$ACTUAL" | grep -q "^v${{ matrix.node-version }}\." || (echo "Expected Node.js v${{ matrix.node-version }}.x but got $ACTUAL" && exit 1)
fi
test-cache-pnpm:
strategy:
fail-fast: false
matrix:
version: [latest, alpha]
runs-on: ubuntu-latest
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2
- name: Create test project with pnpm-lock.yaml
run: |
mkdir -p test-project
cd test-project
echo '{"name":"test-project","private":true}' > package.json
touch pnpm-lock.yaml
- name: Setup Vite+ (${{ matrix.version }}) with pnpm cache
uses: ./
id: setup
with:
version: ${{ matrix.version }}
run-install: false
cache: true
cache-dependency-path: test-project/pnpm-lock.yaml
- name: Verify installation
run: |
vp --version
echo "Installed version: ${{ steps.setup.outputs.version }}"
echo "Cache hit: ${{ steps.setup.outputs.cache-hit }}"
test-cache-npm:
strategy:
fail-fast: false
matrix:
version: [latest, alpha]
runs-on: ubuntu-latest
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2
- name: Create test project with package-lock.json
run: |
mkdir -p test-project
cd test-project
echo '{"name":"test-project","private":true}' > package.json
echo '{"name":"test-project","lockfileVersion":3}' > package-lock.json
- name: Setup Vite+ (${{ matrix.version }}) with npm cache
uses: ./
id: setup
with:
version: ${{ matrix.version }}
run-install: false
cache: true
cache-dependency-path: test-project/package-lock.json
- name: Verify installation
run: |
vp --version
echo "Installed version: ${{ steps.setup.outputs.version }}"
echo "Cache hit: ${{ steps.setup.outputs.cache-hit }}"
test-cache-yarn:
strategy:
fail-fast: false
matrix:
version: [latest, alpha]
runs-on: ubuntu-latest
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2
- name: Create test project with yarn.lock
run: |
mkdir -p test-project
cd test-project
echo '{"name":"test-project","private":true}' > package.json
touch yarn.lock
- name: Setup Vite+ (${{ matrix.version }}) with yarn cache
uses: ./
id: setup
with:
version: ${{ matrix.version }}
run-install: false
cache: true
cache-dependency-path: test-project/yarn.lock
- name: Verify installation
run: |
vp --version
echo "Installed version: ${{ steps.setup.outputs.version }}"
echo "Cache hit: ${{ steps.setup.outputs.cache-hit }}"
test-cache-bun:
strategy:
fail-fast: false
matrix:
version: [latest, alpha]
lockfile: [bun.lock, bun.lockb]
runs-on: ubuntu-latest
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2
- name: Create test project with ${{ matrix.lockfile }}
run: |
mkdir -p test-project
cd test-project
echo '{"name":"test-project","private":true}' > package.json
touch ${{ matrix.lockfile }}
- name: Setup Vite+ (${{ matrix.version }}) with bun cache (${{ matrix.lockfile }})
uses: ./
id: setup
with:
version: ${{ matrix.version }}
run-install: false
cache: true
cache-dependency-path: test-project/${{ matrix.lockfile }}
- name: Verify installation
run: |
vp --version
echo "Installed version: ${{ steps.setup.outputs.version }}"
echo "Cache hit: ${{ steps.setup.outputs.cache-hit }}"
test-vp-exec:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
version: [latest, alpha]
runs-on: ${{ matrix.os }}
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2
- name: Setup Vite+ (${{ matrix.version }})
uses: ./
with:
version: ${{ matrix.version }}
run-install: false
cache: false
- name: Verify vp exec works
run: vp exec node -e "console.log('vp exec works')"
test-vp-install-and-exec:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
version: [latest, alpha]
runs-on: ${{ matrix.os }}
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2
- name: Create test project
shell: bash
run: |
mkdir -p test-project
cd test-project
echo '{"name":"test-project","private":true,"scripts":{"hello":"node -e \"console.log(1+1)\""}}' > package.json
- name: Setup Vite+ (${{ matrix.version }}) with install
uses: ./
with:
version: ${{ matrix.version }}
run-install: |
- cwd: test-project
cache: false
- name: Verify vp exec in project
working-directory: test-project
run: vp exec node -e "console.log('vp exec in project works')"
- name: Verify vp run in project
working-directory: test-project
run: vp run hello
test-registry-url:
strategy:
fail-fast: false
matrix:
version: [latest, alpha]
runs-on: ubuntu-latest
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2
- name: Setup Vite+ (${{ matrix.version }}) with registry-url
uses: ./
with:
version: ${{ matrix.version }}
run-install: false
cache: false
registry-url: "https://npm.pkg.github.com"
scope: "@voidzero-dev"
- name: Verify .npmrc was created
run: |
echo "NPM_CONFIG_USERCONFIG=$NPM_CONFIG_USERCONFIG"
cat "$NPM_CONFIG_USERCONFIG"
grep -q "@voidzero-dev:registry=https://npm.pkg.github.com/" "$NPM_CONFIG_USERCONFIG"
grep -q "_authToken=\${NODE_AUTH_TOKEN}" "$NPM_CONFIG_USERCONFIG"
- name: Verify NODE_AUTH_TOKEN is exported
run: |
echo "NODE_AUTH_TOKEN is set: ${NODE_AUTH_TOKEN:+yes}"
test-alpine-container:
strategy:
fail-fast: false
matrix:
version: [latest, alpha]
runs-on: ubuntu-latest
container:
image: alpine:3.23
steps:
- name: Install Alpine dependencies
run: apk add --no-cache bash curl gcompat libstdc++
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2
- name: Setup Vite+ (${{ matrix.version }})
uses: ./
with:
version: ${{ matrix.version }}
run-install: false
cache: false
- name: Verify installation
run: vp --version
- name: Verify vp exec works
run: vp exec node -e "console.log('vp exec works in Alpine')"
test-sfw:
# On Linux: sfw wraps vp install end-to-end. Verify across all package
# managers vp auto-detects via lockfile (pnpm/npm/yarn/bun).
# On macOS / Windows: sfw is temporarily unsupported; the action emits a
# warning and falls back to plain `vp install` with no sfw binary
# downloaded. We verify the fallback once per non-Linux OS using the
# default package manager (pnpm) — the PM diversity matrix is Linux-only
# because the sfw wrap is Linux-only.
# Tracking: https://github.com/voidzero-dev/setup-vp/issues/73
# vp version is left at the action default (`latest`) — sfw is decoupled
# from vp's release channel. Other test jobs (test-cache-*,
# test-node-version, etc.) still cover the alpha channel for vp itself.
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
package-manager: [pnpm, npm, yarn, bun]
exclude:
# Non-Linux only needs one fallback check per OS — sfw isn't
# invoked there, so PM diversity adds no coverage.
- { os: macos-latest, package-manager: npm }
- { os: macos-latest, package-manager: yarn }
- { os: macos-latest, package-manager: bun }
- { os: windows-latest, package-manager: npm }
- { os: windows-latest, package-manager: yarn }
- { os: windows-latest, package-manager: bun }
runs-on: ${{ matrix.os }}
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2
- name: Create test project for ${{ matrix.package-manager }}
shell: bash
run: |
case "${{ matrix.package-manager }}" in
pnpm) LOCKFILE=pnpm-lock.yaml; CONTENTS='' ;;
npm) LOCKFILE=package-lock.json; CONTENTS='{"name":"test-project","lockfileVersion":3}' ;;
yarn) LOCKFILE=yarn.lock; CONTENTS='' ;;
bun) LOCKFILE=bun.lock; CONTENTS='' ;;
*) echo "Unsupported package-manager: ${{ matrix.package-manager }}" >&2; exit 1 ;;
esac
mkdir -p test-project
cd test-project
echo '{"name":"test-project","private":true,"dependencies":{"is-odd":"^3.0.1"}}' > package.json
printf '%s' "$CONTENTS" > "$LOCKFILE"
- name: Configure Yarn .yarnrc.yml (Linux + yarn only)
if: matrix.package-manager == 'yarn' && runner.os == 'Linux'
# nodeLinker=node-modules: Yarn Berry defaults to Plug'n'Play, which
# makes plain `require()` from a non-yarn-wrapped node process fail.
# enableImmutableInstalls=false: Yarn Berry auto-enables immutable
# installs under CI, which makes the bootstrap from an empty
# yarn.lock fail with YN0028. Setting it here (instead of via the
# YARN_ENABLE_IMMUTABLE_INSTALLS env var) survives any future
# env-sanitization vp might apply to spawned subprocesses.
shell: bash
run: |
{
echo "nodeLinker: node-modules"
echo "enableImmutableInstalls: false"
} > test-project/.yarnrc.yml
- name: Setup Vite+ with sfw + ${{ matrix.package-manager }}
uses: ./
with:
sfw: true
run-install: |
- cwd: test-project
cache: false
- name: Verify sfw is on PATH (Linux only)
if: runner.os == 'Linux'
run: sfw --version
- name: Verify sfw fallback on non-Linux (action did not install sfw)
if: runner.os != 'Linux'
shell: bash
# Check the exact path getSfwBinDir() would have created rather than
# `command -v sfw`, so a runner image that happens to ship sfw
# globally (or a leftover from a prior self-hosted job) doesn't
# false-fail this assertion.
run: |
if [ -e "$RUNNER_TEMP/sfw-bin/sfw" ] || [ -e "$RUNNER_TEMP/sfw-bin/sfw.exe" ]; then
echo "ERROR: expected the action to skip the sfw download on ${{ runner.os }}, but $RUNNER_TEMP/sfw-bin/sfw[.exe] exists"
exit 1
fi
echo "OK: action did not install sfw; fallback to plain vp install confirmed"
- name: Verify dependency installed via ${{ matrix.package-manager }}
working-directory: test-project
run: vp exec node -e "console.log(require('is-odd')(3))"
test-sfw-alpine:
# vp version is left at the action default (`latest`) — sfw's musl asset
# selection is decoupled from vp's release channel.
# NOTE: if this job is later re-matrixed (alpha+latest, multiple alpine
# versions, etc.), restore `strategy: { fail-fast: false }` so a flake in
# one shard doesn't cancel the others.
runs-on: ubuntu-latest
container:
image: alpine:3.23
steps:
- name: Install Alpine dependencies
run: apk add --no-cache bash curl gcompat libstdc++
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2
- name: Create test project with a real dependency
run: |
mkdir -p test-project
cd test-project
echo '{"name":"test-project","private":true,"dependencies":{"is-odd":"^3.0.1"}}' > package.json
- name: Setup Vite+ with sfw (musl)
uses: ./
with:
sfw: true
run-install: |
- cwd: test-project
cache: false
- name: Verify sfw is on PATH (musl)
run: sfw --version
- name: Verify dependency installed under sfw (musl)
working-directory: test-project
run: vp exec node -e "console.log(require('is-odd')(3))"
test-sfw-blocks-malicious:
# Verifies sfw actually intercepts a known-malicious package, not just
# that it wraps the install. Uses `lodahs` (lodash typosquat), the same
# canary SocketDev's own workflows use:
# https://github.com/SocketDev/bun-security-scanner/blob/main/.github/workflows/test.yml
# If this job ever stops blocking, either sfw is misconfigured or the
# canary itself has been delisted — swap it for another Socket-flagged
# package from https://socket.dev/blog/category/threat-research.
# vp version is left at the action default (`latest`) — sfw block behavior
# is decoupled from vp's release channel.
# NOTE: if this job is later re-matrixed, restore
# `strategy: { fail-fast: false }` so a flake in one shard doesn't cancel
# the others.
runs-on: ubuntu-latest
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2
- name: Create test project with a benign dependency
shell: bash
run: |
mkdir -p test-project
cd test-project
echo '{"name":"test-project","private":true,"dependencies":{"is-odd":"^3.0.1"}}' > package.json
- name: Setup Vite+ with sfw and install benign dep
uses: ./
with:
sfw: true
run-install: |
- cwd: test-project
cache: false
- name: Assert sfw blocks malicious package (lodahs typosquat of lodash)
shell: bash
working-directory: test-project
# Exit code alone isn't sufficient: a non-zero exit from npm 404,
# network blip, or vp crash would also produce a false positive. We
# also require the literal sfw block-line for lodahs in the combined
# output so an unrelated failure doesn't get reported as "sfw blocked
# it". The block-line format observed in CI is:
# " - blocked npm package: name: lodahs; version: ...; reason: ..."
# The banner "Protected by Socket Firewall" and the "=== Socket
# Firewall ===" header are emitted on EVERY sfw invocation, so neither
# of those is a usable marker — use the unique "blocked npm package:
# name: lodahs" line instead.
run: |
set +e
OUTPUT=$(sfw vp install lodahs 2>&1)
CODE=$?
set -e
printf '%s\n' "$OUTPUT"
if [ "$CODE" -eq 0 ]; then
echo "::error::sfw failed to block lodahs — install exited 0"
exit 1
fi
if ! printf '%s' "$OUTPUT" | grep -qF -- "blocked npm package: name: lodahs"; then
echo "::error::sfw vp install exited $CODE but the lodahs block-line was not in the output — likely failed for a non-sfw reason (canary delisted, network blip, vp crash, or sfw output format changed). Swap the canary if Socket has delisted lodahs, or update the marker grep if sfw's block-line format changed."
exit 1
fi
echo "OK: sfw blocked lodahs (exit $CODE, block-line found)"
test-sfw-with-socketdev-action:
# Exercises the composition path: install sfw via the upstream
# `socketdev/action@<sha>` step first, then call setup-vp with `sfw:
# true`. setup-vp should DETECT the pre-installed sfw on PATH (via
# findSfwOnPath()) and SKIP its bundled download. We assert that by
# checking $RUNNER_TEMP/sfw-bin/sfw[.exe] — the exact path
# installSfw() would have created — was NOT created.
# See README "Advanced: stricter supply chain via socketdev/action".
runs-on: ubuntu-latest
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2
- name: Create test project with a real dependency
shell: bash
run: |
mkdir -p test-project
cd test-project
echo '{"name":"test-project","private":true,"dependencies":{"is-odd":"^3.0.1"}}' > package.json
- name: Install sfw via socketdev/action
uses: socketdev/action@ba6de6cc0565af1f42295590380973573297e31f
with:
mode: firewall-free
- name: Setup Vite+ with sfw (composition path)
uses: ./
id: setup-vp
with:
sfw: true
run-install: |
- cwd: test-project
cache: false
- name: Verify setup-vp used the composed sfw (no bundled download)
shell: bash
# Negative assertion: if setup-vp had downloaded its own sfw, it
# would land at $RUNNER_TEMP/sfw-bin/sfw[.exe] (per
# getSfwBinDir() in install-sfw.ts). On the composition path the
# PATH-detection branch should fire FIRST and skip the download
# entirely, so neither file should exist.
run: |
if [ -e "$RUNNER_TEMP/sfw-bin/sfw" ] || [ -e "$RUNNER_TEMP/sfw-bin/sfw.exe" ]; then
echo "::error::setup-vp downloaded its own sfw binary even though one was pre-installed via socketdev/action. The PATH-detection branch in setupSfw() regressed."
exit 1
fi
echo "OK: setup-vp used the pre-installed sfw (no bundled download at \$RUNNER_TEMP/sfw-bin/)"
- name: Verify dependency installed under composed sfw
working-directory: test-project
run: vp exec node -e "console.log(require('is-odd')(3))"
build:
runs-on: ubuntu-latest
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2
- name: Setup Vite+ with cache
uses: ./
id: setup
with:
cache: true
node-version-file: .node-version
- name: Type check
run: vp run typecheck
- name: Check
run: vp run check
- name: Unit tests
run: vp run test
- name: Build
run: vp run build
- name: Verify dist is up to date
run: |
git diff --exit-code dist/ || (echo "dist/ is out of date. Run 'vp run build' and commit." && exit 1)