feat: add sfw input to wrap vp install with Socket Firewall Free #265
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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) |