Skip to content

StringRay CI/CD

StringRay CI/CD #1160

Workflow file for this run

name: StringRay CI/CD
on:
push:
branches: [master]
pull_request:
branches: [master]
workflow_dispatch:
schedule:
- cron: "0 8 * * *" # Daily at 8 AM UTC
env:
NODE_VERSION: "20.x"
jobs:
# ═══════════════════════════════════════════════════════
# Docs Build Validation
# ═══════════════════════════════════════════════════════
docs-build:
name: Docs Build
runs-on: ubuntu-latest
if: ${{ github.event_name == 'pull_request' || contains(github.event.head_commit.message, 'docs') }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: "npm"
cache-dependency-path: docs-site/package-lock.json
- name: Install docs dependencies
run: cd docs-site && npm ci
- name: Build docs site
run: cd docs-site && npm run build
- name: Upload docs artifact
if: success()
uses: actions/upload-artifact@v4
with:
name: docs-preview
path: docs-site/build/
retention-days: 7
# ═══════════════════════════════════════════════════════
# Quality Checks
# ═══════════════════════════════════════════════════════
quality:
name: Quality Checks
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: "npm"
- name: Install dependencies
run: npm ci --ignore-scripts
- name: TypeScript check
run: npm run typecheck
- name: ESLint
run: npm run lint
# ═══════════════════════════════════════════════════════
# Unit Tests
# ═══════════════════════════════════════════════════════
test-unit:
name: Unit Tests
runs-on: ubuntu-latest
needs: quality
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build:all
- name: Run unit tests
run: npm test
# ═══════════════════════════════════════════════════════
# Pipeline Tests (gated: schedule, needs-pipeline, or ci:full)
# ═══════════════════════════════════════════════════════
test-pipeline:
name: Pipeline Tests
runs-on: ubuntu-latest
needs: test-unit
if: |
github.event_name == 'schedule' ||
contains(github.event.pull_request.labels.*.name, 'needs-pipeline') ||
contains(github.event.pull_request.labels.*.name, 'ci:full')
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build:all
- name: Run pipeline tests
run: npm run test:pipelines
# ═══════════════════════════════════════════════════════
# Consumer Package Test (gated: schedule, needs-pipeline, or ci:full)
# ═══════════════════════════════════════════════════════
test-package:
name: Package Installation
runs-on: ubuntu-latest
needs: test-pipeline
if: |
github.event_name == 'schedule' ||
contains(github.event.pull_request.labels.*.name, 'needs-pipeline') ||
contains(github.event.pull_request.labels.*.name, 'ci:full')
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Build package
run: |
npm run build:all
npm pack
- name: Create test project
run: |
mkdir -p test-install
cd test-install
npm init -y
npm install ../strray-ai-*.tgz
- name: Run postinstall
run: |
cd test-install
rm -f ~/.hermes # Ensure Hermes isn't detected in CI
node node_modules/strray-ai/scripts/node/postinstall.cjs
- name: Validate postinstall
env:
CI: "true"
run: |
cd test-install
# Skip full validation in CI - just verify package was installed
ls node_modules/strray-ai/package.json || exit 1
echo "✅ Package installed successfully"
- name: Validate MCP
env:
CI: "true"
run: |
cd test-install
node node_modules/strray-ai/scripts/mjs/validate-mcp-connectivity.cjs || true
# ═══════════════════════════════════════════════════════
# Security Audit (gated: schedule, needs-pipeline, or ci:full)
# ═══════════════════════════════════════════════════════
security:
name: Security Audit
runs-on: ubuntu-latest
needs: test-package
if: |
github.event_name == 'schedule' ||
contains(github.event.pull_request.labels.*.name, 'needs-pipeline') ||
contains(github.event.pull_request.labels.*.name, 'ci:full')
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Security audit
run: npm audit --audit-level=high || true
# ═══════════════════════════════════════════════════════
# Codex Enforcement Gate
# ═══════════════════════════════════════════════════════
enforcement:
name: Codex Enforcement
runs-on: ubuntu-latest
needs: [quality, test-unit]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: "npm"
- name: Install dependencies
run: npm ci --ignore-scripts
- name: Build
run: npm run build
- name: Run Codex Enforcement Check
run: |
echo "Running codex-check against codebase..."
node dist/core/bridge.mjs codex-check --operation write --focus "full" || true
- name: Check enforcement violations
run: |
VIOLATIONS=$(grep -c "violation\|blocked\|failed" .opencode/logs/activity.log 2>/dev/null || echo "0")
echo "Enforcement violations found: $VIOLATIONS"
if [ "$VIOLATIONS" -gt "0" ]; then
echo "⚠️ Codex violations detected - review .opencode/logs/activity.log"
fi
# ═══════════════════════════════════════════════════════
# CI/CD Health Monitor (runs after all jobs)
# ═══════════════════════════════════════════════════════
ci-health:
name: CI Health Monitor
runs-on: ubuntu-latest
needs: [ci-summary, docs-build]
if: always()
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: "npm"
- name: Run health monitor
run: node scripts/node/ci-cd-auto-fix.cjs
- name: Auto-generate reflection on failure
if: failure()
run: |
echo "CI failed - auto-generating reflection stub"
node scripts/node/auto-reflection-generator.mjs --trigger ci-failure --title "CI failure investigation"
# Commit the reflection stub
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add docs/reflections/auto-ci-*.md 2>/dev/null || true
git commit -m "docs: auto-generated reflection stub for CI failure" 2>/dev/null || true
git push 2>/dev/null || true
- name: Upload health report
uses: actions/upload-artifact@v4
with:
name: ci-health-report
path: .opencode/logs/ci-cd-monitor-report.json
# ═══════════════════════════════════════════════════════
# CI Summary Job (single required status check)
# ═══════════════════════════════════════════════════════
ci-summary:
name: CI Summary
runs-on: ubuntu-latest
needs: [quality, test-unit, enforcement]
if: always()
steps:
- name: Check required jobs status
run: |
echo "Quality: ${{ needs.quality.result }}"
echo "Unit Tests: ${{ needs.test-unit.result }}"
echo "Codex Enforcement: ${{ needs.enforcement.result }}"
if [ "${{ needs.quality.result }}" != "success" ] || \
[ "${{ needs.test-unit.result }}" != "success" ] || \
[ "${{ needs.enforcement.result }}" != "success" ]; then
echo "❌ One or more required jobs failed"
exit 1
fi
echo "✅ All required CI checks passed"