feat: Deprecate the "Any workflow" caller policy

Merged
RI
2mo ago
+353-8

Summary

The workflow setting This workflow can be called by → Any workflow lets a sub-workflow be called from any project on the instance, which bypasses project permissions: anyone who knows the workflow ID can run it. v3 drops the option.

This PR removes nothing yet. It only deprecates, so people can move off the setting before they upgrade. The deletion will be a separate PR against 3.x, per DEVELOPING_V3.md.

Three channels tell them:

  • The workflow settings dropdown labels the option Any workflow (deprecated), and when that is the selected policy it shows a warning naming the version the option goes away in and which policy to pick instead.
  • Two v3 breaking-change rules in the migration report, described below.
  • The MCP tool and public API descriptions, so agents and integrators stop picking the value we are about to remove. Description text only, the enums are unchanged.

Why two report rules

The remedies differ, so the rules do too.

A workflow that stores any itself needs its own owner to pick a new policy. That is caller-policy-any-removed-v3, a workflow rule listing one row per workflow.

A workflow that stores nothing inherits N8N_WORKFLOW_CALLER_POLICY_DEFAULT_OPTION, which SubworkflowPolicyChecker resolves the same way. On an instance defaulting to any, nearly every workflow is affected by a single misconfiguration, so reporting them per workflow would bury the ones needing individual edits under thousands of rows sharing one one-line fix. That is caller-policy-default-any-v3, an instance rule reported once, in the report's separate instance tab.

Both commonly appear together, because saving a workflow's settings writes the instance default into that workflow. On an any-defaulted instance, workflows accumulate a stored any through ordinary editing. So neither fix covers the other, and each entry says so.

Notes for the reviewer

  • The caller policy field normally requires the Sharing feature, but the policy is enforced regardless of license (workflow-execute-additional-data.ts:542). An instance that downgraded, or whose license lapsed, can still be sitting on any with no way to see or change it, and on Community that is the main way a workflow ends up holding the value. The field is shown to those instances too, but only when the policy is any. The condition is latched when the dialog opens, so the row does not disappear mid-edit once another policy is picked.
  • Severity is medium to match every other v3 rule. The tracker rates this High, but the enum is low | medium | critical and being the only critical rule in the codebase would read as inflation next to removed nodes.
  • The report renders only the rule title, description and docs link. Per-issue descriptions and recommendations are never displayed, so the remedy lives in the description and the rest is API-only.
  • Workflow settings were not loaded during breaking-change detection, so they are added to the rule select in breaking-changes.service.ts.
  • The detail table linked every issue to a node, which produced /workflow/<id>/undefined for a workflow-level issue. It now links only issues that carry a node. Every other rule is node-anchored, so this rule is the first to hit it.
  • Showing the field without Sharing makes an existing label bug easier to hit, where the same-owner option reads "Only workflows in Only workflows in the same project". That is a separate pre-existing bug, reproducible on master, so it is split out into #36353. Worth landing that one first, since the two touch the same lines and will otherwise conflict.
  • MIGRATION_REPORT_TARGET_VERSION is still null, so the report rules reach nobody until that flips with the v3 announcement. The settings warning does not depend on it.

How to test

Two things are off by default and have to be enabled locally, otherwise most of this is invisible.

1. Turn the migration report on. In packages/@n8n/api-types/src/schemas/breaking-changes.schema.ts:

export const MIGRATION_REPORT_TARGET_VERSION: BreakingChangeVersion | null = 'v3';

Rebuild @n8n/api-types, n8n and n8n-editor-ui after changing it, since both the backend module and the settings sidebar entry read it. Note this also lights up every other v3 rule, so expect other entries alongside these two.

2. Make the caller policy field visible. It sits behind the Sharing feature. With a licence, nothing to do. Without one, start n8n with E2E_TESTS=true and toggle it:

curl -X PATCH http://localhost:5678/rest/e2e/feature \
  -H 'Content-Type: application/json' \
  -d '{"feature":"feat:sharing","enabled":true}'

That toggle is in memory, so re-run it after every restart.

The deprecation in workflow settings

  1. Open any workflow, Actions > Settings, and set This workflow can be called by to Any workflow (deprecated). Save.
  2. Reopen settings. The option is labelled deprecated and an amber notice below the field names version 3 and what to switch to.
  3. Change the policy to anything else. The notice disappears, but the field stays visible so the change can be saved. Reopen and it is gone for good.
  4. Check a workflow on another policy: no notice.

The field without the Sharing feature

Disable Sharing again ("enabled":false on the call above, or use an unlicensed instance).

  1. Open a workflow that stores any. The field is still there, with the warning, so the value can be abandoned. This is the downgraded or lapsed licence case.
  2. Open a workflow on any other policy. The field is hidden, as before this PR.

The two report rules

  1. Create a workflow that stores any explicitly, and a second one that never had its settings saved, so it stores no callerPolicy at all. The quickest way to confirm which is which is GET /rest/workflows?filter={} and reading settings.callerPolicy.
  2. Open Settings > Migration Report. Under workflow issues, only the workflow that stores any is listed. The one storing nothing is not, by design.
  3. Restart with N8N_WORKFLOW_CALLER_POLICY_DEFAULT_OPTION=any. An entry now appears under instance issues, covering every workflow that stores no policy of its own. The workflow tab is unchanged: it still lists only the explicit ones, however many workflows the instance has.
  4. Set the variable back to workflowsFromSameOwner and restart. The instance entry disappears, the workflow rows stay.

The report is cached, so after changing data or config use the refresh action on the report page rather than trusting a page reload.

A wrinkle worth seeing

  1. With the default still any, open the settings of a workflow that stores no policy and just hit Save without changing anything. It now stores callerPolicy: "any" and moves from the instance entry to the workflow list. The settings modal materialises unset settings into concrete values before saving, which is long-standing behaviour and not introduced here, but it is why both report entries usually appear together on an any-defaulted instance.

Related Linear tickets, Github issues, and Community forum posts

https://linear.app/n8n/issue/ADO-4923

Review / Merge checklist

  • I have seen this code, I have run this code, and I take responsibility for this code.
  • PR title and summary are descriptive.
  • Docs updated or follow-up ticket created.
  • Tests included.