test: add getOpenOrders mock method and re-assert approvalBinding DB … #7
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: 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 }}" |