chore: Remove unused Claude Task Runner workflow (#36036)

Co-authored-by: n8n-cat-bot[bot] <n8n-cat-bot[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
n8n-cat-bot[bot]
2026-08-11 11:24:46 +00:00
committed by GitHub
co-authored by n8n-cat-bot[bot] Claude Opus 4.8
parent 42b1f2922f
commit 99d19cafec
5 changed files with 0 additions and 451 deletions
-19
View File
@@ -187,7 +187,6 @@ These only run if specific files changed:
| Event | Workflow | Condition |
|----------------------------|-----------------------------|------------------------------------------------------|
| Review approved | `release-chromatic.yml` | + design files changed |
| Comment with `@claude` | `util-claude.yml` | mention in any comment |
| Any review | `util-notify-pr-status.yml` | not community-labeled |
**Why Instance AI evals fire once per PR state-change, not per push:** the
@@ -248,26 +247,8 @@ parallelism). See the `--build-via-mcp` section in
| Workflow | Purpose |
|---------------------------|---------------------------------------------------------|
| `util-claude-task.yml` | Run Claude Code to complete a task and create a PR |
| `util-data-tooling.yml` | SQLite/PostgreSQL export/import validation (manual) |
#### Claude Task Runner (`util-claude-task.yml`)
Runs Claude Code to complete a task, then creates a PR with the changes. Use for well-specced tasks or simple fixes. Can be triggered via GitHub UI or API.
Claude reads templates from `.github/claude-templates/` for task-specific guidance. Add new templates as needed for recurring task types.
**Inputs:**
- `task` - Description of what Claude should do
- `user_token` - GitHub PAT (PR will be authored by the token owner)
**Token requirements** (fine-grained PAT):
- Repository: `n8n-io/n8n`
- Contents: `Read and write`
- Pull requests: `Read and write`
**Governance:** If you provide your personal PAT, you cannot approve the resulting PR. For automated/bot use cases (e.g., dependabot-style updates via n8n workflows), an app token can be used instead.
---
## Workflow Call Graph
-119
View File
@@ -1,119 +0,0 @@
# E2E Test Task Guide
## Required Reading
**Before writing any code**, read these files:
```
packages/testing/playwright/AGENTS.md # Patterns, anti-patterns, entry points
packages/testing/playwright/CONTRIBUTING.md # Detailed architecture (first 200 lines)
```
## Spec Validation
Before starting, verify the spec includes:
| Required | Example |
|----------|---------|
| **File(s) to modify** | `tests/e2e/credentials/crud.spec.ts` |
| **Specific behavior** | "Verify credential renaming updates the list" |
| **Pattern reference** | "Follow existing tests in same file" or "See AGENTS.md" |
**If missing, ask for clarification.** Don't guess at requirements.
## Commands
```bash
# Run single test
pnpm --filter=n8n-playwright test:local tests/e2e/your-test.spec.ts --reporter=list 2>&1 | tail -50
# Run with pattern match
pnpm --filter=n8n-playwright test:local --grep "should do something" --reporter=list 2>&1 | tail -50
# Container tests (requires pnpm build:docker first)
pnpm --filter=n8n-playwright test:container:sqlite --grep @capability:email --reporter=list 2>&1 | tail -50
```
## Test Structure
```typescript
import { test, expect } from '../fixtures/base';
import { nanoid } from 'nanoid';
test('should do something @mode:sqlite', async ({ n8n, api }) => {
// Setup via API (faster, more reliable)
const workflow = await api.workflowApi.createWorkflow(workflowJson);
// UI interaction via entry points
await n8n.start.fromBlankCanvas();
// Assertions
await expect(n8n.workflows.getWorkflowByName(workflow.name)).toBeVisible();
});
```
## Entry Points
Use `n8n.start.*` methods - see `composables/TestEntryComposer.ts`:
- `fromBlankCanvas()` - New workflow
- `fromImportedWorkflow(file)` - Pre-built workflow
- `fromNewProjectBlankCanvas()` - Project-scoped
- `withUser(user)` - Isolated browser context
## Multi-User Tests
```typescript
const member = await api.publicApi.createUser({ role: 'global:member' });
const memberPage = await n8n.start.withUser(member);
await memberPage.navigate.toWorkflows();
```
## Development Process
1. **Validate spec** - Has file, behavior, pattern reference?
2. **Read existing code** - Understand current patterns in the file
3. **Identify helpers needed** - Check `pages/`, `services/`, `composables/`
4. **Add helpers first** if missing
5. **Write test** following 4-layer architecture
6. **Verify iteratively** - Small changes, test frequently
## Mandatory Verification
**Always run before marking complete:**
```bash
# 1. Tests pass (check output for failures - piping loses exit code)
pnpm --filter=n8n-playwright test:local <your-test> --reporter=list 2>&1 | tail -50
# 2. Not flaky (required)
pnpm --filter=n8n-playwright test:local <your-test> --repeat-each 3 --reporter=list 2>&1 | tail -50
# 3. Lint passes
pnpm --filter=n8n-playwright lint 2>&1 | tail -30
# 4. Typecheck passes
pnpm --filter=n8n-playwright typecheck 2>&1 | tail -30
```
**Important:** Piping through `tail` loses the exit code. Always check the output for "failed" or error messages rather than relying on exit codes.
**If any fail, fix before completing.**
## Refactoring Existing Tests
**Always verify tests pass BEFORE making changes:**
```bash
pnpm --filter=n8n-playwright test:local tests/e2e/target-file.spec.ts --reporter=list 2>&1 | tail -50
```
Then make small incremental changes, re-running after each.
## Done Checklist
- [ ] Spec had clear file, behavior, and pattern reference
- [ ] Read `AGENTS.md` and relevant existing code
- [ ] Used `n8n.start.*` entry points
- [ ] Used `nanoid()` for unique IDs (not `Date.now()`)
- [ ] No serial mode, `@db:reset`, or `n8n.api.signin()`
- [ ] Multi-user tests use `n8n.start.withUser()`
- [ ] Tests pass with `--repeat-each 3`
- [ ] Lint and typecheck pass
-179
View File
@@ -1,179 +0,0 @@
# 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
```
@@ -1,75 +0,0 @@
#!/usr/bin/env node
/**
* Builds the Claude task prompt and writes it to GITHUB_ENV.
* Uses a random delimiter to prevent heredoc collision with user input.
*
* Usage: node prepare-claude-prompt.mjs
*
* Environment variables:
* INPUT_TASK - The task description (required)
* USE_RAW_PROMPT - "true" to pass task directly without wrapping
* GITHUB_ENV - Path to GitHub env file (set by Actions)
*/
import { randomUUID } from 'node:crypto';
import { appendFileSync, readdirSync } from 'node:fs';
const task = process.env.INPUT_TASK;
const useRaw = process.env.USE_RAW_PROMPT === 'true';
const envFile = process.env.GITHUB_ENV;
if (!task) {
console.error('INPUT_TASK environment variable is required');
process.exit(1);
}
if (!envFile) {
console.error('GITHUB_ENV environment variable is required');
process.exit(1);
}
let prompt;
if (useRaw) {
prompt = task;
} else if (task.startsWith('/')) {
// Task is a skill invocation (e.g. "/n8n:linear-issue CAT-2820").
// Wrap it so the model invokes the Skill tool instead of implementing code.
prompt = `# Skill Invocation
Invoke the following skill using the Skill tool and follow its instructions.
${task}`;
} else {
// List available templates so Claude knows what exists (reads them if needed)
const templateDir = '.github/claude-templates';
let templateSection = '';
try {
const files = readdirSync(templateDir).filter((f) => f.endsWith('.md'));
if (files.length > 0) {
const listing = files.map((f) => ` - ${templateDir}/${f}`).join('\n');
templateSection = `\n# Templates\nThese guides are available if relevant to your task. Read any that match before starting:\n${listing}`;
}
} catch {
// No templates directory, skip
}
prompt = `# Task
${task}
${templateSection}
# Instructions
1. Read any relevant templates listed above before starting
2. Complete the task described above
3. Make commits as you work - the last commit message will be used as the PR title
4. IMPORTANT: End every commit message with: Co-authored-by: Claude <noreply@anthropic.com>
5. Ensure code passes linting and type checks before finishing
# Token Optimization
When running lint/typecheck, suppress verbose output:
pnpm lint 2>&1 | tail -30
pnpm typecheck 2>&1 | tail -30`;
}
// Random delimiter guarantees no collision with user content
const delimiter = `CLAUDE_PROMPT_DELIM_${randomUUID().replace(/-/g, '')}`;
appendFileSync(envFile, `CLAUDE_PROMPT<<${delimiter}\n${prompt}\n${delimiter}\n`);
@@ -1,59 +0,0 @@
#!/usr/bin/env node
/**
* Sends a callback to the resume URL with the Claude task result.
* Uses fetch() directly to avoid E2BIG errors from shell argument limits.
*
* Usage: node resume-callback.mjs
*
* Environment variables:
* RESUME_URL - Callback URL to POST to (required)
* EXECUTION_FILE - Path to Claude's execution output JSON (optional)
* CLAUDE_OUTCOME - "success" or "failure" (required)
* CLAUDE_SESSION_ID - Session ID for resuming conversations (optional)
* BRANCH_NAME - Git branch name (optional)
*/
import { existsSync, readFileSync } from 'node:fs';
const resumeUrl = process.env.RESUME_URL;
const executionFile = process.env.EXECUTION_FILE;
const claudeOutcome = process.env.CLAUDE_OUTCOME;
const sessionId = process.env.CLAUDE_SESSION_ID ?? '';
const branchName = process.env.BRANCH_NAME ?? '';
if (!resumeUrl) {
console.error('RESUME_URL environment variable is required');
process.exit(1);
}
const success = claudeOutcome === 'success';
let result = null;
if (executionFile && existsSync(executionFile)) {
try {
const execution = JSON.parse(readFileSync(executionFile, 'utf-8'));
// Extract the last element (Claude's final result message)
result = Array.isArray(execution) ? execution.at(-1) : execution;
} catch (err) {
console.warn(`Failed to parse execution file: ${err.message}`);
}
}
const payload = JSON.stringify({ success, branch: branchName, sessionId, result });
try {
const response = await fetch(resumeUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: payload,
});
if (!response.ok) {
const body = await response.text();
console.error(`Callback failed: ${body}`);
process.exit(1);
}
} catch (err) {
console.error(`Callback error: ${err.message}`);
process.exit(1);
}