Repository navigation
fix(report): clarify scan output and package versions #3439
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: CI | |
| on: | |
| push: | |
| branches: [v1.x] | |
| pull_request: | |
| branches: [v1.x] | |
| workflow_dispatch: | |
| inputs: | |
| refresh-native-cache: | |
| description: Refresh native download cache | |
| type: boolean | |
| required: false | |
| default: false | |
| permissions: | |
| contents: read | |
| cache-mode: read | |
| jobs: | |
| lint: | |
| name: 🧹 Lint Check | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Checkout source | |
| shell: bash | |
| env: | |
| CHECKOUT_REF: ${{ github.sha }} | |
| GITHUB_TOKEN: ${{ github.token }} | |
| SERVER_URL: ${{ github.server_url }} | |
| REPOSITORY: ${{ github.repository }} | |
| run: | | |
| set -euo pipefail | |
| git init -q | |
| git config --local advice.detachedHead false | |
| git remote add origin "${SERVER_URL}/${REPOSITORY}" | |
| AUTH_B64="$(printf 'x-access-token:%s' "$GITHUB_TOKEN" | base64 | tr -d '\n')" | |
| export GIT_CONFIG_COUNT=1 | |
| export GIT_CONFIG_KEY_0="http.${SERVER_URL}/.extraheader" | |
| export GIT_CONFIG_VALUE_0="AUTHORIZATION: basic ${AUTH_B64}" | |
| git fetch --no-tags --depth=1 origin "$CHECKOUT_REF" | |
| git checkout -q --detach FETCH_HEAD | |
| - name: Install zizmor | |
| shell: bash | |
| run: | # zizmor: ignore[github-env] | |
| ZIZMOR_VERSION="1.23.1" | |
| ZIZMOR_DIR="${RUNNER_TEMP:-/tmp}/zizmor-bin" | |
| KERNEL="$(uname -s | cut -d- -f1)" | |
| ARCH="$(uname -m)" | |
| case "${KERNEL}-${ARCH}" in | |
| Linux-x86_64) ASSET="zizmor-x86_64-unknown-linux-gnu.tar.gz" ; EXPECTED_SHA256="67a8df0a14352dd81882e14876653d097b99b0f4f6b6fe798edc0320cff27aff" ;; | |
| Linux-aarch64) ASSET="zizmor-aarch64-unknown-linux-gnu.tar.gz" ; EXPECTED_SHA256="3725d7cd7102e4d70827186389f7d5930b6878232930d0a3eb058d7e5b47e658" ;; | |
| Darwin-x86_64) ASSET="zizmor-x86_64-apple-darwin.tar.gz" ; EXPECTED_SHA256="89d5ed42081dd9d0433a10b7545fac42b35f1f030885c278b9712b32c66f2597" ;; | |
| Darwin-arm64) ASSET="zizmor-aarch64-apple-darwin.tar.gz" ; EXPECTED_SHA256="2632561b974c69f952258c1ab4b7432d5c7f92e555704155c3ac28a2910bd717" ;; | |
| MINGW64_NT-x86_64|MSYS_NT-x86_64) ASSET="zizmor-x86_64-pc-windows-msvc.zip" ; EXPECTED_SHA256="33c2293ff02834720dd7cd8b47348aafb2e95a19bdc993c0ecaca9c804ade92a" ;; | |
| *) echo "Unsupported platform: ${KERNEL}-${ARCH}" >&2; exit 1 ;; | |
| esac | |
| ZIZMOR_BIN="$ZIZMOR_DIR/zizmor" | |
| [[ "$ASSET" == *.zip ]] && ZIZMOR_BIN="$ZIZMOR_DIR/zizmor.exe" | |
| if [ ! -x "$ZIZMOR_BIN" ]; then | |
| mkdir -p "$ZIZMOR_DIR" | |
| DOWNLOAD_URL="https://github.com/woodruffw/zizmor/releases/download/v${ZIZMOR_VERSION}/${ASSET}" | |
| DOWNLOAD_FILE="${ZIZMOR_DIR}/${ASSET}" | |
| curl -fsSL -o "$DOWNLOAD_FILE" "$DOWNLOAD_URL" | |
| ACTUAL_SHA256="$( (sha256sum "$DOWNLOAD_FILE" 2>/dev/null || shasum -a 256 "$DOWNLOAD_FILE") | cut -d' ' -f1 | tr -d '\\')" | |
| if [ "$ACTUAL_SHA256" != "$EXPECTED_SHA256" ]; then | |
| echo "Checksum mismatch for ${ASSET}!" >&2 | |
| echo " Expected: ${EXPECTED_SHA256}" >&2 | |
| echo " Actual: ${ACTUAL_SHA256}" >&2 | |
| exit 1 | |
| fi | |
| if [[ "$ASSET" == *.zip ]]; then | |
| unzip -qo "$DOWNLOAD_FILE" -d "$ZIZMOR_DIR" | |
| else | |
| tar xzf "$DOWNLOAD_FILE" -C "$ZIZMOR_DIR" | |
| fi | |
| rm -f "$DOWNLOAD_FILE" | |
| chmod +x "$ZIZMOR_BIN" | |
| fi | |
| echo "$ZIZMOR_DIR" >> "${GITHUB_PATH:-/dev/null}" | |
| - name: Audit GitHub Actions | |
| shell: bash | |
| env: | |
| GITHUB_TOKEN: ${{ github.token }} | |
| run: | | |
| if [ -d .github ]; then | |
| # Exit 0 = clean, 13 = warnings only, 14+ = errors. | |
| zizmor .github --gh-token "${GITHUB_TOKEN}" --min-severity medium || { | |
| exit_code=$? | |
| if [ "$exit_code" -ne 13 ]; then exit "$exit_code"; fi | |
| } | |
| fi | |
| - name: Install pnpm | |
| shell: bash | |
| run: | # zizmor: ignore[github-env] | |
| PNPM_VERSION="10.33.0" | |
| PNPM_DIR="${RUNNER_TEMP:-/tmp}/pnpm-bin" | |
| KERNEL="$(uname -s | cut -d- -f1)" | |
| ARCH="$(uname -m)" | |
| case "${KERNEL}-${ARCH}" in | |
| Linux-x86_64) ASSET="pnpm-linux-x64" ; EXPECTED_SHA256="8d4e8f7d778e8ac482022e2577011706a872542f6f6f233e795a4d9f978ea8b5" ;; | |
| Linux-aarch64) ASSET="pnpm-linux-arm64" ; EXPECTED_SHA256="06755ad2817548b84317d857d5c8003dc6e9e28416a3ea7467256c49ab400d48" ;; | |
| Darwin-x86_64) ASSET="pnpm-macos-x64" ; EXPECTED_SHA256="c31e29554b0e3f4e03f4617195c949595e4dca36085922003de4896c3ca4057d" ;; | |
| Darwin-arm64) ASSET="pnpm-macos-arm64" ; EXPECTED_SHA256="ed8a1f140f4de457b01ebe0be3ae28e9a7e28863315dcd53d22ff1e5a32d63ae" ;; | |
| MINGW64_NT-x86_64|MSYS_NT-x86_64) ASSET="pnpm-win-x64.exe" ; EXPECTED_SHA256="afc96009dc39fe23a835d65192049e6a995f342496b175585dc2beda7d42d33f" ;; | |
| *) echo "Unsupported platform: ${KERNEL}-${ARCH}" >&2; exit 1 ;; | |
| esac | |
| PNPM_BIN="$PNPM_DIR/$ASSET" | |
| if [ ! -x "$PNPM_BIN" ]; then | |
| mkdir -p "$PNPM_DIR" | |
| curl -fsSL -o "$PNPM_BIN" "https://github.com/pnpm/pnpm/releases/download/v${PNPM_VERSION}/${ASSET}" | |
| ACTUAL_SHA256="$( (sha256sum "$PNPM_BIN" 2>/dev/null || shasum -a 256 "$PNPM_BIN") | cut -d' ' -f1 | tr -d '\\')" | |
| if [ "$ACTUAL_SHA256" != "$EXPECTED_SHA256" ]; then | |
| echo "Checksum mismatch for ${ASSET}!" >&2 | |
| echo " Expected: ${EXPECTED_SHA256}" >&2 | |
| echo " Actual: ${ACTUAL_SHA256}" >&2 | |
| rm -f "$PNPM_BIN" | |
| exit 1 | |
| fi | |
| chmod +x "$PNPM_BIN" | |
| # Create pnpm alias. Windows needs a .exe copy; Unix uses a symlink. | |
| if [[ "$ASSET" == *.exe ]]; then | |
| cp "$PNPM_BIN" "$PNPM_DIR/pnpm.exe" | |
| else | |
| ln -sf "$PNPM_BIN" "$PNPM_DIR/pnpm" | |
| fi | |
| fi | |
| echo "$PNPM_DIR" >> "${GITHUB_PATH:-/dev/null}" | |
| - name: Install Node.js | |
| shell: bash | |
| env: | |
| NODE_VERSION: 26.13.0 | |
| run: node scripts/ci/setup-node.mjs --version "$NODE_VERSION" | |
| - name: Download sfw | |
| shell: bash | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| SOCKET_API_KEY: ${{ secrets.SOCKET_API_TOKEN_FOR_CLI_AND_SFW }} # zizmor: ignore[secrets-outside-env] | |
| run: | # zizmor: ignore[github-env] | |
| # Pinned version + per-platform checksum pairs. Bumping a tool | |
| # requires updating the matching version AND every platform's | |
| # SHA256 in the same commit, otherwise the download / verify | |
| # steps will diverge. | |
| SFW_FREE_VERSION="1.15.0" | |
| SFW_ENTERPRISE_VERSION="1.15.0" | |
| SFW_DIR="${RUNNER_TEMP:-/tmp}/sfw-bin" | |
| KERNEL="$(uname -s | cut -d- -f1)" | |
| ARCH="$(uname -m)" | |
| USE_ENTERPRISE=false | |
| [ -n "$SOCKET_API_KEY" ] && USE_ENTERPRISE=true | |
| if [ "$USE_ENTERPRISE" = "true" ]; then | |
| REPO="SocketDev/firewall-release" | |
| SFW_VERSION="$SFW_ENTERPRISE_VERSION" | |
| case "${KERNEL}-${ARCH}" in | |
| Linux-x86_64) ASSET="sfw-linux-x86_64" ; SFW_BIN="$SFW_DIR/sfw" ; EXPECTED_SHA256="5d33de4859e5138633592fb49a62fb9ac520a6a16211100d21bcb871a9b2d77f" ;; | |
| Linux-aarch64) ASSET="sfw-linux-arm64" ; SFW_BIN="$SFW_DIR/sfw" ; EXPECTED_SHA256="4cc5c51eb224cfa1c9819c218cc39753bce5273e89a50dfd226d8d71449bfd95" ;; | |
| Darwin-x86_64) ASSET="sfw-macos-x86_64" ; SFW_BIN="$SFW_DIR/sfw" ; EXPECTED_SHA256="fc39d500171dfa53eba26e4f59dfd187f3ae47094b8d3a54b7ac53df1c770245" ;; | |
| Darwin-arm64) ASSET="sfw-macos-arm64" ; SFW_BIN="$SFW_DIR/sfw" ; EXPECTED_SHA256="98c87f9316a3caf67f33bb065f6b08123ae90325164535cf5b692cb1024cb64e" ;; | |
| MINGW64_NT-x86_64|MSYS_NT-x86_64) ASSET="sfw-windows-x86_64.exe" ; SFW_BIN="$SFW_DIR/sfw.exe" ; EXPECTED_SHA256="7869366709d7ca25c096ec0bcd98f5b69d9f2f13c4c0964dd5b8f656d0fb4359" ;; | |
| *) echo "Unsupported platform: ${KERNEL}-${ARCH}" >&2; exit 1 ;; | |
| esac | |
| else | |
| REPO="SocketDev/sfw-free" | |
| SFW_VERSION="$SFW_FREE_VERSION" | |
| case "${KERNEL}-${ARCH}" in | |
| Linux-x86_64) ASSET="sfw-free-linux-x86_64" ; SFW_BIN="$SFW_DIR/sfw" ; EXPECTED_SHA256="c80371910a808ea5c68916c48e5451716a91ca411cf5e422fdbd8119729b742c" ;; | |
| Linux-aarch64) ASSET="sfw-free-linux-arm64" ; SFW_BIN="$SFW_DIR/sfw" ; EXPECTED_SHA256="55671fa409ef3d40fcee66acbba4d7acfff8a5332d349ad47cca809ebf473cd0" ;; | |
| Darwin-x86_64) ASSET="sfw-free-macos-x86_64" ; SFW_BIN="$SFW_DIR/sfw" ; EXPECTED_SHA256="07cfcc9805812130ebca07f73c51c2cd9c0181b394f25be4c969c0d31c9dc26f" ;; | |
| Darwin-arm64) ASSET="sfw-free-macos-arm64" ; SFW_BIN="$SFW_DIR/sfw" ; EXPECTED_SHA256="fa473291b8b76220f4b636cf655e8a4dc03332145bdea3acfd9bc96887b2da20" ;; | |
| MINGW64_NT-x86_64|MSYS_NT-x86_64) ASSET="sfw-free-windows-x86_64.exe" ; SFW_BIN="$SFW_DIR/sfw.exe" ; EXPECTED_SHA256="029882f10e1020c96353b184ec0dba7da853e0f6d35131ca930515a7e61e89e6" ;; | |
| *) echo "Unsupported platform: ${KERNEL}-${ARCH}" >&2; exit 1 ;; | |
| esac | |
| fi | |
| if [ ! -x "$SFW_BIN" ]; then | |
| mkdir -p "$SFW_DIR" | |
| DOWNLOAD_URL="$(gh api "repos/${REPO}/releases/tags/v${SFW_VERSION}" \ | |
| --jq ".assets[] | select(.name == \"$ASSET\") | .browser_download_url")" | |
| if [ -z "$DOWNLOAD_URL" ]; then | |
| echo "Asset ${ASSET} not found in ${REPO}@v${SFW_VERSION}" >&2 | |
| exit 1 | |
| fi | |
| curl -fsSL -o "$SFW_BIN" "$DOWNLOAD_URL" | |
| ACTUAL_SHA256="$( (sha256sum "$SFW_BIN" 2>/dev/null || shasum -a 256 "$SFW_BIN") | cut -d' ' -f1 | tr -d '\\')" | |
| if [ "$ACTUAL_SHA256" != "$EXPECTED_SHA256" ]; then | |
| echo "Checksum mismatch for ${ASSET} (${REPO}@v${SFW_VERSION})!" >&2 | |
| echo " Expected: ${EXPECTED_SHA256}" >&2 | |
| echo " Actual: ${ACTUAL_SHA256}" >&2 | |
| rm -f "$SFW_BIN" | |
| exit 1 | |
| fi | |
| chmod +x "$SFW_BIN" | |
| fi | |
| echo "SFW_BIN=$SFW_BIN" >> "${GITHUB_ENV:-/dev/null}" | |
| echo "SFW_IS_ENTERPRISE=$USE_ENTERPRISE" >> "${GITHUB_ENV:-/dev/null}" | |
| if [ "$USE_ENTERPRISE" = "true" ]; then | |
| echo "SOCKET_API_KEY=$SOCKET_API_KEY" >> "${GITHUB_ENV:-/dev/null}" | |
| fi | |
| - name: Create sfw shims | |
| shell: bash | |
| run: | # zizmor: ignore[github-env] | |
| SHIM_DIR="${RUNNER_TEMP:-/tmp}/sfw-shim" | |
| rm -rf "$SHIM_DIR" | |
| mkdir -p "$SHIM_DIR" | |
| IS_WINDOWS=false | |
| [[ "$OSTYPE" == msys* || "$OSTYPE" == cygwin* ]] && IS_WINDOWS=true | |
| msys_to_win_path() { | |
| if $IS_WINDOWS && [[ "$1" =~ ^/([a-zA-Z])/(.*) ]]; then | |
| echo "${BASH_REMATCH[1]^^}:\\${BASH_REMATCH[2]//\//\\}" | |
| else | |
| echo "$1" | |
| fi | |
| } | |
| strip_shim_dir() { echo "$PATH" | tr ':' '\n' | grep -vxF "$SHIM_DIR" | paste -sd: -; } | |
| CLEAN_PATH="$(strip_shim_dir)" | |
| # Wrapper mode ecosystems (sfw-free): | |
| # JavaScript/TypeScript: npm, yarn, pnpm | |
| # Python: pip, uv | |
| # Rust: cargo | |
| # https://github.com/SocketDev/sfw-free?tab=readme-ov-file#supported-package-managers | |
| # | |
| # Additional wrapper mode ecosystems (sfw-enterprise): | |
| # Ruby: gem, bundler | |
| # .NET: nuget | |
| # Go: go (Linux only) | |
| # https://github.com/SocketDev/firewall-release/wiki#support-matrix | |
| SSL_WORKAROUND="" | |
| SHIM_CMDS="npm yarn pnpm pip uv cargo" | |
| if [ "$SFW_IS_ENTERPRISE" = "true" ]; then | |
| SHIM_CMDS="npm yarn pnpm pip uv cargo gem bundler nuget" | |
| # Go wrapper mode is only supported on Linux. | |
| [[ "$OSTYPE" == linux* ]] && SHIM_CMDS="$SHIM_CMDS go" | |
| else | |
| SSL_WORKAROUND='export GIT_SSL_NO_VERIFY=true # Workaround: sfw-free does not yet set GIT_SSL_CAINFO.' | |
| fi | |
| for CMD in $SHIM_CMDS; do | |
| REAL="$(PATH="$CLEAN_PATH" command -v "$CMD" 2>/dev/null || true)" | |
| [ -z "$REAL" ] && continue | |
| REAL="$(msys_to_win_path "$REAL")" | |
| SHIM_LINES=('#!/bin/bash' "export PATH=\"\$(echo \"\$PATH\" | tr ':' '\n' | grep -vxF '${SHIM_DIR}' | paste -sd: -)\"") | |
| [ -n "$SSL_WORKAROUND" ] && SHIM_LINES+=("$SSL_WORKAROUND") | |
| SHIM_LINES+=("exec \"${SFW_BIN}\" \"${REAL}\" \"\$@\"") | |
| printf '%s\n' "${SHIM_LINES[@]}" > "$SHIM_DIR/$CMD" | |
| chmod +x "$SHIM_DIR/$CMD" | |
| if $IS_WINDOWS; then | |
| printf '@echo off\r\nset "PATH=;%%PATH%%;"\r\nset "PATH=%%PATH:;%s;=;%%"\r\nset "PATH=%%PATH:~1,-1%%"\r\n"%s" "%s" %%*\r\n' \ | |
| "$SHIM_DIR" "$SFW_BIN" "$REAL" > "$SHIM_DIR/$CMD.cmd" | |
| fi | |
| done | |
| echo "$SHIM_DIR" >> "${GITHUB_PATH:-/dev/null}" | |
| echo "SFW_SHIM_DIR=$SHIM_DIR" >> "${GITHUB_ENV:-/dev/null}" | |
| - name: Install dependencies | |
| run: pnpm install --loglevel error | |
| - name: Lint | |
| run: | | |
| pnpm run check:actions | |
| pnpm check:lint | |
| typecheck: | |
| name: 🔍 Type Check | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Checkout source | |
| shell: bash | |
| env: | |
| CHECKOUT_REF: ${{ github.sha }} | |
| GITHUB_TOKEN: ${{ github.token }} | |
| SERVER_URL: ${{ github.server_url }} | |
| REPOSITORY: ${{ github.repository }} | |
| run: | | |
| set -euo pipefail | |
| git init -q | |
| git config --local advice.detachedHead false | |
| git remote add origin "${SERVER_URL}/${REPOSITORY}" | |
| AUTH_B64="$(printf 'x-access-token:%s' "$GITHUB_TOKEN" | base64 | tr -d '\n')" | |
| export GIT_CONFIG_COUNT=1 | |
| export GIT_CONFIG_KEY_0="http.${SERVER_URL}/.extraheader" | |
| export GIT_CONFIG_VALUE_0="AUTHORIZATION: basic ${AUTH_B64}" | |
| git fetch --no-tags --depth=1 origin "$CHECKOUT_REF" | |
| git checkout -q --detach FETCH_HEAD | |
| - name: Install pnpm | |
| shell: bash | |
| run: | # zizmor: ignore[github-env] | |
| PNPM_VERSION="10.33.0" | |
| PNPM_DIR="${RUNNER_TEMP:-/tmp}/pnpm-bin" | |
| KERNEL="$(uname -s | cut -d- -f1)" | |
| ARCH="$(uname -m)" | |
| case "${KERNEL}-${ARCH}" in | |
| Linux-x86_64) ASSET="pnpm-linux-x64" ; EXPECTED_SHA256="8d4e8f7d778e8ac482022e2577011706a872542f6f6f233e795a4d9f978ea8b5" ;; | |
| Linux-aarch64) ASSET="pnpm-linux-arm64" ; EXPECTED_SHA256="06755ad2817548b84317d857d5c8003dc6e9e28416a3ea7467256c49ab400d48" ;; | |
| Darwin-x86_64) ASSET="pnpm-macos-x64" ; EXPECTED_SHA256="c31e29554b0e3f4e03f4617195c949595e4dca36085922003de4896c3ca4057d" ;; | |
| Darwin-arm64) ASSET="pnpm-macos-arm64" ; EXPECTED_SHA256="ed8a1f140f4de457b01ebe0be3ae28e9a7e28863315dcd53d22ff1e5a32d63ae" ;; | |
| MINGW64_NT-x86_64|MSYS_NT-x86_64) ASSET="pnpm-win-x64.exe" ; EXPECTED_SHA256="afc96009dc39fe23a835d65192049e6a995f342496b175585dc2beda7d42d33f" ;; | |
| *) echo "Unsupported platform: ${KERNEL}-${ARCH}" >&2; exit 1 ;; | |
| esac | |
| PNPM_BIN="$PNPM_DIR/$ASSET" | |
| if [ ! -x "$PNPM_BIN" ]; then | |
| mkdir -p "$PNPM_DIR" | |
| curl -fsSL -o "$PNPM_BIN" "https://github.com/pnpm/pnpm/releases/download/v${PNPM_VERSION}/${ASSET}" | |
| ACTUAL_SHA256="$( (sha256sum "$PNPM_BIN" 2>/dev/null || shasum -a 256 "$PNPM_BIN") | cut -d' ' -f1 | tr -d '\\')" | |
| if [ "$ACTUAL_SHA256" != "$EXPECTED_SHA256" ]; then | |
| echo "Checksum mismatch for ${ASSET}!" >&2 | |
| echo " Expected: ${EXPECTED_SHA256}" >&2 | |
| echo " Actual: ${ACTUAL_SHA256}" >&2 | |
| rm -f "$PNPM_BIN" | |
| exit 1 | |
| fi | |
| chmod +x "$PNPM_BIN" | |
| # Create pnpm alias. Windows needs a .exe copy; Unix uses a symlink. | |
| if [[ "$ASSET" == *.exe ]]; then | |
| cp "$PNPM_BIN" "$PNPM_DIR/pnpm.exe" | |
| else | |
| ln -sf "$PNPM_BIN" "$PNPM_DIR/pnpm" | |
| fi | |
| fi | |
| echo "$PNPM_DIR" >> "${GITHUB_PATH:-/dev/null}" | |
| - name: Install Node.js | |
| shell: bash | |
| env: | |
| NODE_VERSION: 26.13.0 | |
| run: node scripts/ci/setup-node.mjs --version "$NODE_VERSION" | |
| - name: Download sfw | |
| shell: bash | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| SOCKET_API_KEY: ${{ secrets.SOCKET_API_TOKEN_FOR_CLI_AND_SFW }} # zizmor: ignore[secrets-outside-env] | |
| run: | # zizmor: ignore[github-env] | |
| # Pinned version + per-platform checksum pairs. Bumping a tool | |
| # requires updating the matching version AND every platform's | |
| # SHA256 in the same commit, otherwise the download / verify | |
| # steps will diverge. | |
| SFW_FREE_VERSION="1.15.0" | |
| SFW_ENTERPRISE_VERSION="1.15.0" | |
| SFW_DIR="${RUNNER_TEMP:-/tmp}/sfw-bin" | |
| KERNEL="$(uname -s | cut -d- -f1)" | |
| ARCH="$(uname -m)" | |
| USE_ENTERPRISE=false | |
| [ -n "$SOCKET_API_KEY" ] && USE_ENTERPRISE=true | |
| if [ "$USE_ENTERPRISE" = "true" ]; then | |
| REPO="SocketDev/firewall-release" | |
| SFW_VERSION="$SFW_ENTERPRISE_VERSION" | |
| case "${KERNEL}-${ARCH}" in | |
| Linux-x86_64) ASSET="sfw-linux-x86_64" ; SFW_BIN="$SFW_DIR/sfw" ; EXPECTED_SHA256="5d33de4859e5138633592fb49a62fb9ac520a6a16211100d21bcb871a9b2d77f" ;; | |
| Linux-aarch64) ASSET="sfw-linux-arm64" ; SFW_BIN="$SFW_DIR/sfw" ; EXPECTED_SHA256="4cc5c51eb224cfa1c9819c218cc39753bce5273e89a50dfd226d8d71449bfd95" ;; | |
| Darwin-x86_64) ASSET="sfw-macos-x86_64" ; SFW_BIN="$SFW_DIR/sfw" ; EXPECTED_SHA256="fc39d500171dfa53eba26e4f59dfd187f3ae47094b8d3a54b7ac53df1c770245" ;; | |
| Darwin-arm64) ASSET="sfw-macos-arm64" ; SFW_BIN="$SFW_DIR/sfw" ; EXPECTED_SHA256="98c87f9316a3caf67f33bb065f6b08123ae90325164535cf5b692cb1024cb64e" ;; | |
| MINGW64_NT-x86_64|MSYS_NT-x86_64) ASSET="sfw-windows-x86_64.exe" ; SFW_BIN="$SFW_DIR/sfw.exe" ; EXPECTED_SHA256="7869366709d7ca25c096ec0bcd98f5b69d9f2f13c4c0964dd5b8f656d0fb4359" ;; | |
| *) echo "Unsupported platform: ${KERNEL}-${ARCH}" >&2; exit 1 ;; | |
| esac | |
| else | |
| REPO="SocketDev/sfw-free" | |
| SFW_VERSION="$SFW_FREE_VERSION" | |
| case "${KERNEL}-${ARCH}" in | |
| Linux-x86_64) ASSET="sfw-free-linux-x86_64" ; SFW_BIN="$SFW_DIR/sfw" ; EXPECTED_SHA256="c80371910a808ea5c68916c48e5451716a91ca411cf5e422fdbd8119729b742c" ;; | |
| Linux-aarch64) ASSET="sfw-free-linux-arm64" ; SFW_BIN="$SFW_DIR/sfw" ; EXPECTED_SHA256="55671fa409ef3d40fcee66acbba4d7acfff8a5332d349ad47cca809ebf473cd0" ;; | |
| Darwin-x86_64) ASSET="sfw-free-macos-x86_64" ; SFW_BIN="$SFW_DIR/sfw" ; EXPECTED_SHA256="07cfcc9805812130ebca07f73c51c2cd9c0181b394f25be4c969c0d31c9dc26f" ;; | |
| Darwin-arm64) ASSET="sfw-free-macos-arm64" ; SFW_BIN="$SFW_DIR/sfw" ; EXPECTED_SHA256="fa473291b8b76220f4b636cf655e8a4dc03332145bdea3acfd9bc96887b2da20" ;; | |
| MINGW64_NT-x86_64|MSYS_NT-x86_64) ASSET="sfw-free-windows-x86_64.exe" ; SFW_BIN="$SFW_DIR/sfw.exe" ; EXPECTED_SHA256="029882f10e1020c96353b184ec0dba7da853e0f6d35131ca930515a7e61e89e6" ;; | |
| *) echo "Unsupported platform: ${KERNEL}-${ARCH}" >&2; exit 1 ;; | |
| esac | |
| fi | |
| if [ ! -x "$SFW_BIN" ]; then | |
| mkdir -p "$SFW_DIR" | |
| DOWNLOAD_URL="$(gh api "repos/${REPO}/releases/tags/v${SFW_VERSION}" \ | |
| --jq ".assets[] | select(.name == \"$ASSET\") | .browser_download_url")" | |
| if [ -z "$DOWNLOAD_URL" ]; then | |
| echo "Asset ${ASSET} not found in ${REPO}@v${SFW_VERSION}" >&2 | |
| exit 1 | |
| fi | |
| curl -fsSL -o "$SFW_BIN" "$DOWNLOAD_URL" | |
| ACTUAL_SHA256="$( (sha256sum "$SFW_BIN" 2>/dev/null || shasum -a 256 "$SFW_BIN") | cut -d' ' -f1 | tr -d '\\')" | |
| if [ "$ACTUAL_SHA256" != "$EXPECTED_SHA256" ]; then | |
| echo "Checksum mismatch for ${ASSET} (${REPO}@v${SFW_VERSION})!" >&2 | |
| echo " Expected: ${EXPECTED_SHA256}" >&2 | |
| echo " Actual: ${ACTUAL_SHA256}" >&2 | |
| rm -f "$SFW_BIN" | |
| exit 1 | |
| fi | |
| chmod +x "$SFW_BIN" | |
| fi | |
| echo "SFW_BIN=$SFW_BIN" >> "${GITHUB_ENV:-/dev/null}" | |
| echo "SFW_IS_ENTERPRISE=$USE_ENTERPRISE" >> "${GITHUB_ENV:-/dev/null}" | |
| if [ "$USE_ENTERPRISE" = "true" ]; then | |
| echo "SOCKET_API_KEY=$SOCKET_API_KEY" >> "${GITHUB_ENV:-/dev/null}" | |
| fi | |
| - name: Create sfw shims | |
| shell: bash | |
| run: | # zizmor: ignore[github-env] | |
| SHIM_DIR="${RUNNER_TEMP:-/tmp}/sfw-shim" | |
| rm -rf "$SHIM_DIR" | |
| mkdir -p "$SHIM_DIR" | |
| IS_WINDOWS=false | |
| [[ "$OSTYPE" == msys* || "$OSTYPE" == cygwin* ]] && IS_WINDOWS=true | |
| msys_to_win_path() { | |
| if $IS_WINDOWS && [[ "$1" =~ ^/([a-zA-Z])/(.*) ]]; then | |
| echo "${BASH_REMATCH[1]^^}:\\${BASH_REMATCH[2]//\//\\}" | |
| else | |
| echo "$1" | |
| fi | |
| } | |
| strip_shim_dir() { echo "$PATH" | tr ':' '\n' | grep -vxF "$SHIM_DIR" | paste -sd: -; } | |
| CLEAN_PATH="$(strip_shim_dir)" | |
| # Wrapper mode ecosystems (sfw-free): | |
| # JavaScript/TypeScript: npm, yarn, pnpm | |
| # Python: pip, uv | |
| # Rust: cargo | |
| # https://github.com/SocketDev/sfw-free?tab=readme-ov-file#supported-package-managers | |
| # | |
| # Additional wrapper mode ecosystems (sfw-enterprise): | |
| # Ruby: gem, bundler | |
| # .NET: nuget | |
| # Go: go (Linux only) | |
| # https://github.com/SocketDev/firewall-release/wiki#support-matrix | |
| SSL_WORKAROUND="" | |
| SHIM_CMDS="npm yarn pnpm pip uv cargo" | |
| if [ "$SFW_IS_ENTERPRISE" = "true" ]; then | |
| SHIM_CMDS="npm yarn pnpm pip uv cargo gem bundler nuget" | |
| # Go wrapper mode is only supported on Linux. | |
| [[ "$OSTYPE" == linux* ]] && SHIM_CMDS="$SHIM_CMDS go" | |
| else | |
| SSL_WORKAROUND='export GIT_SSL_NO_VERIFY=true # Workaround: sfw-free does not yet set GIT_SSL_CAINFO.' | |
| fi | |
| for CMD in $SHIM_CMDS; do | |
| REAL="$(PATH="$CLEAN_PATH" command -v "$CMD" 2>/dev/null || true)" | |
| [ -z "$REAL" ] && continue | |
| REAL="$(msys_to_win_path "$REAL")" | |
| SHIM_LINES=('#!/bin/bash' "export PATH=\"\$(echo \"\$PATH\" | tr ':' '\n' | grep -vxF '${SHIM_DIR}' | paste -sd: -)\"") | |
| [ -n "$SSL_WORKAROUND" ] && SHIM_LINES+=("$SSL_WORKAROUND") | |
| SHIM_LINES+=("exec \"${SFW_BIN}\" \"${REAL}\" \"\$@\"") | |
| printf '%s\n' "${SHIM_LINES[@]}" > "$SHIM_DIR/$CMD" | |
| chmod +x "$SHIM_DIR/$CMD" | |
| if $IS_WINDOWS; then | |
| printf '@echo off\r\nset "PATH=;%%PATH%%;"\r\nset "PATH=%%PATH:;%s;=;%%"\r\nset "PATH=%%PATH:~1,-1%%"\r\n"%s" "%s" %%*\r\n' \ | |
| "$SHIM_DIR" "$SFW_BIN" "$REAL" > "$SHIM_DIR/$CMD.cmd" | |
| fi | |
| done | |
| echo "$SHIM_DIR" >> "${GITHUB_PATH:-/dev/null}" | |
| echo "SFW_SHIM_DIR=$SHIM_DIR" >> "${GITHUB_ENV:-/dev/null}" | |
| - name: Install dependencies | |
| run: pnpm install --loglevel error | |
| - name: Type check | |
| run: pnpm check:tsc | |
| test: | |
| name: 🧪 Test Matrix | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 15 | |
| strategy: | |
| fail-fast: true | |
| matrix: | |
| # Node 20 reached end-of-life 2026-03-24; test supported majors only. | |
| node-version: [22, 24, 26.13.0] | |
| os: [ubuntu-latest] | |
| steps: | |
| - name: Checkout source | |
| shell: bash | |
| env: | |
| CHECKOUT_REF: ${{ github.sha }} | |
| GITHUB_TOKEN: ${{ github.token }} | |
| SERVER_URL: ${{ github.server_url }} | |
| REPOSITORY: ${{ github.repository }} | |
| run: | | |
| set -euo pipefail | |
| git init -q | |
| git config --local advice.detachedHead false | |
| git remote add origin "${SERVER_URL}/${REPOSITORY}" | |
| AUTH_B64="$(printf 'x-access-token:%s' "$GITHUB_TOKEN" | base64 | tr -d '\n')" | |
| export GIT_CONFIG_COUNT=1 | |
| export GIT_CONFIG_KEY_0="http.${SERVER_URL}/.extraheader" | |
| export GIT_CONFIG_VALUE_0="AUTHORIZATION: basic ${AUTH_B64}" | |
| git fetch --no-tags --depth=1 origin "$CHECKOUT_REF" | |
| git checkout -q --detach FETCH_HEAD | |
| - name: Install pnpm | |
| shell: bash | |
| run: | # zizmor: ignore[github-env] | |
| PNPM_VERSION="10.33.0" | |
| PNPM_DIR="${RUNNER_TEMP:-/tmp}/pnpm-bin" | |
| KERNEL="$(uname -s | cut -d- -f1)" | |
| ARCH="$(uname -m)" | |
| case "${KERNEL}-${ARCH}" in | |
| Linux-x86_64) ASSET="pnpm-linux-x64" ; EXPECTED_SHA256="8d4e8f7d778e8ac482022e2577011706a872542f6f6f233e795a4d9f978ea8b5" ;; | |
| Linux-aarch64) ASSET="pnpm-linux-arm64" ; EXPECTED_SHA256="06755ad2817548b84317d857d5c8003dc6e9e28416a3ea7467256c49ab400d48" ;; | |
| Darwin-x86_64) ASSET="pnpm-macos-x64" ; EXPECTED_SHA256="c31e29554b0e3f4e03f4617195c949595e4dca36085922003de4896c3ca4057d" ;; | |
| Darwin-arm64) ASSET="pnpm-macos-arm64" ; EXPECTED_SHA256="ed8a1f140f4de457b01ebe0be3ae28e9a7e28863315dcd53d22ff1e5a32d63ae" ;; | |
| MINGW64_NT-x86_64|MSYS_NT-x86_64) ASSET="pnpm-win-x64.exe" ; EXPECTED_SHA256="afc96009dc39fe23a835d65192049e6a995f342496b175585dc2beda7d42d33f" ;; | |
| *) echo "Unsupported platform: ${KERNEL}-${ARCH}" >&2; exit 1 ;; | |
| esac | |
| PNPM_BIN="$PNPM_DIR/$ASSET" | |
| if [ ! -x "$PNPM_BIN" ]; then | |
| mkdir -p "$PNPM_DIR" | |
| curl -fsSL -o "$PNPM_BIN" "https://github.com/pnpm/pnpm/releases/download/v${PNPM_VERSION}/${ASSET}" | |
| ACTUAL_SHA256="$( (sha256sum "$PNPM_BIN" 2>/dev/null || shasum -a 256 "$PNPM_BIN") | cut -d' ' -f1 | tr -d '\\')" | |
| if [ "$ACTUAL_SHA256" != "$EXPECTED_SHA256" ]; then | |
| echo "Checksum mismatch for ${ASSET}!" >&2 | |
| echo " Expected: ${EXPECTED_SHA256}" >&2 | |
| echo " Actual: ${ACTUAL_SHA256}" >&2 | |
| rm -f "$PNPM_BIN" | |
| exit 1 | |
| fi | |
| chmod +x "$PNPM_BIN" | |
| # Create pnpm alias. Windows needs a .exe copy; Unix uses a symlink. | |
| if [[ "$ASSET" == *.exe ]]; then | |
| cp "$PNPM_BIN" "$PNPM_DIR/pnpm.exe" | |
| else | |
| ln -sf "$PNPM_BIN" "$PNPM_DIR/pnpm" | |
| fi | |
| fi | |
| echo "$PNPM_DIR" >> "${GITHUB_PATH:-/dev/null}" | |
| - name: Install Node.js | |
| shell: bash | |
| env: | |
| NODE_VERSION: ${{ matrix.node-version }} | |
| run: node scripts/ci/setup-node.mjs --version "$NODE_VERSION" | |
| - name: Download sfw | |
| shell: bash | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| SOCKET_API_KEY: ${{ secrets.SOCKET_API_TOKEN_FOR_CLI_AND_SFW }} # zizmor: ignore[secrets-outside-env] | |
| run: | # zizmor: ignore[github-env] | |
| # Pinned version + per-platform checksum pairs. Bumping a tool | |
| # requires updating the matching version AND every platform's | |
| # SHA256 in the same commit, otherwise the download / verify | |
| # steps will diverge. | |
| SFW_FREE_VERSION="1.15.0" | |
| SFW_ENTERPRISE_VERSION="1.15.0" | |
| SFW_DIR="${RUNNER_TEMP:-/tmp}/sfw-bin" | |
| KERNEL="$(uname -s | cut -d- -f1)" | |
| ARCH="$(uname -m)" | |
| USE_ENTERPRISE=false | |
| [ -n "$SOCKET_API_KEY" ] && USE_ENTERPRISE=true | |
| if [ "$USE_ENTERPRISE" = "true" ]; then | |
| REPO="SocketDev/firewall-release" | |
| SFW_VERSION="$SFW_ENTERPRISE_VERSION" | |
| case "${KERNEL}-${ARCH}" in | |
| Linux-x86_64) ASSET="sfw-linux-x86_64" ; SFW_BIN="$SFW_DIR/sfw" ; EXPECTED_SHA256="5d33de4859e5138633592fb49a62fb9ac520a6a16211100d21bcb871a9b2d77f" ;; | |
| Linux-aarch64) ASSET="sfw-linux-arm64" ; SFW_BIN="$SFW_DIR/sfw" ; EXPECTED_SHA256="4cc5c51eb224cfa1c9819c218cc39753bce5273e89a50dfd226d8d71449bfd95" ;; | |
| Darwin-x86_64) ASSET="sfw-macos-x86_64" ; SFW_BIN="$SFW_DIR/sfw" ; EXPECTED_SHA256="fc39d500171dfa53eba26e4f59dfd187f3ae47094b8d3a54b7ac53df1c770245" ;; | |
| Darwin-arm64) ASSET="sfw-macos-arm64" ; SFW_BIN="$SFW_DIR/sfw" ; EXPECTED_SHA256="98c87f9316a3caf67f33bb065f6b08123ae90325164535cf5b692cb1024cb64e" ;; | |
| MINGW64_NT-x86_64|MSYS_NT-x86_64) ASSET="sfw-windows-x86_64.exe" ; SFW_BIN="$SFW_DIR/sfw.exe" ; EXPECTED_SHA256="7869366709d7ca25c096ec0bcd98f5b69d9f2f13c4c0964dd5b8f656d0fb4359" ;; | |
| *) echo "Unsupported platform: ${KERNEL}-${ARCH}" >&2; exit 1 ;; | |
| esac | |
| else | |
| REPO="SocketDev/sfw-free" | |
| SFW_VERSION="$SFW_FREE_VERSION" | |
| case "${KERNEL}-${ARCH}" in | |
| Linux-x86_64) ASSET="sfw-free-linux-x86_64" ; SFW_BIN="$SFW_DIR/sfw" ; EXPECTED_SHA256="c80371910a808ea5c68916c48e5451716a91ca411cf5e422fdbd8119729b742c" ;; | |
| Linux-aarch64) ASSET="sfw-free-linux-arm64" ; SFW_BIN="$SFW_DIR/sfw" ; EXPECTED_SHA256="55671fa409ef3d40fcee66acbba4d7acfff8a5332d349ad47cca809ebf473cd0" ;; | |
| Darwin-x86_64) ASSET="sfw-free-macos-x86_64" ; SFW_BIN="$SFW_DIR/sfw" ; EXPECTED_SHA256="07cfcc9805812130ebca07f73c51c2cd9c0181b394f25be4c969c0d31c9dc26f" ;; | |
| Darwin-arm64) ASSET="sfw-free-macos-arm64" ; SFW_BIN="$SFW_DIR/sfw" ; EXPECTED_SHA256="fa473291b8b76220f4b636cf655e8a4dc03332145bdea3acfd9bc96887b2da20" ;; | |
| MINGW64_NT-x86_64|MSYS_NT-x86_64) ASSET="sfw-free-windows-x86_64.exe" ; SFW_BIN="$SFW_DIR/sfw.exe" ; EXPECTED_SHA256="029882f10e1020c96353b184ec0dba7da853e0f6d35131ca930515a7e61e89e6" ;; | |
| *) echo "Unsupported platform: ${KERNEL}-${ARCH}" >&2; exit 1 ;; | |
| esac | |
| fi | |
| if [ ! -x "$SFW_BIN" ]; then | |
| mkdir -p "$SFW_DIR" | |
| DOWNLOAD_URL="$(gh api "repos/${REPO}/releases/tags/v${SFW_VERSION}" \ | |
| --jq ".assets[] | select(.name == \"$ASSET\") | .browser_download_url")" | |
| if [ -z "$DOWNLOAD_URL" ]; then | |
| echo "Asset ${ASSET} not found in ${REPO}@v${SFW_VERSION}" >&2 | |
| exit 1 | |
| fi | |
| curl -fsSL -o "$SFW_BIN" "$DOWNLOAD_URL" | |
| ACTUAL_SHA256="$( (sha256sum "$SFW_BIN" 2>/dev/null || shasum -a 256 "$SFW_BIN") | cut -d' ' -f1 | tr -d '\\')" | |
| if [ "$ACTUAL_SHA256" != "$EXPECTED_SHA256" ]; then | |
| echo "Checksum mismatch for ${ASSET} (${REPO}@v${SFW_VERSION})!" >&2 | |
| echo " Expected: ${EXPECTED_SHA256}" >&2 | |
| echo " Actual: ${ACTUAL_SHA256}" >&2 | |
| rm -f "$SFW_BIN" | |
| exit 1 | |
| fi | |
| chmod +x "$SFW_BIN" | |
| fi | |
| echo "SFW_BIN=$SFW_BIN" >> "${GITHUB_ENV:-/dev/null}" | |
| echo "SFW_IS_ENTERPRISE=$USE_ENTERPRISE" >> "${GITHUB_ENV:-/dev/null}" | |
| if [ "$USE_ENTERPRISE" = "true" ]; then | |
| echo "SOCKET_API_KEY=$SOCKET_API_KEY" >> "${GITHUB_ENV:-/dev/null}" | |
| fi | |
| - name: Create sfw shims | |
| shell: bash | |
| run: | # zizmor: ignore[github-env] | |
| SHIM_DIR="${RUNNER_TEMP:-/tmp}/sfw-shim" | |
| rm -rf "$SHIM_DIR" | |
| mkdir -p "$SHIM_DIR" | |
| IS_WINDOWS=false | |
| [[ "$OSTYPE" == msys* || "$OSTYPE" == cygwin* ]] && IS_WINDOWS=true | |
| msys_to_win_path() { | |
| if $IS_WINDOWS && [[ "$1" =~ ^/([a-zA-Z])/(.*) ]]; then | |
| echo "${BASH_REMATCH[1]^^}:\\${BASH_REMATCH[2]//\//\\}" | |
| else | |
| echo "$1" | |
| fi | |
| } | |
| strip_shim_dir() { echo "$PATH" | tr ':' '\n' | grep -vxF "$SHIM_DIR" | paste -sd: -; } | |
| CLEAN_PATH="$(strip_shim_dir)" | |
| # Wrapper mode ecosystems (sfw-free): | |
| # JavaScript/TypeScript: npm, yarn, pnpm | |
| # Python: pip, uv | |
| # Rust: cargo | |
| # https://github.com/SocketDev/sfw-free?tab=readme-ov-file#supported-package-managers | |
| # | |
| # Additional wrapper mode ecosystems (sfw-enterprise): | |
| # Ruby: gem, bundler | |
| # .NET: nuget | |
| # Go: go (Linux only) | |
| # https://github.com/SocketDev/firewall-release/wiki#support-matrix | |
| SSL_WORKAROUND="" | |
| SHIM_CMDS="npm yarn pnpm pip uv cargo" | |
| if [ "$SFW_IS_ENTERPRISE" = "true" ]; then | |
| SHIM_CMDS="npm yarn pnpm pip uv cargo gem bundler nuget" | |
| # Go wrapper mode is only supported on Linux. | |
| [[ "$OSTYPE" == linux* ]] && SHIM_CMDS="$SHIM_CMDS go" | |
| else | |
| SSL_WORKAROUND='export GIT_SSL_NO_VERIFY=true # Workaround: sfw-free does not yet set GIT_SSL_CAINFO.' | |
| fi | |
| for CMD in $SHIM_CMDS; do | |
| REAL="$(PATH="$CLEAN_PATH" command -v "$CMD" 2>/dev/null || true)" | |
| [ -z "$REAL" ] && continue | |
| REAL="$(msys_to_win_path "$REAL")" | |
| SHIM_LINES=('#!/bin/bash' "export PATH=\"\$(echo \"\$PATH\" | tr ':' '\n' | grep -vxF '${SHIM_DIR}' | paste -sd: -)\"") | |
| [ -n "$SSL_WORKAROUND" ] && SHIM_LINES+=("$SSL_WORKAROUND") | |
| SHIM_LINES+=("exec \"${SFW_BIN}\" \"${REAL}\" \"\$@\"") | |
| printf '%s\n' "${SHIM_LINES[@]}" > "$SHIM_DIR/$CMD" | |
| chmod +x "$SHIM_DIR/$CMD" | |
| if $IS_WINDOWS; then | |
| printf '@echo off\r\nset "PATH=;%%PATH%%;"\r\nset "PATH=%%PATH:;%s;=;%%"\r\nset "PATH=%%PATH:~1,-1%%"\r\n"%s" "%s" %%*\r\n' \ | |
| "$SHIM_DIR" "$SFW_BIN" "$REAL" > "$SHIM_DIR/$CMD.cmd" | |
| fi | |
| done | |
| echo "$SHIM_DIR" >> "${GITHUB_PATH:-/dev/null}" | |
| echo "SFW_SHIM_DIR=$SHIM_DIR" >> "${GITHUB_ENV:-/dev/null}" | |
| - name: Install dependencies | |
| run: pnpm install --loglevel error | |
| - name: Build and run unit tests | |
| run: pnpm test-ci | |
| native-cli-pr: | |
| name: Native CLI tests • Cache read-only • No Apple signing | |
| if: github.event_name == 'pull_request' && github.base_ref == 'v1.x' | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 60 | |
| concurrency: &native_concurrency | |
| group: native-cli-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }}-${{ matrix.target }} | |
| cancel-in-progress: true | |
| strategy: &native_strategy | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: ubuntu-24.04 | |
| target: linux-x64 | |
| - os: macos-15 | |
| target: darwin-arm64 | |
| - os: windows-2025 | |
| target: win-x64 | |
| steps: &native_steps | |
| - name: Checkout source | |
| shell: bash | |
| env: | |
| CHECKOUT_REF: ${{ github.sha }} | |
| GITHUB_TOKEN: ${{ github.token }} | |
| SERVER_URL: ${{ github.server_url }} | |
| REPOSITORY: ${{ github.repository }} | |
| run: | | |
| set -euo pipefail | |
| git init -q | |
| git config --local advice.detachedHead false | |
| git remote add origin "${SERVER_URL}/${REPOSITORY}" | |
| AUTH_B64="$(printf 'x-access-token:%s' "$GITHUB_TOKEN" | base64 | tr -d '\n')" | |
| export GIT_CONFIG_COUNT=1 | |
| export GIT_CONFIG_KEY_0="http.${SERVER_URL}/.extraheader" | |
| export GIT_CONFIG_VALUE_0="AUTHORIZATION: basic ${AUTH_B64}" | |
| git fetch --no-tags --depth=1 origin "$CHECKOUT_REF" | |
| git checkout -q --detach FETCH_HEAD | |
| - name: Install Node.js 26.13.0 (checksum verified) | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| version=26.13.0 | |
| base="https://nodejs.org/dist/v${version}" | |
| if [[ "$RUNNER_OS" == Windows ]]; then | |
| archive="node-v${version}-win-x64.zip" | |
| curl -fsSLO "$base/$archive" | |
| curl -fsSLO "$base/SHASUMS256.txt" | |
| grep " $archive$" SHASUMS256.txt | sha256sum -c - | |
| mkdir -p "$RUNNER_TEMP/node" | |
| unzip -q "$archive" -d "$RUNNER_TEMP/node" | |
| cygpath -w "$RUNNER_TEMP/node/node-v${version}-win-x64" >> "$GITHUB_PATH" | |
| else | |
| if [[ "$RUNNER_OS" == macOS ]]; then platform=darwin-arm64; else platform=linux-x64; fi | |
| archive="node-v${version}-${platform}.tar.xz" | |
| curl -fsSLO "$base/$archive" | |
| curl -fsSLO "$base/SHASUMS256.txt" | |
| grep " $archive$" SHASUMS256.txt | shasum -a 256 -c - | |
| mkdir -p "$RUNNER_TEMP/node" | |
| tar -xJf "$archive" -C "$RUNNER_TEMP/node" --strip-components=1 | |
| echo "$RUNNER_TEMP/node/bin" >> "$GITHUB_PATH" | |
| fi | |
| if [[ "$RUNNER_OS" == Windows ]]; then "$RUNNER_TEMP/node/node-v${version}-win-x64/node.exe" -e 'if(process.versions.node!=="26.13.0")process.exit(1)'; else "$RUNNER_TEMP/node/bin/node" -e 'if(process.versions.node!=="26.13.0")process.exit(1)'; fi | |
| - name: Install pinned pnpm | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| version=10.33.0 | |
| case "$RUNNER_OS/$RUNNER_ARCH" in | |
| Linux/X64) asset=pnpm-linux-x64; sha=8d4e8f7d778e8ac482022e2577011706a872542f6f6f233e795a4d9f978ea8b5 ;; | |
| macOS/ARM64) asset=pnpm-macos-arm64; sha=ed8a1f140f4de457b01ebe0be3ae28e9a7e28863315dcd53d22ff1e5a32d63ae ;; | |
| Windows/X64) asset=pnpm-win-x64.exe; sha=afc96009dc39fe23a835d65192049e6a995f342496b175585dc2beda7d42d33f ;; | |
| *) echo "Unsupported runner: $RUNNER_OS/$RUNNER_ARCH" >&2; exit 1 ;; | |
| esac | |
| dir="$RUNNER_TEMP/pnpm-bin" | |
| mkdir -p "$dir" | |
| curl -fsSL "https://github.com/pnpm/pnpm/releases/download/v${version}/${asset}" -o "$dir/$asset" | |
| actual=$( (sha256sum "$dir/$asset" 2>/dev/null || shasum -a 256 "$dir/$asset") | cut -d' ' -f1 | tr -d '\134') | |
| [[ "$actual" == "$sha" ]] || { echo "pnpm checksum mismatch" >&2; exit 1; } | |
| if [[ "$asset" == *.exe ]]; then cp "$dir/$asset" "$dir/pnpm.exe"; else chmod +x "$dir/$asset"; ln -sf "$asset" "$dir/pnpm"; fi | |
| if [[ "$RUNNER_OS" == Windows ]]; then dir=$(cygpath -w "$dir"); fi | |
| echo "$dir" >> "$GITHUB_PATH" | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Restore pinned SEA download cache | |
| id: sea-download-cache | |
| uses: ./.github/actions/repo/cache-downloads | |
| with: | |
| mode: restore | |
| path: ~/.cache/socket-sea/downloads/v1/blobs | |
| key: sea-downloads-v1-${{ matrix.target }}-${{ hashFiles('pnpm-lock.yaml', 'src/sea/uv-pins.json', 'src/sea/build-sea.mts') }}${{ inputs.refresh-native-cache && format('-refresh-{0}-{1}', github.run_id, github.run_attempt) || '' }} | |
| restore-keys: | | |
| sea-downloads-v1-${{ matrix.target }}- | |
| - name: Test screenshot and signing helpers | |
| shell: bash | |
| run: | | |
| pnpm exec vitest run --config .config/vitest.config.mts test/unit/scripts/test/apple-signing.test.mts | |
| pnpm exec vitest run --config .config/vitest.terminal.config.mts | |
| - name: Verify .NET SDK | |
| shell: bash | |
| run: dotnet --list-sdks | awk -F. '$1 >= 8 { found=1 } END { exit !found }' | |
| - name: Build prototype native executable | |
| env: | |
| NODE_OPTIONS: ${{ matrix.target == 'darwin-arm64' && '--max-old-space-size=4096' || '' }} | |
| run: pnpm build:sea --prototype | |
| - name: Save pinned SEA download cache | |
| if: success() && steps.sea-download-cache.outputs.cache-hit != 'true' && github.repository == 'SocketDev/socket-cli' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/v1.x' || github.ref == 'refs/heads/feat/v1x-node27-sea-vfs-socket' || startsWith(github.ref, 'refs/heads/test/native-terminal-validation-')) | |
| uses: ./.github/actions/repo/cache-downloads | |
| with: | |
| mode: save | |
| path: ~/.cache/socket-sea/downloads/v1/blobs | |
| key: sea-downloads-v1-${{ matrix.target }}-${{ hashFiles('pnpm-lock.yaml', 'src/sea/uv-pins.json', 'src/sea/build-sea.mts') }}${{ inputs.refresh-native-cache && format('-refresh-{0}-{1}', github.run_id, github.run_attempt) || '' }} | |
| - name: Run native screenshot tests | |
| shell: bash | |
| env: | |
| SOCKET_CLI_NATIVE_TEST_ARTIFACTS: build/native-test-artifacts/${{ matrix.target }} | |
| APPLE_DEVELOPER_ID_IDENTITY: ${{ matrix.target == 'darwin-arm64' && github.event_name != 'pull_request' && github.repository == 'SocketDev/socket-cli' && (github.ref == 'refs/heads/v1.x' || github.ref == 'refs/heads/feat/v1x-node27-sea-vfs-socket' || startsWith(github.ref, 'refs/heads/test/native-terminal-validation-')) && secrets.APPLE_DEVELOPER_ID_IDENTITY || '' }} | |
| APPLE_TEAM_ID: ${{ matrix.target == 'darwin-arm64' && github.event_name != 'pull_request' && github.repository == 'SocketDev/socket-cli' && (github.ref == 'refs/heads/v1.x' || github.ref == 'refs/heads/feat/v1x-node27-sea-vfs-socket' || startsWith(github.ref, 'refs/heads/test/native-terminal-validation-')) && secrets.APPLE_TEAM_ID || '' }} | |
| APPLE_DEVELOPER_ID_APPLICATION_CERTS_P12: ${{ matrix.target == 'darwin-arm64' && github.event_name != 'pull_request' && github.repository == 'SocketDev/socket-cli' && (github.ref == 'refs/heads/v1.x' || github.ref == 'refs/heads/feat/v1x-node27-sea-vfs-socket' || startsWith(github.ref, 'refs/heads/test/native-terminal-validation-')) && secrets.APPLE_DEVELOPER_ID_APPLICATION_CERTS_P12 || '' }} | |
| APPLE_DEVELOPER_ID_APPLICATION_CERTS_P12_PASS: ${{ matrix.target == 'darwin-arm64' && github.event_name != 'pull_request' && github.repository == 'SocketDev/socket-cli' && (github.ref == 'refs/heads/v1.x' || github.ref == 'refs/heads/feat/v1x-node27-sea-vfs-socket' || startsWith(github.ref, 'refs/heads/test/native-terminal-validation-')) && secrets.APPLE_DEVELOPER_ID_APPLICATION_CERTS_P12_PASS || '' }} | |
| SOCKET_CLI_NATIVE_TEST_REQUIRE_APPLE_SIGNATURE: ${{ matrix.target == 'darwin-arm64' && github.event_name != 'pull_request' && github.repository == 'SocketDev/socket-cli' && (github.ref == 'refs/heads/v1.x' || github.ref == 'refs/heads/feat/v1x-node27-sea-vfs-socket' || startsWith(github.ref, 'refs/heads/test/native-terminal-validation-')) && (secrets.APPLE_DEVELOPER_ID_IDENTITY != '' || secrets.APPLE_TEAM_ID != '' || secrets.APPLE_DEVELOPER_ID_APPLICATION_CERTS_P12 != '' || secrets.APPLE_DEVELOPER_ID_APPLICATION_CERTS_P12_PASS != '') && '1' || '' }} | |
| run: | | |
| set -euo pipefail | |
| export SOCKET_CLI_NATIVE_TEST_ARTIFACTS | |
| rm -rf "$SOCKET_CLI_NATIVE_TEST_ARTIFACTS" | |
| mkdir -p "$SOCKET_CLI_NATIVE_TEST_ARTIFACTS" | |
| if pnpm test:native test/native/commands/cli.native.test.mts test/native/commands/cli-behavior.native.test.mts test/native/commands/tui.native.test.mts; then result=0; else result=$?; fi | |
| if [[ $result == 0 ]]; then status=passed; else status=failed; fi | |
| export TEST_STATUS="$status" TEST_EXIT_CODE="$result" TEST_PLATFORM="$RUNNER_OS/$RUNNER_ARCH" | |
| node -e 'const fs=require("node:fs"); let receipt={}; try { receipt=JSON.parse(fs.readFileSync(process.env.SOCKET_CLI_NATIVE_TEST_ARTIFACTS+"/signing-receipt.json","utf8")); } catch {} process.stdout.write(JSON.stringify({status:process.env.TEST_STATUS,exitCode:Number(process.env.TEST_EXIT_CODE),platform:process.env.TEST_PLATFORM,sourceCommit:process.env.GITHUB_SHA||"unknown",signingMode:receipt.mode||"unknown",sourceSha256:receipt.sourceSha256,binarySha256:receipt.stagedSha256})+"\n")' > "$SOCKET_CLI_NATIVE_TEST_ARTIFACTS/test-result.json" | |
| exit "$result" | |
| - name: Generate self-contained report | |
| if: always() | |
| shell: bash | |
| env: | |
| SOCKET_CLI_NATIVE_TEST_ARTIFACTS: build/native-test-artifacts/${{ matrix.target }} | |
| run: node scripts/test/terminal-report.mts --artifacts "$SOCKET_CLI_NATIVE_TEST_ARTIFACTS" --output "$SOCKET_CLI_NATIVE_TEST_ARTIFACTS/index.html" | |
| native-cli-writer: | |
| name: Native CLI tests • Cache writes • Apple signing available | |
| cache-mode: write | |
| if: github.repository == 'SocketDev/socket-cli' && ((github.event_name == 'push' && (github.ref == 'refs/heads/v1.x' || github.ref == 'refs/heads/feat/v1x-node27-sea-vfs-socket' || startsWith(github.ref, 'refs/heads/test/native-terminal-validation-'))) || (github.event_name == 'workflow_dispatch' && (github.ref == 'refs/heads/v1.x' || github.ref == 'refs/heads/feat/v1x-node27-sea-vfs-socket' || startsWith(github.ref, 'refs/heads/test/native-terminal-validation-')))) | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 60 | |
| concurrency: *native_concurrency | |
| strategy: *native_strategy | |
| steps: *native_steps |