From dc6d6baa776087b6a32266e3f331cee68048fce4 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 18 Oct 2026 17:37:16 +0000 Subject: [PATCH] ci: publish with NPM_TOKEN and run OSV on Mac minis npm trusted publishing does not support self-hosted runners, so the publish job now authenticates with the org-level NPM_TOKEN secret. The OSV scan no longer calls Google's ubuntu-latest reusable workflow; it runs the same v2.3.8 scanner binary on the Mac minis. Co-authored-by: Joe Blau --- .github/scripts/osv-scan.sh | 47 ++++++++++++++++++++ .github/workflows/publish_npm.yml | 25 +++++++++-- .github/workflows/security.yml | 73 +++++++++++++++++-------------- docs/ci-runners.md | 26 ++++++----- 4 files changed, 125 insertions(+), 46 deletions(-) create mode 100755 .github/scripts/osv-scan.sh diff --git a/.github/scripts/osv-scan.sh b/.github/scripts/osv-scan.sh new file mode 100755 index 00000000..35bec8e8 --- /dev/null +++ b/.github/scripts/osv-scan.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# Pin-download OSV-Scanner v2.3.8 for darwin-arm64 and scan the same lockfiles +# as google/osv-scanner-action's reusable workflow. That callee pins +# `runs-on: ubuntu-latest` and a Linux container, so it cannot run on these +# Mac minis. The standalone binary is the same scanner version. +# +# Fail closed on any vulnerability (scanner exit 1). Results stay in the +# workspace so the workflow can upload them even when the scan fails. +set -eu + +VERSION=v2.3.8 +ARCHIVE=osv-scanner_darwin_arm64 +EXPECTED_SHA256=a8cd6507b06239f463a7642430cfd2d154882f150f6e30cdc0653e28dfc34216 +DEST="$RUNNER_TEMP/osv-scanner" +BIN="$DEST/osv-scanner" +RESULTS="${OSV_RESULTS:-$GITHUB_WORKSPACE/osv-results.json}" + +mkdir -p "$DEST" +curl -fsSL "https://github.com/google/osv-scanner/releases/download/${VERSION}/${ARCHIVE}" \ + -o "$BIN" +actual=$(shasum -a 256 "$BIN") +actual=${actual%% *} +if [ "$actual" != "$EXPECTED_SHA256" ]; then + echo "osv-scanner checksum mismatch: got $actual want $EXPECTED_SHA256" >&2 + exit 1 +fi +chmod +x "$BIN" + +# Same lockfiles as security.yml previously passed to the reusable workflow. +# Known residual gap (verified 2026-07-26 against OSV-Scanner v2.4.0): OSV has +# no JSR ecosystem, and @jsr/scope__name aliases do not match npm advisories. +# npm-named packages (the vast majority, including npm transitives) are covered. +set +e +"$BIN" \ + --format json \ + --output "$RESULTS" \ + --lockfile=bun.lock \ + --lockfile=packages/hyperliquid/.dev/ts7/bun.lock +status=$? +set -e + +if [ ! -s "$RESULTS" ]; then + echo "osv-scanner produced no results at $RESULTS" >&2 + exit 1 +fi + +exit "$status" diff --git a/.github/workflows/publish_npm.yml b/.github/workflows/publish_npm.yml index 57ea40c3..1e3b9621 100644 --- a/.github/workflows/publish_npm.yml +++ b/.github/workflows/publish_npm.yml @@ -1,4 +1,9 @@ name: Publish to npm + +# npm trusted publishing does not support self-hosted runners +# (https://docs.npmjs.com/trusted-publishers/). This job authenticates with the +# org-level NPM_TOKEN secret instead. That drops OIDC trusted publishing and +# automatic provenance. on: release: types: [published] @@ -10,17 +15,21 @@ jobs: permissions: contents: read - id-token: write + + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} steps: # Job-level env cannot use the runner context on these Mac minis. - name: Point TMPDIR at runner temp run: echo "TMPDIR=$RUNNER_TEMP" >> "$GITHUB_ENV" - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - # npm publishes via OIDC trusted publishing (no token here), which needs npm >= 11.5.1. + # Token publish uses the same Node 24 / npm CLI surface as before. - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 with: node-version: "24.x" + registry-url: "https://registry.npmjs.org" + package-manager-cache: false # setup-bun writes ~/.bun, shared across runner instances on one Mac mini. - name: Install Bun canary into runner temp run: sh .github/scripts/setup-bun-isolated.sh @@ -47,7 +56,17 @@ jobs: esac echo "value=$TAG" >> "$GITHUB_OUTPUT" + # Fail closed before publish if the org-level secret is not shared with this repo. + # Never print the token. + - name: Verify npm token is present + run: | + if [ -z "$NODE_AUTH_TOKEN" ]; then + echo "NPM_TOKEN is missing. The org-level NPM_TOKEN secret must be shared with this repository." >&2 + exit 1 + fi + + # Scoped packages default to private access (paid); this SDK publishes public. + # Token publish does not attach provenance (trusted publishing is unavailable here). - name: Publish package working-directory: ./packages/hyperliquid/dist - # Scoped packages default to private access (paid); this SDK publishes public. run: npm publish --access public --tag ${{ steps.tag.outputs.value }} diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index f122ef7d..a1aa09f4 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -14,37 +14,46 @@ permissions: jobs: osv-scan: name: OSV-Scanner (dependency vulnerabilities) - permissions: - # Required by the reusable workflow even when SARIF upload is disabled. - actions: read - contents: read - security-events: write - # Not migrated to the Mac mini runners. This reusable workflow pins - # `runs-on: ubuntu-latest` and a Linux container internally; we cannot set - # its runner. See docs/ci-runners.md. - # - # SHA is the v2.3.8 tag target, verified via `gh api repos/google/osv-scanner-action/git/ref/tags/v2.3.8`. - # The reusable workflow pins its own sub-actions and the osv-scanner container image by SHA internally. - uses: google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@9a498708959aeaef5ef730655706c5a1df1edbc2 # v2.3.8 - with: - # Explicit lockfiles instead of the default recursive `-r ./`: bun audit skips every @jsr/* - # package ("do not come from the default registry"), and the SDK's .dev/ts7 resolves - # crypto-critical deps (@noble/hashes, valibot) through JSR. The root workspace lockfile - # covers both the SDK and documentation app; TS7 retains its isolated lockfile. + runs-on: [self-hosted, macOS, ARM64] + timeout-minutes: 15 + + steps: + # Job-level env cannot use the runner context on these Mac minis. + - name: Point TMPDIR at runner temp + run: echo "TMPDIR=$RUNNER_TEMP" >> "$GITHUB_ENV" + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + + # google/osv-scanner-action's reusable workflow pins `runs-on: ubuntu-latest` + # and a Linux container. Same scanner version (v2.3.8), same lockfiles, + # same fail-on-vuln, installed into $RUNNER_TEMP for the Mac mini. # - # Known residual gap (verified 2026-07-26 against OSV-Scanner v2.4.0): OSV has no JSR - # ecosystem, and @jsr/scope__name aliases do not match npm advisories — e.g. - # @jsr/valibot__valibot@1.4.1 is not flagged although npm valibot@1.4.1 maps to - # GHSA-5qjj-4xww-7phc. npm-named packages in these lockfiles (the vast majority, including - # all npm transitives) are covered; JSR-aliased entries are extracted and queried but only - # match if OSV ever learns the alias. + # Explicit lockfiles instead of the default recursive `-r ./`: bun audit skips + # every @jsr/* package ("do not come from the default registry"), and the + # SDK's .dev/ts7 resolves crypto-critical deps (@noble/hashes, valibot) + # through JSR. The root workspace lockfile covers both the SDK and + # documentation app; TS7 retains its isolated lockfile. # - # Patched versions of vulnerable transitive dependencies are pinned through "overrides" in - # the root package.json. - scan-args: |- - --lockfile=bun.lock - --lockfile=packages/hyperliquid/.dev/ts7/bun.lock - # Keep SARIF upload disabled; results are available as a build artifact and - # the job fails on any vulnerability. The callee still requires the permissions above. - upload-sarif: false - fail-on-vuln: true + # Known residual gap (verified 2026-07-26 against OSV-Scanner v2.4.0): OSV + # has no JSR ecosystem, and @jsr/scope__name aliases do not match npm + # advisories — e.g. @jsr/valibot__valibot@1.4.1 is not flagged although + # npm valibot@1.4.1 maps to GHSA-5qjj-4xww-7phc. npm-named packages in + # these lockfiles (the vast majority, including all npm transitives) are + # covered; JSR-aliased entries are extracted and queried but only match if + # OSV ever learns the alias. + # + # Patched versions of vulnerable transitive dependencies are pinned through + # "overrides" in the root package.json. + - name: Scan lockfiles with OSV-Scanner + run: sh .github/scripts/osv-scan.sh + + # Results stay available as a build artifact when the scan finds + # vulnerabilities (the scan step fails the job). SARIF upload stays + # disabled, matching the previous reusable-workflow inputs. + - name: Upload OSV results + if: ${{ !cancelled() }} + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: OSV Scanner results + path: osv-results.json + if-no-files-found: warn + retention-days: 5 diff --git a/docs/ci-runners.md b/docs/ci-runners.md index 2daf4bf9..fc8d1280 100644 --- a/docs/ci-runners.md +++ b/docs/ci-runners.md @@ -1,6 +1,6 @@ # CI runners -Jobs in this repository run on self-hosted Apple Silicon Mac minis. +Every GitHub Actions job in this repository runs on self-hosted Apple Silicon Mac minis. ```yaml runs-on: [self-hosted, macOS, ARM64] @@ -8,9 +8,9 @@ runs-on: [self-hosted, macOS, ARM64] The runner must carry those three labels exactly. Workflows do not use `apt`, `sudo`, Homebrew, or Docker. -## Not migrated +## Trusted publishing is unavailable -`security.yml` calls Google's `osv-scanner-reusable.yml`. That reusable workflow pins `runs-on: ubuntu-latest` and a Linux container internally. This repository cannot set its runner, so the OSV scan stays on GitHub-hosted Ubuntu. +[npm trusted publishing does not support self-hosted runners](https://docs.npmjs.com/trusted-publishers/). The publish job therefore authenticates with the org-level `NPM_TOKEN` secret (`NODE_AUTH_TOKEN`). That **drops OIDC trusted publishing and automatic provenance**. ## What the runner must already have @@ -19,13 +19,15 @@ Install these on the Mac mini before registering the GitHub Actions runner. Work | Tool | Why | | --- | --- | | macOS on Apple Silicon | Matches the `macOS` and `ARM64` labels. | -| GitHub Actions runner | Registered with labels `self-hosted`, `macOS`, `ARM64`. | +| GitHub Actions runner | Registered with labels `self-hosted`, `macOS`, `ARM64` (runner group JWS). | | Xcode Command Line Tools | `git`, `clang`, and the headers native packages (Bun, sharp, Playwright) expect. | | `curl`, `tar`, `unzip`, `sed`, `shasum`, `bash`, `tee` | Stock macOS. Workflow scripts stay BSD-portable and write scratch files under `$RUNNER_TEMP` (exported as `TMPDIR` via `$GITHUB_ENV` in a setup step; job-level `env` cannot use the `runner` context). | -Do not install CI tools with `apt` or `sudo` for these workflows. Homebrew is not required. +Do not install CI tools with `apt` or `sudo` for these workflows. Homebrew is not required for this repository. -The runner currently lacks **`gpg`**. `codecov/codecov-action` refuses to start without it (it GPG-checks the Codecov CLI). These workflows do not need host `gpg`: they pin-download `codecovcli_macos` v11.3.1 and SHA256-verify it, the same way they install lychee. Sibling repos that still call `codecov-action` directly will need `gpg` on the Mac mini (GnuPG, on `PATH`). This repository also does not need host `gh`, `gtar`, or `jq`. +The runner currently also has **`gpg`** (GnuPG), **`gh`**, and **`gtar`** (Homebrew `gnu-tar`). This repository does not call them: Codecov uses a pinned CLI, publish reads the version with Bun, and archives use stock `tar`. Sibling repos that call `codecov-action` or `actions/upload-pages-artifact` directly need those host tools. + +`actions/setup-python` cannot install on these minis (`/Users/runner` is not writable). This repository does not need Python. The runner user must be able to write the workspace and `$RUNNER_TEMP`. The machine needs enough free disk for a Bun install, a perf worktree, and Playwright's Chromium download (a few gigabytes in total). @@ -34,25 +36,27 @@ The runner user must be able to write the workspace and `$RUNNER_TEMP`. The mach These are not machine prerequisites. The jobs fetch them into the job environment or `$RUNNER_TEMP`: - **Bun canary** — downloaded into `$RUNNER_TEMP` (`bun-darwin-aarch64` zip) on every job that runs workspace scripts. `oven-sh/setup-bun` is not used: it installs into `~/.bun`, which is shared across runner instances on the same Mac mini, and a mid-job overwrite makes the perf gate see two Bun versions. -- **Node.js 24** — `actions/setup-node` on the npm publish job only (OIDC trusted publishing needs npm ≥ 11.5.1). +- **Node.js 24** — `actions/setup-node` on the npm publish job only (the npm CLI used to publish `@bloxwap/hyperliquid`). - **Playwright Chromium** — `bunx playwright install chromium` in the docs job. `--with-deps` is omitted; that flag installs Linux apt packages. Chromium's macOS libraries ship with the OS. The first docs run downloads the browser into Playwright's cache on the runner. - **lychee v0.24.2** (`aarch64-apple-darwin`) — downloaded into `$RUNNER_TEMP`, checksum-verified, and used for the same Markdown link scan as before. The `lychee-action` composite only ships a Linux GNU binary. - **Codecov CLI v11.3.1** (`codecovcli_macos`, universal x86_64/arm64) — downloaded into `$RUNNER_TEMP`, checksum-verified, and used for the same `upload-coverage` call as `codecov-action` (`--file`, `--disable-search`, `--fail-on-error`). The action is not used because it requires host `gpg`. +- **OSV-Scanner v2.3.8** (`osv-scanner_darwin_arm64`) — downloaded into `$RUNNER_TEMP`, checksum-verified, and used for the same lockfile scan as `google/osv-scanner-action` v2.3.8 (`bun.lock` and `packages/hyperliquid/.dev/ts7/bun.lock`, fail on any vulnerability). The reusable workflow pins `ubuntu-latest` and a Linux container, so it cannot run here. ## Network egress The runner needs outbound HTTPS to: -- `github.com` (checkout, Actions APIs, Pages deploy, lychee release assets, OIDC) +- `github.com` (checkout, Actions APIs, Pages deploy, lychee / OSV-Scanner / Codecov CLI release assets) - the Bun and npm registries - Playwright's browser CDN - `codecov.io` and `coveralls.io` (coverage uploads) - Hyperliquid testnet (the online test job) - `registry.npmjs.org` (publish) +- `api.osv.dev` (OSV vulnerability queries) ## Secrets -Unchanged: `CODECOV_TOKEN`, `PRIVATE_KEY` (online tests), and the default `GITHUB_TOKEN`. npm publish uses OIDC trusted publishing (`id-token: write`), not an npm token. +Unchanged: `CODECOV_TOKEN`, `PRIVATE_KEY` (online tests), and the default `GITHUB_TOKEN`. npm publish uses the org-level `NPM_TOKEN` secret (`NODE_AUTH_TOKEN`), not OIDC trusted publishing. ## Jobs @@ -63,7 +67,7 @@ Unchanged: `CODECOV_TOKEN`, `PRIVATE_KEY` (online tests), and the default `GITHU | `docs.yml` | `docs` | self-hosted Mac mini | | `docs.yml` | `deploy` | self-hosted Mac mini | | `perf.yml` | `perf` | self-hosted Mac mini | -| `publish_npm.yml` | `publish` | self-hosted Mac mini | +| `publish_npm.yml` | `publish` | self-hosted Mac mini; `NPM_TOKEN`; release / workflow_dispatch | | `tests_offline.yml` | `test` | self-hosted Mac mini | | `tests_online.yml` | `test` | self-hosted Mac mini | -| `security.yml` | `osv-scan` | GitHub-hosted Ubuntu (Google reusable workflow) | +| `security.yml` | `osv-scan` | self-hosted Mac mini |