Skip to content

fix: v1.8.1 — --dry-run no longer mutates on activate/deactivate - #5

Merged
trngthnh369 merged 1 commit into
mainfrom
fix/dry-run-guard-activate
Aug 15, 2026
Merged

trngthnh369 merged 1 commit into
mainfrom
fix/dry-run-guard-activate

Conversation

@trngthnh369

Copy link
Copy Markdown
Owner

The bug

workflow activate and workflow deactivate ignored --dry-run and performed the
change anyway.
All 25 other mutation verbs guard on the flag, so a caller reasonably
treats --dry-run as a safe way to see what a script would touch on production:

$ n8nctl workflow --dry-run deactivate <id>
○ deactivated workflow <id> "Sub: Content Generator"     # ← it actually did it

A --dry-run that mutates is doing the opposite of its contract, and this is the more
damaging half: it takes a live workflow offline.

How it surfaced

Running that exact command against the live instance while verifying the 1.8.0
release — it printed deactivated where [dry-run] was expected. No damage: the
target was already inactive and updatedAt never moved (still 2026-05-13), confirmed
before and after.

It is pre-existing, not introduced by 1.7.0/1.8.0. It was raised as a LOW
"out-of-scope" note during the #3 review and deprioritised there — which in hindsight
undersold it, since the flag's entire purpose is production safety.

The fix

Both handlers now GET the workflow, print a [dry-run] preview, and issue no write:

$ n8nctl workflow --dry-run deactivate <id>
[dry-run] would deactivate workflow <id> "Sub: Content Generator" (already inactive — no change)

The preview flags a no-op so a dry run doesn't imply a change that wouldn't happen, and
is machine-readable under --json ("dryRun": true, "alreadyInactive": …).

Tests

The regression tests assert the POST is never issued, not just the wording — a
--dry-run bug is exactly what a passing "it printed something" test would miss:

env.apiMock.onPost('/workflows/42/deactivate').reply(() => { posted = true; … });
await deactivateHandler(env.factory, {}, ['42']);
expect(posted).toBe(false);

516 tests (+5), coverage gate green, lint/build/audit clean. Re-verified against the
live instance: updatedAt unchanged after the fix.

Not tagged — v1.8.1 is bumped in package.json + CHANGELOG.md.

🤖 Generated with Claude Code

`workflow activate` and `workflow deactivate` ignored --dry-run and performed
the change anyway. Every other mutation verb (25 of them) guards on the flag,
so a caller reasonably treats --dry-run as a safe way to see what a script
would touch on production — `n8nctl workflow --dry-run deactivate <id>` took a
live workflow offline instead.

Found the hard way: running that exact command against the live instance while
verifying the 1.8.0 release printed "deactivated" where "[dry-run]" was
expected. No damage — the target was already inactive and updatedAt never
moved — but the flag was doing the opposite of its contract.

Both handlers now GET the workflow, print a [dry-run] preview (noting when it
would be a no-op), and issue no write.

The regression tests assert the POST is never issued, not just the wording, so
the guard cannot decay into a cosmetic message change. A --dry-run that
mutates is exactly the kind of bug a passing "it printed something" test would
have missed.

Pre-existing, not introduced by 1.7.0/1.8.0 — flagged as a LOW/out-of-scope
note during the #3 review and deprioritised there, which in hindsight
undersold it: the flag's whole purpose is production safety.

516 tests (+5), coverage gate green, lint/build/audit clean.
@trngthnh369
trngthnh369 merged commit f75a55c into main Aug 15, 2026
7 checks passed
@trngthnh369
trngthnh369 deleted the fix/dry-run-guard-activate branch August 15, 2026 12:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant