Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .github/scripts/osv-scan.sh
Original file line number Diff line number Diff line change
@@ -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"
25 changes: 22 additions & 3 deletions .github/workflows/publish_npm.yml
Original file line number Diff line number Diff line change
@@ -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]
Expand All @@ -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
Expand All @@ -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 }}
73 changes: 41 additions & 32 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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/[email protected] is not flagged although npm [email protected] 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/[email protected] is not flagged although
# npm [email protected] 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
26 changes: 15 additions & 11 deletions docs/ci-runners.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# 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]
```

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

Expand All @@ -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).

Expand All @@ -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

Expand All @@ -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 |