Skip to content

Merge pull request #2 from 6829nkhpas/ci/centralized-context #4

Merge pull request #2 from 6829nkhpas/ci/centralized-context

Merge pull request #2 from 6829nkhpas/ci/centralized-context #4

Workflow file for this run

name: Context CI
on:
push:
paths:
- "centralized_context.json"
- "openapi/**"
- "types/**"
- "chain/contracts/abi/**"
- "ws/**"
pull_request:
paths:
- "centralized_context.json"
- "openapi/**"
- "types/**"
- "chain/contracts/abi/**"
- "ws/**"
jobs:
json-lint:
name: JSON Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Lint centralized_context.json
run: python3 -m json.tool centralized_context.json > /dev/null
- name: Lint contract ABIs
run: |
for f in chain/contracts/abi/*.json; do
echo "Validating $f..."
python3 -m json.tool "$f" > /dev/null
done
openapi-validate:
name: OpenAPI Validate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
- name: Validate OpenAPI spec
run: npx -y @redocly/cli@latest lint openapi/generated-openapi.yaml --skip-rule no-server-example.com
ts-compile:
name: TypeScript Compile Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install TypeScript
run: npm install -g typescript
- name: Type check generated types
run: tsc --noEmit --strict --target ES2020 --moduleResolution node types/generated-types.ts
abi-parse:
name: ABI Parse Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate ABI structure
run: |
for f in chain/contracts/abi/*.json; do
echo "Checking $f..."
python3 -c "
import json, sys
with open('$f') as fh:
abi = json.load(fh)
assert 'contract_name' in abi, 'Missing contract_name'
assert 'methods' in abi, 'Missing methods'
for m in abi['methods']:
assert 'name' in m, f'Method missing name in {m}'
assert 'mutability' in m, f'Method {m[\"name\"]} missing mutability'
print(f' ✓ {abi[\"contract_name\"]}: {len(abi[\"methods\"])} methods')
"
done
replay-smoke:
name: Replay Smoke Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate context structure
run: |
python3 -c "
import json
with open('centralized_context.json') as f:
ctx = json.load(f)
# Required top-level keys
required = ['project','apis','websockets','types','contracts','events','services','errors','versioning','constraints']
for key in required:
assert key in ctx, f'Missing top-level key: {key}'
# Validate all API examples have request or response
for api in ctx['apis']:
assert 'examples' in api, f'API {api[\"path\"]} missing examples'
# Validate sequence is strictly string across examples
def check_sequence_string(obj, path=''):
if isinstance(obj, dict):
if 'sequence' in obj:
assert isinstance(obj['sequence'], str), f'sequence must be string, got {type(obj[\"sequence\"])} at {path}'
for k, v in obj.items():
check_sequence_string(v, f'{path}.{k}')
elif isinstance(obj, list):
for i, v in enumerate(obj):
check_sequence_string(v, f'{path}[{i}]')
check_sequence_string(ctx)
# Validate timestamps are strings (not integers)
for api in ctx['apis']:
ex = api.get('examples', {})
resp = ex.get('response', {})
for ts_field in ['created_at', 'updated_at']:
if ts_field in resp:
assert isinstance(resp[ts_field], str), f'{ts_field} must be string, got {type(resp[ts_field])}'
# Validate no 24h_ prefixed keys in json or markdown files
def check_no_24h_keys(obj, path=''):
if isinstance(obj, dict):
for k, v in obj.items():
assert not k.startswith('24h_'), f'Found illegal key {k} at {path}'
check_no_24h_keys(v, f'{path}.{k}')
elif isinstance(obj, list):
for i, v in enumerate(obj):
check_sequence_string(v, f'{path}[{i}]')
check_no_24h_keys(v, f'{path}[{i}]')
check_no_24h_keys(ctx)
import glob, re
spec_files = glob.glob('spec/*.md') + ['ws/ws-protocol.md']
for f in spec_files:
with open(f) as fh:
content = fh.read()
assert not re.search(r'\b24h_', content), f'Found illegal 24h_ in {f}'
# Validate Event Envelope fields
for ws in ctx.get('websockets', []):
for ex_name, ex in ws.get('examples', {}).items():
for f in ['event_id', 'event_type', 'sequence', 'timestamp', 'source', 'payload', 'metadata']:
assert f in ex, f'Missing envelope field {f} in WS example {ex_name}'
assert isinstance(ex['sequence'], str)
assert isinstance(ex['timestamp'], str)
# Validate contract ABI paths exist
import os
for name, contract in ctx['contracts'].items():
abi_path = contract.get('abi_path', '')
assert os.path.exists(abi_path), f'ABI path missing for {name}: {abi_path}'
print('✓ All replay smoke checks passed')
"