chore: upgrade Node.js runtime to v24 across codebase #419
120
.woodpecker/README.md
Normal file
120
.woodpecker/README.md
Normal file
@@ -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=<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.
|
||||
90
.woodpecker/codex-review.yml
Normal file
90
.woodpecker/codex-review.yml
Normal file
@@ -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"
|
||||
92
.woodpecker/schemas/code-review-schema.json
Normal file
92
.woodpecker/schemas/code-review-schema.json
Normal file
@@ -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"]
|
||||
}
|
||||
106
.woodpecker/schemas/security-review-schema.json
Normal file
106
.woodpecker/schemas/security-review-schema.json
Normal file
@@ -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"]
|
||||
}
|
||||
Reference in New Issue
Block a user