Skip to content

test: add getOpenOrders mock method and re-assert approvalBinding DB … #7

test: add getOpenOrders mock method and re-assert approvalBinding DB …

test: add getOpenOrders mock method and re-assert approvalBinding DB … #7

Workflow file for this run

name: Release
on:
push:
tags:
- "v*"
permissions:
contents: write
jobs:
test:
# Sharded test matrix. The full 840-file suite is split across disjoint
# path subsets so each shard is a FRESH `bun test` process over far fewer
# files. This eliminates the cross-file contamination that flaked the
# money-path DB tests (global sqlite singleton via setDatabasePathForTesting)
# when the whole suite ran in one process, and it runs faster in parallel.
# Each shard picks up bunfig [test].preload (the global reset) automatically.
#
# COVERAGE INVARIANT: the union of every shard's `paths` MUST cover every
# *.test.ts file under src/ (plus the 2 script tests) with NO file matched
# by zero shards and NONE matched by two. `infra-rest` in particular must
# list EVERY src/infra subdir that is NOT already claimed by `agents` or
# `money-path` — bun test path args cannot express "src/infra MINUS those",
# so new src/infra subdirs must be added here by hand. A missed subdir =
# untested code shipping. Verified by enumerating find src -name '*.test.ts'.
name: Test (${{ matrix.shard-name }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- shard-name: core
paths: src/core
- shard-name: agents
paths: src/infra/agents
- shard-name: money-path
paths: src/infra/trading src/infra/safety src/infra/storage src/infra/exchange src/infra/broker
- shard-name: infra-rest
paths: src/infra/acp src/infra/action-log src/infra/ai src/infra/auth src/infra/calibration src/infra/cli src/infra/config src/infra/context src/infra/data src/infra/diagnostics src/infra/domain src/infra/execution src/infra/hooks src/infra/logger src/infra/memory src/infra/news src/infra/observability src/infra/permissions src/infra/platform src/infra/proactive src/infra/protocols src/infra/runtime src/infra/scheduler src/infra/security src/infra/skills src/infra/testing src/infra/tools src/infra/venues
- shard-name: app-ui
paths: src/tui src/app src/runtime src/backtest src/services src/gateway src/utils src/events src/types src/cli.test.ts scripts/dev/harness scripts/research/scans
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
- name: Cache bun install
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }}
restore-keys: |
bun-${{ runner.os }}-
- name: Install dependencies (frozen lockfile)
# Frozen so CI-green == what ships. A frozen install does NOT re-resolve
# versions, so bunfig.toml's minimumReleaseAge age-gate never blocks it
# (that gate only applies to NEW resolutions, not to replaying bun.lock).
run: bun install --frozen-lockfile
- name: Patch Bun-incompatible dependencies
run: node scripts/patches/patch-mastra.cjs
- name: Run tests (shard ${{ matrix.shard-name }})
run: bun test ${{ matrix.paths }}
# Single-shard gates: broker conformance, latency, and typecheck are
# suite-wide and must run exactly ONCE, not redundantly per test shard.
test-gates:
name: Test Gates (conformance + typecheck)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
- name: Cache bun install
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }}
restore-keys: |
bun-${{ runner.os }}-
- name: Install dependencies (frozen lockfile)
run: bun install --frozen-lockfile
- name: Patch Bun-incompatible dependencies
run: node scripts/patches/patch-mastra.cjs
- name: Run broker conformance matrix
run: bun run test:broker-conformance
- name: Run broker latency quality gate
run: bun run quality:brokers
- name: Run typecheck
run: bun run typecheck
verify-npm-wrapper:
name: Verify npm Wrapper (${{ matrix.os }})
needs: [test, test-gates]
runs-on: ${{ matrix.os }}
env:
GORDON_NPM_VERSION: ${{ github.ref_name }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- macos-latest
- windows-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
- name: Prepare npm wrapper
run: npm run prepare:npm-wrapper
- name: Check npm wrapper
run: npm run check:npm-wrapper
- name: Smoke test npm wrapper
run: npm run smoke:npm-wrapper
- name: Audit npm pack contents (no source files, no .map)
run: node scripts/npm/audit-npm-pack.cjs
- name: Audit npm pack content for credential leaks
if: matrix.os == 'ubuntu-latest'
run: node scripts/npm/audit-npm-pack-content.cjs
- name: Source map guardrail (block sourcemap leak)
run: node scripts/build/check-no-sourcemaps.cjs
verify-public-dist:
name: Verify Public Dist Bundle
needs: [test, test-gates]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Prepare public dist bundle
run: node scripts/build/prepare-public-dist.cjs --out-dir .public-dist
- name: Verify public dist bundle
run: |
test -f .public-dist/README.md
test -f .public-dist/install.sh
test -f .public-dist/install.ps1
test -f .public-dist/Formula/gordon.rb
test -f .public-dist/bucket/gordon.json
create-source-release:
name: Create Source Release
needs:
- test
- test-gates
- verify-npm-wrapper
- verify-public-dist
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Generate CycloneDX SBOM
# Software Bill of Materials attached to every release. CycloneDX 1.5 JSON.
run: |
npm install --package-lock-only --ignore-scripts
node scripts/dev/codegen/generate-sbom.cjs --output gordon-sbom.json
- name: Create or update GitHub Release
uses: softprops/action-gh-release@v1
with:
generate_release_notes: true
files: gordon-sbom.json
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
build:
name: Build ${{ matrix.target }}
needs:
- create-source-release
runs-on: ${{ matrix.os }}
# Experimental targets (windows-arm64) may fail without blocking the
# release. Under the optionalDependencies model this is fully non-blocking:
# a missing platform sub-package just isn't published, and the launcher
# degrades gracefully on that host instead of crashing.
continue-on-error: ${{ matrix.experimental == true }}
strategy:
fail-fast: false
matrix:
include:
# Standard glibc Linux
- target: linux-x64
bun_target: bun-linux-x64
os: ubuntu-latest
binary_name: gordon-linux-x64
- target: linux-arm64
bun_target: bun-linux-arm64
os: ubuntu-latest
binary_name: gordon-linux-arm64
# Alpine / musl Linux (separate libc — glibc binaries crash on Alpine)
- target: linux-x64-musl
bun_target: bun-linux-x64-musl
os: ubuntu-latest
binary_name: gordon-linux-x64-musl
- target: linux-arm64-musl
bun_target: bun-linux-arm64-musl
os: ubuntu-latest
binary_name: gordon-linux-arm64-musl
# macOS
- target: darwin-x64
bun_target: bun-darwin-x64
os: macos-latest
binary_name: gordon-darwin-x64
- target: darwin-arm64
bun_target: bun-darwin-arm64
os: macos-latest
binary_name: gordon-darwin-arm64
# Windows — both architectures
- target: windows-x64
bun_target: bun-windows-x64
os: windows-latest
binary_name: gordon-windows-x64.exe
- target: windows-arm64
bun_target: bun-windows-arm64
os: windows-latest
binary_name: gordon-windows-arm64.exe
experimental: true
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
- name: Cache bun install
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }}
restore-keys: |
bun-${{ runner.os }}-
- name: Install dependencies (frozen lockfile)
run: bun install --frozen-lockfile
- name: Patch Bun-incompatible dependencies
run: node scripts/patches/patch-mastra.cjs
- name: Build binary
# Cross-compile through scripts/build/build.ts so the shipped binary
# carries the exact EXTERNALS list a local `bun run build:binary` uses
# (no CI-vs-local drift). Retry: Bun's cross-compile runtime download is
# occasionally truncated on windows-arm64; the fix is just to try again.
shell: bash
run: |
set -e
attempt=1
max=3
until bun scripts/build/build.ts --binary \
--target ${{ matrix.bun_target }} \
--outfile ${{ matrix.binary_name }}; do
if [ $attempt -ge $max ]; then
echo "Build failed after $attempt attempts"
exit 1
fi
echo "Build attempt $attempt failed, retrying..."
attempt=$((attempt + 1))
sleep 10
done
- name: Upload binary artifact
# Build-once, promote: the publish job downloads these artifacts rather
# than rebuilding. Also uploaded to the GH Release below for the
# direct-binary channel (install.sh / Homebrew / Scoop).
uses: actions/upload-artifact@v4
with:
name: binary-${{ matrix.target }}
path: ${{ matrix.binary_name }}
if-no-files-found: error
retention-days: 1
- name: Upload binary to release
shell: pwsh
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
& gh release upload "${env:GITHUB_REF_NAME}" "${{ matrix.binary_name }}#${{ matrix.binary_name }}" --clobber
publish:
name: Stage + Publish
needs: build
runs-on: ubuntu-latest
# id-token: write enables OIDC so `npm publish --provenance` signs each
# tarball (root wrapper + every platform sub-package) with SLSA Build L3
# attestations. contents: write is for the manifest commit + SHA256SUMS
# asset upload.
permissions:
id-token: write
contents: write
env:
VERSION: ${{ github.ref_name }}
steps:
- name: Checkout source repo
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
registry-url: https://registry.npmjs.org
- name: Download built binaries
uses: actions/download-artifact@v4
with:
path: dist-assets
pattern: binary-*
merge-multiple: true
- name: Stage per-platform npm sub-packages
# Generates one @general-liquidity/gordon-<target> package dir per
# available binary + a manifest with per-asset sha256. Missing targets
# (e.g. a failed windows-arm64) are simply skipped, not fatal.
run: |
node scripts/npm/stage-platform-packages.cjs \
--binaries dist-assets \
--out staging \
--version "${VERSION}" \
--manifest staging/manifest.json
- name: Wire per-asset hashes into Formula / Scoop / SHA256SUMS
# Deterministic, asset-name-keyed (replaces the fragile ordered-sed):
# correct per-arch hashes, no x64/arm64 reuse.
run: node scripts/npm/apply-release-hashes.cjs --manifest staging/manifest.json --version "${VERSION}"
- name: Prepare npm wrapper metadata
env:
GORDON_NPM_VERSION: ${{ github.ref_name }}
run: npm run prepare:npm-wrapper
- name: Resolve source branch
run: |
SOURCE_BRANCH=$(git branch -r --contains "${GITHUB_SHA}" | grep -v HEAD | sed 's|origin/||' | grep '^v' | head -1 | xargs)
if [ -z "${SOURCE_BRANCH}" ]; then
SOURCE_BRANCH=$(git branch -r --contains "${GITHUB_SHA}" | grep -v HEAD | sed 's|origin/||' | head -1 | xargs)
fi
if [ -z "${SOURCE_BRANCH}" ]; then
SOURCE_BRANCH="main"
fi
echo "SOURCE_BRANCH=${SOURCE_BRANCH}" >> "$GITHUB_ENV"
git checkout "${SOURCE_BRANCH}"
- name: Commit source manifest updates
run: |
git config user.name "Tiberiu Toca"
git config user.email "tibi.toca@gmail.com"
git add Formula/gordon.rb scripts/scoop/gordon.json scripts/SHA256SUMS npm/package.json npm/README.md npm/LICENSE
git diff --cached --quiet || git commit -m "chore: publish assets for ${VERSION}"
git push origin "HEAD:${SOURCE_BRANCH}"
- name: Upload SHA256SUMS to release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh release upload "${VERSION}" scripts/SHA256SUMS#SHA256SUMS --clobber
- name: Determine npm dist-tag
id: dist-tag
run: |
# Pre-release tags (v0.1.0-alpha.1, -beta, -rc, -friends) publish to a
# side channel so `npm install -g @general-liquidity/gordon` (which
# resolves @latest) never picks them up. Clean tags go to @latest.
if echo "${{ github.ref_name }}" | grep -qE 'friends|alpha|beta|rc'; then
echo "tag=next" >> "$GITHUB_OUTPUT"
else
echo "tag=latest" >> "$GITHUB_OUTPUT"
fi
- name: Publish platform sub-packages to npm
# Sub-packages FIRST so the root wrapper's optionalDependencies already
# resolve on the registry when it publishes. Each gets its own provenance
# attestation. A publish failure of one target should not silently pass —
# but a target that was never staged simply has no dir to iterate.
working-directory: staging/@general-liquidity
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
set -e
for dir in */; do
pkg="${dir%/}"
echo "Publishing @general-liquidity/${pkg}..."
( cd "${pkg}" && npm publish --access public --provenance --tag "${{ steps.dist-tag.outputs.tag }}" )
done
- name: Publish root wrapper to npm
working-directory: npm
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npm publish --access public --provenance --tag "${{ steps.dist-tag.outputs.tag }}"