mirror of
https://github.com/n8n-io/n8n
synced 2026-04-21 15:47:20 +00:00
ci: Add claude task runner POC (#24179)
This commit is contained in:
parent
9795214836
commit
9bd52fab39
2 changed files with 341 additions and 0 deletions
179
.github/claude-templates/security-fix.md
vendored
Normal file
179
.github/claude-templates/security-fix.md
vendored
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
# Security Vulnerability Fix Guidelines
|
||||
|
||||
## Overview
|
||||
This guide covers how to fix security vulnerabilities in the n8n codebase. Follow a systematic approach to identify, fix, and verify vulnerabilities in dependencies or base images.
|
||||
|
||||
## Decision Tree
|
||||
```
|
||||
Is it a direct dependency?
|
||||
→ Yes: Update in catalog or package.json
|
||||
→ No: Is it transitive?
|
||||
→ Yes: Add pnpm override
|
||||
→ No: Is it base image?
|
||||
→ Yes: Update Dockerfile, trigger base image workflow
|
||||
```
|
||||
|
||||
## Process Flow
|
||||
```
|
||||
Scan → Investigate → Fix → Verify
|
||||
↓ ↓ ↓ ↓
|
||||
pnpm pnpm why Update pnpm
|
||||
build: (trace) deps build:
|
||||
docker: or docker:
|
||||
scan override scan
|
||||
```
|
||||
|
||||
## Step-by-Step Process
|
||||
|
||||
### 1. Initial Setup
|
||||
Start with a clean install:
|
||||
```bash
|
||||
pnpm install --frozen-lockfile
|
||||
```
|
||||
|
||||
### 2. Scan for Vulnerabilities
|
||||
Run the Docker scan to verify if the vulnerability exists:
|
||||
```bash
|
||||
pnpm build:docker:scan
|
||||
```
|
||||
|
||||
### 3. Investigate the Source
|
||||
Use `pnpm why` to trace where the vulnerable package is coming from:
|
||||
```bash
|
||||
pnpm why <package-name> -r
|
||||
```
|
||||
|
||||
### 4. Determine Fix Strategy
|
||||
|
||||
#### Case A: Direct Dependency
|
||||
If the vulnerable package is a **direct dependency**:
|
||||
|
||||
**Update via Catalog** (preferred for shared dependencies):
|
||||
```yaml
|
||||
# pnpm-workspace.yaml
|
||||
catalog:
|
||||
'@azure/identity': 4.13.0 # Updated version
|
||||
```
|
||||
|
||||
```json
|
||||
// packages/cli/package.json
|
||||
{
|
||||
"dependencies": {
|
||||
"@azure/identity": "catalog:"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Or update directly in package.json:**
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"vulnerable-package": "^1.2.3"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then: `pnpm install`
|
||||
|
||||
#### Case B: Transitive Dependency
|
||||
If the vulnerable package is a **transitive dependency**:
|
||||
|
||||
**Add an override** in the root `package.json`:
|
||||
```json
|
||||
{
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"vulnerable-package": "^1.2.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**For multiple versions:**
|
||||
```json
|
||||
{
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"vulnerable-package@3": "^3.2.1",
|
||||
"vulnerable-package@4": "^4.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then: `pnpm install`
|
||||
|
||||
#### Case C: Base Image / NPM Issue
|
||||
If the vulnerability comes from the **base Docker image**:
|
||||
|
||||
1. Check `docker/images/n8n-base/Dockerfile`
|
||||
2. Update Node version or Alpine packages if needed
|
||||
3. Note: Base image rebuild requires manual workflow trigger
|
||||
|
||||
### 5. Verify the Fix
|
||||
```bash
|
||||
pnpm install
|
||||
pnpm why <package-name> # Check version updated
|
||||
pnpm build:docker:scan # Confirm vulnerability resolved
|
||||
```
|
||||
|
||||
## Commit & PR Standards
|
||||
|
||||
### Commit Format
|
||||
```
|
||||
{type}({scope}): {neutral description}
|
||||
|
||||
{Brief neutral context}
|
||||
|
||||
Addresses: CVE-XXXX-XXXXX
|
||||
Refs: {LINEAR-ID}
|
||||
```
|
||||
|
||||
### Type Selection
|
||||
| Scenario | Type |
|
||||
|----------|------|
|
||||
| Dependency update | `fix(deps)` |
|
||||
| Code vulnerability fix | `fix` |
|
||||
| License/compliance | `chore` |
|
||||
| Docker/build hardening | `build` |
|
||||
|
||||
### Title Language - USE NEUTRAL LANGUAGE
|
||||
Commit/PR titles appear in changelogs. Use neutral language:
|
||||
|
||||
| ❌ Avoid | ✅ Use Instead |
|
||||
|----------|----------------|
|
||||
| CVE-XXXX-XXXXX | (footer only) |
|
||||
| vulnerability, exploit | issue, concern |
|
||||
| critical, security fix | improvement, update |
|
||||
| patch vulnerability | validate, harden, ensure |
|
||||
|
||||
### Example Commit
|
||||
**Good:**
|
||||
```
|
||||
fix(deps): update jws to 4.0.1
|
||||
|
||||
Updates jws package to latest stable version.
|
||||
|
||||
Addresses: CVE-2025-65945
|
||||
Refs: SEC-412
|
||||
```
|
||||
|
||||
**Bad:**
|
||||
```
|
||||
fix(security): patch critical CVE-2025-65945 in jws
|
||||
```
|
||||
|
||||
## Done Checklist
|
||||
- [ ] `pnpm build:docker:scan` shows no vulnerability for the CVE
|
||||
- [ ] `pnpm why <package>` shows updated version
|
||||
- [ ] Commit follows neutral language format (no CVE in title)
|
||||
- [ ] PR references Linear ticket if provided
|
||||
|
||||
## Common Commands
|
||||
```bash
|
||||
pnpm install --frozen-lockfile # Initial setup
|
||||
pnpm build:docker:scan # Scan for vulnerabilities
|
||||
pnpm why <package-name> -r # Investigate dependency
|
||||
pnpm install # Update lockfile after changes
|
||||
pnpm list <package-name> # Check specific package versions
|
||||
```
|
||||
162
.github/workflows/util-claude-task.yml
vendored
Normal file
162
.github/workflows/util-claude-task.yml
vendored
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
name: 'Util: Claude Task Runner'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
task:
|
||||
description: 'Task description - what should Claude do?'
|
||||
required: true
|
||||
type: string
|
||||
branch_name:
|
||||
description: 'Branch name to create (leave empty for auto-generated)'
|
||||
required: false
|
||||
type: string
|
||||
create_pr:
|
||||
description: 'Create PR after completing task'
|
||||
required: false
|
||||
type: boolean
|
||||
default: true
|
||||
base_branch:
|
||||
description: 'Base branch for PR'
|
||||
required: false
|
||||
type: string
|
||||
default: 'master'
|
||||
|
||||
jobs:
|
||||
run-claude-task:
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2204
|
||||
timeout-minutes: 60
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
issues: write
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ inputs.base_branch }}
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: ./.github/actions/setup-nodejs
|
||||
with:
|
||||
build-command: 'echo "Skipping build - Claude will build if needed"'
|
||||
|
||||
- name: Generate branch name
|
||||
id: branch
|
||||
shell: bash
|
||||
env:
|
||||
INPUT_BRANCH_NAME: ${{ inputs.branch_name }}
|
||||
run: |
|
||||
if [ -n "$INPUT_BRANCH_NAME" ]; then
|
||||
BRANCH="$INPUT_BRANCH_NAME"
|
||||
else
|
||||
# Auto-generate branch name from timestamp
|
||||
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
||||
BRANCH="claude/task-${TIMESTAMP}"
|
||||
fi
|
||||
echo "name=$BRANCH" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Create working branch
|
||||
shell: bash
|
||||
run: |
|
||||
git checkout -b "${{ steps.branch.outputs.name }}"
|
||||
|
||||
- name: Prepare Claude prompt
|
||||
id: prompt
|
||||
shell: bash
|
||||
env:
|
||||
INPUT_TASK: ${{ inputs.task }}
|
||||
run: |
|
||||
# Build the prompt with task and pointer to templates
|
||||
{
|
||||
echo 'CLAUDE_PROMPT<<EOF'
|
||||
echo "# Task"
|
||||
echo "$INPUT_TASK"
|
||||
echo ""
|
||||
echo "# Guidelines"
|
||||
echo "Check .github/claude-templates/ for relevant guides before starting."
|
||||
echo "Read any templates that match your task type (e.g., security-fix.md for CVE fixes)."
|
||||
echo ""
|
||||
echo "# Instructions"
|
||||
echo "1. Read relevant templates from .github/claude-templates/ first"
|
||||
echo "2. Complete the task described above"
|
||||
echo "3. Follow the guidelines from the templates"
|
||||
echo "4. Make commits as you work with descriptive messages"
|
||||
echo "5. Ensure code passes linting and type checks before finishing"
|
||||
echo 'EOF'
|
||||
} >> "$GITHUB_ENV"
|
||||
|
||||
- name: Run Claude
|
||||
uses: anthropics/claude-code-action@beta
|
||||
with:
|
||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
timeout_minutes: '45'
|
||||
direct_prompt: ${{ env.CLAUDE_PROMPT }}
|
||||
allowed_tools: |
|
||||
Bash
|
||||
Read
|
||||
Write
|
||||
Edit
|
||||
Glob
|
||||
Grep
|
||||
WebFetch
|
||||
WebSearch
|
||||
TodoWrite
|
||||
|
||||
- name: Push branch
|
||||
shell: bash
|
||||
env:
|
||||
INPUT_BASE_BRANCH: ${{ inputs.base_branch }}
|
||||
BRANCH_NAME: ${{ steps.branch.outputs.name }}
|
||||
run: |
|
||||
# Check if there are any commits to push
|
||||
if git log "origin/$INPUT_BASE_BRANCH..HEAD" --oneline | grep -q .; then
|
||||
git push -u origin "$BRANCH_NAME"
|
||||
echo "CHANGES_MADE=true" >> "$GITHUB_ENV"
|
||||
else
|
||||
echo "No commits were made by Claude"
|
||||
echo "CHANGES_MADE=false" >> "$GITHUB_ENV"
|
||||
fi
|
||||
|
||||
- name: Create Pull Request
|
||||
if: inputs.create_pr && env.CHANGES_MADE == 'true'
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
INPUT_TASK: ${{ inputs.task }}
|
||||
INPUT_BASE_BRANCH: ${{ inputs.base_branch }}
|
||||
run: |
|
||||
# Create PR with task description in body
|
||||
gh pr create \
|
||||
--title "chore: Claude automated task" \
|
||||
--body "## Summary
|
||||
Automated task completed by Claude.
|
||||
|
||||
### Task Description
|
||||
$INPUT_TASK
|
||||
|
||||
---
|
||||
*This PR was created automatically by the Claude Task Runner workflow.*" \
|
||||
--base "$INPUT_BASE_BRANCH" \
|
||||
--draft
|
||||
|
||||
- name: Summary
|
||||
shell: bash
|
||||
env:
|
||||
INPUT_TASK: ${{ inputs.task }}
|
||||
INPUT_CREATE_PR: ${{ inputs.create_pr }}
|
||||
BRANCH_NAME: ${{ steps.branch.outputs.name }}
|
||||
run: |
|
||||
{
|
||||
echo "## Claude Task Runner Summary"
|
||||
echo ""
|
||||
echo "**Task:** $INPUT_TASK"
|
||||
echo "**Branch:** $BRANCH_NAME"
|
||||
echo "**Changes Made:** $CHANGES_MADE"
|
||||
if [ "$CHANGES_MADE" == "true" ] && [ "$INPUT_CREATE_PR" == "true" ]; then
|
||||
echo "**PR Created:** Yes (Draft)"
|
||||
fi
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
Loading…
Reference in a new issue