# TEST REPORT: n8n 3.0 Upgrade Check v1.0.0

Run by `N8N_BIN=n8n245/node_modules/.bin/n8n bash tests/run_all.sh`; full output in `tests/logs/run-20261030.txt`.
Started 2026-10-30 09:10:13 GMT, finished 09:10:28 GMT (times from `date` at run time). Box: Linux, Python 3.13.5, npm 11.21.1, **n8n 2.45.7** (npm, current `latest`/`stable` tag).

**Result: 3/3 steps passed, `FAILED STEPS: 0`. 20/20 tests (15 scanner, 3 npm cross-checks with per-node subtests, 2 real-n8n round trip).**

## What is real and what is not
- **Real:** the shipped `scripts/n8n3_scan.py` run as a module and as a CLI. Real npm packages `n8n-nodes-base` and `@n8n/n8n-nodes-langchain` at 2.45.6, 2.46.3 and 3.0.1 (`npm pack`, reading `dist/types/nodes.json`). A real n8n 2.45.7 CLI importing and exporting the fixture workflows into a throwaway SQLite user folder.
- **Not tested at first: n8n 3.0 itself** (superseded: see "Real-app verification 2026-10-30" below, where workflows were run on a real n8n 3.0.1). 3.0 is Docker-only and Docker isn't available on the test box. The rules come from the official breaking-changes page (checked 30 Oct 2026) plus the npm node-list diff.
- **Not tested:** real customer exports, Kubernetes/Helm values, custom Dockerfiles, Windows paths, Python versions below 3.13 (the code uses only the standard library and targets 3.9+, but only 3.13.5 was run).
- Fixtures are hand-written and use real node type names and versions (checked against npm, below). Deployment fixtures (.env, docker-compose.yml, package.json) are made-up examples.

## 1. Scanner: `tests/test_scan.py` (15/15)
- All 9 removed node types in the fixture are found, with replacements; a removed trigger gets the "won't activate" note.
- Each workflow rule fires on its fixture node: AGENT-V1, EDIT-IMAGE-V1, SUBWORKFLOW-SOURCE, GETPAIREDITEM, EVALEXPR, SLACK-SIGNING-SECRET, GMAIL-TRIGGER, ALWAYS-OUTPUT, COMPRESSION-LIMITS, WEBFLOW-LEGACY, CHAT-WEBSOCKET, SSRF-CGNAT, COMMUNITY-NODES.
- A modern workflow (Schedule Trigger, HTTP Request 4.2, Set 3.4, AI Agent 3.1, Gmail Trigger 1.4, Edit Image 2, Execute Workflow from database) has **0 findings**.
- Slack Trigger is a blocker when published (`active` or `activeVersionId`) and a warning when not.
- CGNAT boundaries: 100.64.0.1 and 100.127.255.254 flagged; 100.63.255.255, 100.128.0.1 and 10.0.0.5 not.
- Input formats: folder of `--separate` files, CLI `--all` array, public API `{"data": [...]}`; archived skipped unless `--include-archived`; broken JSON reported without stopping the scan.
- Deployment: 1.x image -> FROM-1X; `package.json` dependency and `n8n start` script -> 2 NPM-INSTALL; 3 removed env vars (a commented-out line is ignored); binary mode `default`; `.n8n/binaryData` volume; missing task timeout; insecure-mode note; SSRF note. A clean 2.45.7 compose file gives 0 findings; a 2.20 image gives NO-MIGRATION-REPORT.
- CLI exit codes: 1 with blockers, 0 clean, 2 for a missing path or only-broken input; `--strict` turns warnings into exit 1; `--json` and `--markdown` output parse.
- SKILL.md has valid frontmatter and explains every rule id used in the code.

## 2. Against npm: `tests/test_against_npm.py` (3/3)
- **The scanner's removed-node list equals the npm diff exactly: 572 node types in 2.45.6, 535 in 3.0.1, 37 removed.**
- Every node type and `typeVersion` in the fixtures exists in real n8n 2.x packages.
- The node types the rules target still exist in 3.0.1, Gmail Trigger 1.4 exists in 2.45.6, and Edit Image v2 is in 2.46.3 and 3.0.1 but **not** in 2.45.6.

## 3. Real n8n 2.45.7 round trip: `tests/test_real_n8n.py` (2/2)
- `n8n import:workflow` of the unmodified fixtures is **rejected** by 2.45.7: "Cannot use a n8n-nodes-base.function node … this node type is deprecated". So current 2.x already refuses Function/Function Item on import (documented in the reference and the README for buyers restoring old backups).
- With those 2 nodes removed, the fixtures import, export with `export:workflow --all` and with `--all --separate --pretty`, and scanning either export gives **the same findings as the input** (13 blockers, 5 warnings, 2 notes). Slack Trigger is excluded from that comparison because CLI import unpublishes workflows, which correctly turns that blocker into a warning.

## Failures seen during development (fixed before the logged run)
1. First `test_scan.py` run: 1 error, `SKILL.md` not written yet. Fixed by writing it.
2. First full run: 1 failure. The "clean" fixture used Edit Image v2, which **doesn't exist in 2.45.6**. Checking npm showed v2 first ships in 2.46.x (the npm `beta`/`next` tag on 30 Oct). This was a real finding: the fix text now says to move to 2.46+ before moving Edit Image to v2, and the test checks it.

Nothing was published, deployed or sent. The npm cache (`tests/.npm-cache`, ~38 MB; moved out of the draft folder after the run) is a download cache and should be left out of the zip.

## Real-app verification 2026-10-30

Run by `N8N_BIN=n8n245/node_modules/.bin/n8n N8N3_CMD="n8n3-run/start.sh N8N_RUNNERS_BROKER_PORT=5695" N8N3_HOST_DATA=n8n3-run/data N8N3_DATA=/data bash tests/run_all.sh`. Full output is in `tests/logs/run-20261030-realapp.txt`. The run started at 12:12:40 GMT and finished at 12:13:33 GMT.

**Result: 4/4 steps passed, `FAILED STEPS: 0`. 24/24 tests: 17 scanner, 3 npm, 2 real n8n 2.45.7 and 2 real n8n 3.0.1.**

### How 3.0.1 was run
- npm has no runnable n8n 3.x. The image `n8nio/n8n:3.0.1` was pulled from Docker Hub with the registry API. Docker isn't installed, so its layers were unpacked to `/opt/n8n3/rootfs`.
- The image's own Node 26.12.1 and `n8n` CLI run in a chroot as uid 1000. Settings: `N8N_USER_FOLDER=/data`, SQLite, port 5690 on 127.0.0.1, and `N8N_RELEASE_TYPE=rc` as in the image.
- This is the real 3.0.1 code, not a mock. It is not Docker's network or cgroup setup, and the Python task runner isn't available in this image (n8n logs "Python 3 is missing").

### What was checked on real 3.0.1
- **Import and export.** `n8n import:workflow --separate` imported all 4 unmodified fixtures, including Function, Cron and Item Lists: "Successfully imported 4 workflows". It deactivated "Clean modern" and "Legacy everything".
  - **So 3.0.1 does not refuse removed nodes on import**, unlike 2.45.7. They fail only when run. Don't count on an import error to catch them.
  - The `export:workflow --all` output scanned to the same findings as the input.
- **Execution probes** (`tests/fixtures/probes-3x`, run with `n8n execute --id=…`). There are 9 probes: an Execute Workflow Trigger, a Set node, and the node under test. The rule is that a probe runs if and only if the scanner reports no blocker for it. All 9 agreed:

| Probe | Real 3.0.1 result | Scanner |
|---|---|---|
| Code node (`x*21`) | ran, `y: 42` | no findings |
| Function | `Unrecognized node type: n8n-nodes-base.function` | N3-NODE-REMOVED |
| Function Item | `Unrecognized node type: n8n-nodes-base.functionItem` | N3-NODE-REMOVED |
| Item Lists 3.1 | `Unrecognized node type: n8n-nodes-base.itemLists` | N3-NODE-REMOVED |
| HTML Extract | `Unrecognized node type: n8n-nodes-base.htmlExtract` | N3-NODE-REMOVED |
| Code with `$evaluateExpression` | `The function "$evaluateExpression" is not available in this context` | N3-EVALEXPR |
| Set with `$getPairedItem` | `$getPairedItem was removed. Use $('Node').item, …` | N3-GETPAIREDITEM |
| Edit Image v1 | `Edit Image versions 1 and 1.1 are no longer supported. Upgrade the node to version 2.` | N3-EDIT-IMAGE-V1 |
| Execute Workflow, source localFile | `The "Local File" source was removed. …` | N3-SUBWORKFLOW-SOURCE |

- **Node list.** The real 3.0.1 install has 535 node types in n8n-nodes-base and nodes-langchain. None of the scanner's 37 removed types is present.
- **n8n's own Migration Report rules.** 3.0.1 ships them in `dist/modules/breaking-changes/rules/v3`, 25 rule files. The scanner was compared with each one:
  - Their removed-node list (36, with AI Transform as its own rule) equals the scanner's 37.
  - Every workflow-level official rule has a scanner rule.
  - Instance-only rules the scanner can't see from files: Import from URL removed, external-secrets project-role default, Slack credential can't be saved without a signature secret. These are now listed in SKILL.md Limits and point to the Migration Report.

### Bugs found and fixed
1. **N3-AGENT-V1 gave the wrong mode and severity.** It labelled an AI Agent with no explicit mode as "toolsAgent (default)", and flagged every v<2 agent as a blocker.
   - n8n 3.0.1's own rule (`agent-node-mode.js`) treats no mode as **Conversational Agent up to v1.5** and Tools Agent from v1.6. Only the Conversational, OpenAI Functions, Plan and Execute, ReAct and SQL modes fail. A v1.6–1.9 Tools Agent "will run with version 2 behavior" (a warning).
   - Fixed to match, with a new test `test_agent_mode_resolution_matches_n8n_301`.
2. **Missing: Chat hub off by default.** This is in the official notes and in 3.0.1's `chat-hub-deprecated` rule. Added **N3-CHAT-HUB** (note) for when a deployment is checked and `N8N_ENABLED_MODULES` lacks `chat-hub`. The tests were updated: a clean deploy now gives exactly this note, and listing `chat-hub` gives 0.
3. **Missing: both storage directories exist, so 3.0 fails to start.** This is in the official notes and in `storage-path-rename.rule.js`. Added **N3-STORAGE-BOTH** (blocker) for a `.n8n` folder under `--deploy` containing both `binaryData` and `storage`. N3-STORAGE-PATH and N3-STORAGE-BOTH are now skipped when `N8N_STORAGE_PATH` or `N8N_BINARY_DATA_STORAGE_PATH` is set, as in n8n's rule. New test: `test_storage_both_dirs`.
4. SKILL.md said N3-NO-MIGRATION-REPORT was a warning. The code emits a note; the doc was fixed. The rule count is now **25: 11 blockers, 9 warnings, 5 notes** (README and LISTING updated).
5. `test_against_npm.py` crashed with `TimeoutExpired` on a fresh cache: npm wrote the tarball but didn't exit within 300 s. It now uses the tarball if it is complete, otherwise it skips.

### Official 3.0 notes vs this pack (docs.n8n.io/changelog/v30-breaking-changes, fetched 2026-10-30)
- Covered: removed nodes, AI Agent < 2, Edit Image < 2, sub-workflow sources, `$getPairedItem`, `$evaluateExpression`, Slack signing secret, Gmail Trigger 1.4, Always Output Data, compression limits, Webflow legacy, chat WebSocket JSON, SSRF ranges, removed env vars, binary data mode, task-runner timeout, unverified community packages, storage rename, Docker-only, 1.x to 3.x path. Chat hub and both-directories were added today.
- Not covered, and needing no file-level action: encryption-key rotation on by default, the Ask AI tab removed, community-node `defaults.color` and `n8n-node` dev-tool changes (node authors only).
- The docs call 3.0 early access; the image is tagged `rc`.

Still not tested: a real Docker or Kubernetes deployment, the Migration Report UI and REST endpoint (not run here; its rule code was read), real customer exports.

## Re-run 2026-11-02 (promoted from drafts/2026-10-30 to products/)
`N8N_BIN=n8n245/node_modules/.bin/n8n N8N3_CMD="n8n3-run/start.sh N8N_RUNNERS_BROKER_PORT=5695" … bash tests/run_all.sh`; full output in `tests/logs/run-20261102.txt`, started 2026-11-02 07:13:46 GMT, finished 07:14:58 GMT.
**Result: `FAILED STEPS: 0`, 24/24 tests:** 17 scanner, 3 npm cross-checks, 2 real n8n 2.45.7, 2 real n8n 3.0.1 (chroot of the official 3.0.1 image, as above).
Extra finding on 3.0.1 (from the Stripe Access Drift Check tests, same day): on a never-started 3.x instance `n8n import:credentials` fails with "No active encryption key found"; 3.x creates the key on the first `n8n start` (`dist/encryption/encryption-bootstrap.service.js`, main instance only). Worth adding as a NOTE rule in v1.1 (not added yet; the scanner is unchanged).

## Pre-launch re-run 2026-11-02
Same command as above, with real n8n 2.45.7 and the real n8n 3.0.1 chroot; full output in `tests/logs/run-20261102-prelaunch.txt`, started 08:00:30 GMT, finished 08:01:35 GMT. **`FAILED STEPS: 0`, 24/24 tests** (17 scanner, 3 npm, 2 real n8n 2.45.7, 2 real n8n 3.0.1). Counts unchanged. Box-specific install paths in the run commands above were shortened (e.g. `n8n245/...`, `n8n3-run/...`); the commands are otherwise as run.
