diff --git a/.woodpecker/README.md b/.woodpecker/README.md new file mode 100644 index 0000000..548c1ce --- /dev/null +++ b/.woodpecker/README.md @@ -0,0 +1,120 @@ +# Woodpecker CI Configuration for Mosaic Stack + +## Codex AI Review Pipeline + +This directory contains the Codex AI review pipeline configuration for automated code and security reviews on pull requests. + +### Setup + +1. **Add Codex API key to Woodpecker:** + - Go to mosaic-stack repo at `https://ci.mosaicstack.dev` + - Settings → Secrets + - Add secret: `codex_api_key` with your OpenAI API key + +2. **Enable the pipeline:** + - The `codex-review.yml` pipeline will automatically run on all PRs + - The main `.woodpecker.yml` handles primary CI tasks + - This codex pipeline is independent and focused solely on reviews + +### What Gets Reviewed + +**Code Review (`code-review` step):** + +- Correctness — logic errors, edge cases, error handling +- Code Quality — complexity, duplication, naming +- Testing — coverage, test quality +- Performance — N+1 queries, blocking ops +- Dependencies — deprecated packages +- Documentation — comments, API docs + +**Security Review (`security-review` step):** + +- OWASP Top 10 vulnerabilities +- Hardcoded secrets/credentials +- Injection flaws (SQL, NoSQL, OS command) +- XSS, CSRF, SSRF +- Auth/authz gaps +- Data exposure in logs + +### Pipeline Behavior + +- **Triggers:** Every pull request +- **Runs:** Code review + Security review in parallel +- **Fails if:** + - Code review finds **blockers** + - Security review finds **critical** or **high** severity issues +- **Outputs:** Structured JSON results in CI logs + +### Local Testing + +Test the review scripts locally before pushing: + +```bash +# Code review of uncommitted changes +~/.claude/scripts/codex/codex-code-review.sh --uncommitted + +# Security review of uncommitted changes +~/.claude/scripts/codex/codex-security-review.sh --uncommitted + +# Code review against main branch +~/.claude/scripts/codex/codex-code-review.sh -b main + +# Security review and save JSON +~/.claude/scripts/codex/codex-security-review.sh -b main -o security.json +``` + +### Schema Files + +The `schemas/` directory contains JSON schemas that enforce structured output from Codex: + +- `code-review-schema.json` — Defines output for code quality reviews +- `security-review-schema.json` — Defines output for security reviews + +These schemas ensure consistent, machine-readable findings that the CI pipeline can parse and fail on. + +### Integration with Main Pipeline + +The main `.woodpecker.yml` in the repo root handles: + +- Type checking (TypeScript) +- Linting (ESLint) +- Unit tests (Vitest) +- Integration tests (Playwright) +- Docker image builds + +This `codex-review.yml` is independent and focuses solely on: + +- AI-powered code quality review +- AI-powered security vulnerability scanning + +Both pipelines run in parallel on PRs. + +### Troubleshooting + +**Pipeline fails with "codex: command not found"** + +- Check that the node image in `codex-review.yml` matches a version with npm +- Current: `node:22-slim` + +**Pipeline fails with auth errors** + +- Verify `codex_api_key` secret is set in Woodpecker +- Test the key locally: `CODEX_API_KEY= codex exec "test"` + +**Pipeline passes but should fail** + +- Check the failure conditions in `codex-review.yml` +- Current thresholds: blockers, critical, or high findings + +## Files + +| File | Purpose | +| ------------------------------------- | -------------------------------------- | +| `codex-review.yml` | Codex AI review pipeline configuration | +| `schemas/code-review-schema.json` | Code review output schema | +| `schemas/security-review-schema.json` | Security review output schema | +| `README.md` | This file | + +## Parent CI Pipeline + +The main `.woodpecker.yml` is located at the repository root and handles all build/test tasks. diff --git a/.woodpecker/codex-review.yml b/.woodpecker/codex-review.yml new file mode 100644 index 0000000..ee552bb --- /dev/null +++ b/.woodpecker/codex-review.yml @@ -0,0 +1,90 @@ +# Codex AI Review Pipeline for Woodpecker CI +# Drop this into your repo's .woodpecker/ directory to enable automated +# code and security reviews on every pull request. +# +# Required secrets: +# - codex_api_key: OpenAI API key or Codex-compatible key +# +# Optional secrets: +# - gitea_token: Gitea API token for posting PR comments (if not using tea CLI auth) + +when: + event: pull_request + +variables: + - &node_image "node:22-slim" + - &install_codex "npm i -g @openai/codex" + +steps: + # --- Code Quality Review --- + code-review: + image: *node_image + environment: + CODEX_API_KEY: + from_secret: codex_api_key + commands: + - *install_codex + - apt-get update -qq && apt-get install -y -qq jq git > /dev/null 2>&1 + + # Generate the diff + - git fetch origin ${CI_COMMIT_TARGET_BRANCH:-main} + - DIFF=$(git diff origin/${CI_COMMIT_TARGET_BRANCH:-main}...HEAD) + + # Run code review with structured output + - | + codex exec \ + --sandbox read-only \ + --output-schema .woodpecker/schemas/code-review-schema.json \ + -o /tmp/code-review.json \ + "You are an expert code reviewer. Review the following code changes for correctness, code quality, testing, performance, and documentation issues. Only flag actionable, important issues. Categorize as blocker/should-fix/suggestion. If code looks good, say so. + + Changes: + $DIFF" + + # Output summary + - echo "=== Code Review Results ===" + - jq '.' /tmp/code-review.json + - | + BLOCKERS=$(jq '.stats.blockers // 0' /tmp/code-review.json) + if [ "$BLOCKERS" -gt 0 ]; then + echo "FAIL: $BLOCKERS blocker(s) found" + exit 1 + fi + echo "PASS: No blockers found" + + # --- Security Review --- + security-review: + image: *node_image + environment: + CODEX_API_KEY: + from_secret: codex_api_key + commands: + - *install_codex + - apt-get update -qq && apt-get install -y -qq jq git > /dev/null 2>&1 + + # Generate the diff + - git fetch origin ${CI_COMMIT_TARGET_BRANCH:-main} + - DIFF=$(git diff origin/${CI_COMMIT_TARGET_BRANCH:-main}...HEAD) + + # Run security review with structured output + - | + codex exec \ + --sandbox read-only \ + --output-schema .woodpecker/schemas/security-review-schema.json \ + -o /tmp/security-review.json \ + "You are an expert application security engineer. Review the following code changes for security vulnerabilities including OWASP Top 10, hardcoded secrets, injection flaws, auth/authz gaps, XSS, CSRF, SSRF, path traversal, and supply chain risks. Include CWE IDs and remediation steps. Only flag real security issues, not code quality. + + Changes: + $DIFF" + + # Output summary + - echo "=== Security Review Results ===" + - jq '.' /tmp/security-review.json + - | + CRITICAL=$(jq '.stats.critical // 0' /tmp/security-review.json) + HIGH=$(jq '.stats.high // 0' /tmp/security-review.json) + if [ "$CRITICAL" -gt 0 ] || [ "$HIGH" -gt 0 ]; then + echo "FAIL: $CRITICAL critical, $HIGH high severity finding(s)" + exit 1 + fi + echo "PASS: No critical or high severity findings" diff --git a/.woodpecker/schemas/code-review-schema.json b/.woodpecker/schemas/code-review-schema.json new file mode 100644 index 0000000..df35fbc --- /dev/null +++ b/.woodpecker/schemas/code-review-schema.json @@ -0,0 +1,92 @@ +{ + "type": "object", + "additionalProperties": false, + "properties": { + "summary": { + "type": "string", + "description": "Brief overall assessment of the code changes" + }, + "verdict": { + "type": "string", + "enum": ["approve", "request-changes", "comment"], + "description": "Overall review verdict" + }, + "confidence": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "Confidence score for the review (0-1)" + }, + "findings": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "severity": { + "type": "string", + "enum": ["blocker", "should-fix", "suggestion"], + "description": "Finding severity: blocker (must fix), should-fix (important), suggestion (optional)" + }, + "title": { + "type": "string", + "description": "Short title describing the issue" + }, + "file": { + "type": "string", + "description": "File path where the issue was found" + }, + "line_start": { + "type": "integer", + "description": "Starting line number" + }, + "line_end": { + "type": "integer", + "description": "Ending line number" + }, + "description": { + "type": "string", + "description": "Detailed explanation of the issue" + }, + "suggestion": { + "type": "string", + "description": "Suggested fix or improvement" + } + }, + "required": [ + "severity", + "title", + "file", + "line_start", + "line_end", + "description", + "suggestion" + ] + } + }, + "stats": { + "type": "object", + "additionalProperties": false, + "properties": { + "files_reviewed": { + "type": "integer", + "description": "Number of files reviewed" + }, + "blockers": { + "type": "integer", + "description": "Count of blocker findings" + }, + "should_fix": { + "type": "integer", + "description": "Count of should-fix findings" + }, + "suggestions": { + "type": "integer", + "description": "Count of suggestion findings" + } + }, + "required": ["files_reviewed", "blockers", "should_fix", "suggestions"] + } + }, + "required": ["summary", "verdict", "confidence", "findings", "stats"] +} diff --git a/.woodpecker/schemas/security-review-schema.json b/.woodpecker/schemas/security-review-schema.json new file mode 100644 index 0000000..5b109fe --- /dev/null +++ b/.woodpecker/schemas/security-review-schema.json @@ -0,0 +1,106 @@ +{ + "type": "object", + "additionalProperties": false, + "properties": { + "summary": { + "type": "string", + "description": "Brief overall security assessment of the code changes" + }, + "risk_level": { + "type": "string", + "enum": ["critical", "high", "medium", "low", "none"], + "description": "Overall security risk level" + }, + "confidence": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "Confidence score for the review (0-1)" + }, + "findings": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "severity": { + "type": "string", + "enum": ["critical", "high", "medium", "low"], + "description": "Vulnerability severity level" + }, + "title": { + "type": "string", + "description": "Short title describing the vulnerability" + }, + "file": { + "type": "string", + "description": "File path where the vulnerability was found" + }, + "line_start": { + "type": "integer", + "description": "Starting line number" + }, + "line_end": { + "type": "integer", + "description": "Ending line number" + }, + "description": { + "type": "string", + "description": "Detailed explanation of the vulnerability" + }, + "cwe_id": { + "type": "string", + "description": "CWE identifier if applicable (e.g., CWE-79)" + }, + "owasp_category": { + "type": "string", + "description": "OWASP Top 10 category if applicable (e.g., A03:2021-Injection)" + }, + "remediation": { + "type": "string", + "description": "Specific remediation steps to fix the vulnerability" + } + }, + "required": [ + "severity", + "title", + "file", + "line_start", + "line_end", + "description", + "cwe_id", + "owasp_category", + "remediation" + ] + } + }, + "stats": { + "type": "object", + "additionalProperties": false, + "properties": { + "files_reviewed": { + "type": "integer", + "description": "Number of files reviewed" + }, + "critical": { + "type": "integer", + "description": "Count of critical findings" + }, + "high": { + "type": "integer", + "description": "Count of high findings" + }, + "medium": { + "type": "integer", + "description": "Count of medium findings" + }, + "low": { + "type": "integer", + "description": "Count of low findings" + } + }, + "required": ["files_reviewed", "critical", "high", "medium", "low"] + } + }, + "required": ["summary", "risk_level", "confidence", "findings", "stats"] +}