feat(knowledge): automate knowledge intake pipeline (GT-236) #338
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: 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: Winston 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 Winston 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" |