Skip to content

Live-API smoke

Live-API smoke #19

Workflow file for this run

name: Live-API smoke
# Runs the smoke test against real public APIs (DexScreener, GoPlus, OpenOcean,
# Across, Hyperliquid, Polymarket, Morpho, Pendle, Drift, etc.) on a schedule
# and on-demand. Unit tests mock these APIs; this catches drift between our
# wiring and what the upstream services actually return.
#
# This intentionally runs separately from the standard CI workflow so a
# transient upstream outage doesn't block PRs.
on:
schedule:
# Daily at 09:00 UTC. Picks up endpoint shape changes within a day.
- cron: '0 9 * * *'
workflow_dispatch:
inputs:
ref:
description: 'Git ref to test (default: main)'
required: false
default: 'main'
jobs:
smoke:
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
issues: write
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.ref || 'main' }}
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: mcp-server/package-lock.json
- name: Install deps
run: cd mcp-server && npm ci
- name: Compile TypeScript
run: cd mcp-server && node node_modules/typescript/bin/tsc
- name: Run live-API smoke
env:
# CHAINGPT_API_KEY is required for the server to boot, but the
# read-only smoke cases never hit the ChainGPT plugin API itself.
CHAINGPT_API_KEY: ${{ secrets.CHAINGPT_API_KEY || 'smoke-test' }}
MORALIS_API_KEY: ${{ secrets.MORALIS_API_KEY }}
ONEINCH_API_KEY: ${{ secrets.ONEINCH_API_KEY }}
ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY }}
run: cd mcp-server && node dist/smoke-test.js
- name: Open issue on failure
if: ${{ failure() && github.event_name == 'schedule' }}
uses: actions/github-script@v7
with:
script: |
const title = `[smoke] Daily live-API smoke failed — ${new Date().toISOString().slice(0,10)}`;
const body = [
'The scheduled live-API smoke run failed.',
'',
`Workflow: ${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`,
'',
'Likely causes:',
'- An upstream API changed its response shape',
'- A rate limit was hit',
'- A protocol moved to a new endpoint',
'',
'Open the workflow log to see which case(s) failed and which endpoint to inspect.',
].join('\n');
// Only open one issue per day, even if the workflow runs multiple times
const today = new Date().toISOString().slice(0, 10);
const { data: existing } = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
labels: 'smoke-failure',
per_page: 50,
});
if (existing.some((i) => i.title.includes(today))) {
core.info('Smoke-failure issue for today already exists; skipping.');
return;
}
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title,
body,
labels: ['smoke-failure', 'live-api'],
});