Skip to content

docs(gaps): close 26 gaps — closure evidence + checkbox updates #331

docs(gaps): close 26 gaps — closure evidence + checkbox updates

docs(gaps): close 26 gaps — closure evidence + checkbox updates #331

Workflow file for this run

name: Evolith SDK CLI - CI Pipeline
on:
pull_request:
branches: [main, develop]
paths:
- 'sdk/cli/**'
- '.harness/**'
- 'release-please-config.json'
- '.github/workflows/sdk-cli-ci.yml'
push:
branches: [main, develop]
paths:
- 'sdk/cli/**'
- '.harness/**'
- 'release-please-config.json'
- '.github/workflows/sdk-cli-ci.yml'
workflow_dispatch:
env:
NODE_VERSION: '20'
CLI_DIR: 'sdk/cli'
jobs:
# ============================================
# JOB 1: Evolith Core Validation
# ============================================
core-validation:
name: Evolith Core Validation
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
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'
cache-dependency-path: package-lock.json
- name: Install Dependencies
run: npm ci
- name: Validate Documentation
run: node .harness/scripts/ci/01-validate-docs.mjs --render-mermaid
- name: Check Bilingual Parity
run: node .harness/scripts/ci/04-check-bilingual-parity.mjs
- name: Bilingual Terminology Lint
run: node .harness/scripts/bilingual-terminology-lint.mjs
- name: Verify Root Cleanliness
run: node .harness/scripts/ci/03-validate-root-cleanliness.mjs
- name: Check Bilingual Coverage
run: node .harness/scripts/bilingual-coverage.mjs
# ============================================
# JOB 2: Security Audit
# ============================================
security-audit:
name: Security Audit
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Install Dependencies
run: npm ci
- name: Security Vulnerability Audit
working-directory: ${{ env.CLI_DIR }}
run: npm audit --audit-level=high
# ============================================
# JOB 3: Lint and Type Check
# ============================================
lint-and-types:
name: Lint and Type Check
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
cache-dependency-path: package-lock.json
- name: Install Dependencies
run: npm ci
- name: Build workspace dependencies
run: |
npm run build -w @evolith/core-domain
npm run build -w @evolith/infra-providers
npm run build -w @evolith/core
npm run build -w @evolith/mcp-server
- name: Architecture Boundary Lint (eslint-plugin-boundaries)
working-directory: ${{ env.CLI_DIR }}
run: npm run lint
- name: Type Check
working-directory: ${{ env.CLI_DIR }}
run: npm run build
- name: Test Type Check
working-directory: ${{ env.CLI_DIR }}
run: npx tsc --noEmit -p tsconfig.test.json
# ============================================
# JOB 4: Unit Tests with Coverage
# ============================================
unit-tests:
name: Unit Tests
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
cache-dependency-path: package-lock.json
- name: Install Dependencies
run: npm ci
- name: Build workspace dependencies
run: |
npm run build -w @evolith/core-domain
npm run build -w @evolith/infra-providers
npm run build -w @evolith/core
npm run build -w @evolith/mcp-server
- name: Run Unit Tests
working-directory: ${{ env.CLI_DIR }}
# Emit json-summary (consumed by the coverage gate below) alongside the
# console summary. A single --coverage-reporters override would drop the
# json file and break the threshold check.
run: npm run test:cov -- --coverageReporters=text-summary --coverageReporters=json-summary
- name: Upload Coverage
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: ${{ env.CLI_DIR }}/coverage/
- name: Check Coverage Threshold
run: |
COVERAGE=$(jq -r '.total.statements.pct' ${{ env.CLI_DIR }}/coverage/coverage-summary.json)
THRESHOLD=80
if (( $(echo "$COVERAGE < $THRESHOLD" | bc -l) )); then
echo "Statement coverage $COVERAGE% is below threshold $THRESHOLD%"
exit 1
fi
echo "Statement coverage: $COVERAGE%"
# ============================================
# JOB 5: Architecture Validation
# ============================================
architecture-validation:
name: Architecture Validation
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Verify Git Tag Alignment
run: node .harness/scripts/verify-git-tag.mjs
- name: Verify Version Log
run: node .harness/scripts/verify-version-log.mjs
- name: Check ADR Consistency
run: node .harness/scripts/adr-lifecycle.mjs --check-only
- name: Doc Complexity Score
run: node .harness/scripts/doc-complexity-score.mjs --threshold=15
# ============================================
# JOB 6: Package Integrity
# ============================================
package-integrity:
name: Package Integrity
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Install Dependencies
run: npm ci
- name: Build workspace dependencies
run: |
npm run build -w @evolith/core-domain
npm run build -w @evolith/infra-providers
npm run build -w @evolith/core
npm run build -w @evolith/mcp-server
- name: Build Package
working-directory: ${{ env.CLI_DIR }}
run: npm run build
- name: Verify Binary Entry Point
run: |
echo "Checking bin entry point..."
ls -la ${{ env.CLI_DIR }}/dist/main.js
echo "Checking package.json bin field..."
node -e "const pkg=require('./${{ env.CLI_DIR }}/package.json'); console.log('bin:', pkg.bin)"
- name: Verify Package Structure
run: |
echo "Verifying package structure..."
node -e "
const pkg = require('./${{ env.CLI_DIR }}/package.json');
const fs = require('fs');
const path = require('path');
// Check main entry
const mainExists = fs.existsSync(path.join('${{ env.CLI_DIR }}', pkg.main));
console.log('Main exists:', mainExists);
// Check bin entry (identity comes from package.json, not a hardcoded name)
const binTargets = typeof pkg.bin === 'string' ? [pkg.bin] : Object.values(pkg.bin);
const binExists = binTargets.length > 0 &&
binTargets.every((target) => fs.existsSync(path.join('${{ env.CLI_DIR }}', target)));
console.log('Bin targets:', binTargets);
console.log('Bin exists:', binExists);
// Check exports
console.log('Main:', pkg.main);
console.log('Bin:', pkg.bin);
if (!mainExists || !binExists) {
process.exit(1);
}
"
# ============================================
# JOB 7: E2E Smoke Test (optional)
# ============================================
e2e-tests:
name: E2E Tests
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Install Dependencies
run: npm ci
- name: Build workspace dependencies
run: |
npm run build -w @evolith/core-domain
npm run build -w @evolith/infra-providers
npm run build -w @evolith/core
npm run build -w @evolith/mcp-server
- name: Build
working-directory: ${{ env.CLI_DIR }}
run: npm run build
- name: Run E2E Tests
working-directory: ${{ env.CLI_DIR }}
run: npm run test:e2e
- name: Run MCP Stdio and HTTP Smoke
working-directory: ${{ env.CLI_DIR }}
run: npm run mcp:smoke
# ============================================
# JOB 9: CodeQL SAST Analysis (GT-227)
# ============================================
codeql-analysis:
name: CodeQL SAST
runs-on: ubuntu-latest
permissions:
security-events: write
contents: read
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: javascript-typescript
queries: security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:javascript-typescript"
# ============================================
# JOB 10: Trivy Container Scan (GT-227)
# ============================================
trivy-scan:
name: Trivy Container Scan
runs-on: ubuntu-latest
permissions:
security-events: write
contents: read
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Run Trivy Vulnerability Scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
- name: Upload Trivy SARIF Report
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: 'trivy-results.sarif'
category: 'trivy-scan'
# ============================================
# JOB 11: DAST OWASP ZAP Scan (GT-245)
# ============================================
dast-scan:
name: DAST OWASP ZAP
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork == false
runs-on: ubuntu-latest
continue-on-error: true
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Run OWASP ZAP Full Scan
uses: zaproxy/action-full-scan@v0.10.0
with:
target: 'http://localhost:8000'
rules_file_name: '.zap/rules.tsv'
cmd_options: >-
-a
-j
-l WARN
allow_issue_writing: false
artifact_name: 'zap-scan-report'
fail_action: false
- name: Upload ZAP SARIF Report
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: 'zap_scan_report.sarif'
category: 'dast-zap'
agentic-review:
name: Wilson Agentic Review
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork == false
runs-on: ubuntu-latest
# Least privilege: the review only reads the repo to diff changes (GT-146).
permissions:
contents: read
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies
run: npm ci
- name: Run Wilson review
env:
EVOLITH_AGENTIC_REVIEW: "true"
EVOLITH_LLM_API_KEY: ${{ secrets.EVOLITH_LLM_API_KEY }}
run: node .harness/scripts/ci/13-agentic-code-review.mjs
# ============================================
# Gate: All Jobs Must Pass
# ============================================
gate:
name: CI Gate
needs: [core-validation, security-audit, lint-and-types, unit-tests, e2e-tests, architecture-validation, package-integrity, agentic-review, codeql-analysis, trivy-scan, dast-scan]
runs-on: ubuntu-latest
steps:
- name: All Checks Passed
run: echo "✅ All CI checks passed"