Skip to content

fix(core): Remove insights:read scope from member API keys#30906

Open
konstantintieber wants to merge 3 commits into
masterfrom
ligo-550-remove-insights-read-from-member-api-keys
Open

fix(core): Remove insights:read scope from member API keys#30906
konstantintieber wants to merge 3 commits into
masterfrom
ligo-550-remove-insights-read-from-member-api-keys

Conversation

@konstantintieber
Copy link
Copy Markdown
Contributor

@konstantintieber konstantintieber commented May 21, 2026

Summary

Migration to remove insights:read scope from API keys that have been created by members in n8n versions spanning 2.16.x to 2.22.x.
See #27868 and #30778

While this migration makes sense on a technical level, I'm still not sure if we should merge it, since the data that a member gets access to by having insights:read scope on an API key is not sensitive.
I am leaning towards not merging this migration, but would like to hear the migration's team opinion.

Related Linear tickets, Github issues, and Community forum posts

closes https://linear.app/n8n/issue/LIGO-550/

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. (conventions)
  • Docs updated or follow-up ticket created.
  • Tests included.
  • PR Labeled with Backport to Beta, Backport to Stable, or Backport to v1 (if the PR is an urgent fix that needs to be backported)

@konstantintieber konstantintieber requested a review from a team as a code owner May 21, 2026 13:28
@n8n-assistant
Copy link
Copy Markdown
Contributor

n8n-assistant Bot commented May 21, 2026

Recommended reviewers

Based on ownership of the 5 changed files in this PR:

Team Files owned Share
@n8n-io/migrations-review 4 80%
@n8n-io/catalysts 1 20%

FROM ${userApiKeysTable}
JOIN ${userTable} ON ${userApiKeysTable}.${userIdCol} = ${userTable}.${idCol}
WHERE ${userTable}.${roleSlugCol} = 'global:member'
AND ${userApiKeysTable}.${createdAtCol} >= '2026-04-06'
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This date filter is here because Apr 7th is the day that the insights:read scope was added to members for the first time: #27868 (comment)

@codecov
Copy link
Copy Markdown

codecov Bot commented May 21, 2026

Codecov Report

❌ Patch coverage is 12.50000% with 28 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...000009-RemoveInsightsReadScopeFromMemberApiKeys.ts 6.66% 14 Missing ⚠️
...000009-RemoveInsightsReadScopeFromMemberApiKeys.ts 6.66% 14 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 5 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/@n8n/db/src/migrations/postgresdb/1784000000009--RemoveInsightsReadScopeFromMemberApiKeys.ts">

<violation number="1" location="packages/@n8n/db/src/migrations/postgresdb/1784000000009--RemoveInsightsReadScopeFromMemberApiKeys.ts:25">
P1: Role filter uses current user role, not role at key creation. Keys created by members can be missed after role changes. Use a key-selection rule that does not depend on mutable current role.

According to linked Linear issue LIGO-550, this does not fully match the migration target.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant App as Application
    participant Migration as DB Migration
    participant PSql as PostgreSQL DB
    participant SQLite as SQLite DB
    participant UserTable as user Table
    participant ApiKeyTable as user_api_keys Table

    Note over App,SQLite: Startup Migration Phase

    App->>Migration: Run migration: RemoveInsightsReadScopeFromMemberApiKeys1779321600000
    Migration->>Migration: Execute up() method

    alt PostgreSQL Database
        Migration->>PSql: Query: SELECT id FROM user_api_keys JOIN user ON user_api_keys.userId = user.id
        PSql->>UserTable: WHERE user.roleSlug = 'global:member'
        PSql->>ApiKeyTable: AND user_api_keys.createdAt >= '2026-04-06'
        PSql->>ApiKeyTable: AND scopes::jsonb @> '["insights:read"]'
        UserTable-->>PSql: Matching user rows
        ApiKeyTable-->>PSql: Matching API key rows
        PSql-->>Migration: Return matching key IDs

        alt Matching keys found
            Migration->>PSql: UPDATE user_api_keys SET scopes = remove 'insights:read' FROM scopes JSONB
            PSql->>ApiKeyTable: COALESCE(json_agg(elem), '[]') excluding 'insights:read'
            ApiKeyTable-->>PSql: Updated rows
            PSql-->>Migration: Query complete
        else No matching keys
            Migration->>Migration: Return early, no update needed
        end

    else SQLite Database
        Migration->>SQLite: Query: SELECT id FROM user_api_keys JOIN user ON user_api_keys.userId = user.id
        SQLite->>UserTable: WHERE user.roleSlug = 'global:member'
        SQLite->>ApiKeyTable: AND user_api_keys.createdAt >= '2026-04-06'
        SQLite->>ApiKeyTable: AND EXISTS (SELECT 1 FROM json_each(scopes) WHERE value = 'insights:read')
        UserTable-->>SQLite: Matching user rows
        ApiKeyTable-->>SQLite: Matching API key rows
        SQLite-->>Migration: Return matching key IDs

        alt Matching keys found
            Migration->>SQLite: UPDATE user_api_keys SET scopes = remove 'insights:read' FROM scopes JSON
            SQLite->>ApiKeyTable: COALESCE(json_group_array(value), '[]') excluding 'insights:read'
            ApiKeyTable-->>SQLite: Updated rows
            SQLite-->>Migration: Query complete
        else No matching keys
            Migration->>Migration: Return early, no update needed
        end
    end

    Migration-->>App: Migration complete (irreversible)

    Note over App,SQLite: Scope affected: global:member users with insights:read API keys created on/after 2026-04-06
Loading

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

SELECT ${userApiKeysTable}.${idCol}
FROM ${userApiKeysTable}
JOIN ${userTable} ON ${userApiKeysTable}.${userIdCol} = ${userTable}.${idCol}
WHERE ${userTable}.${roleSlugCol} = 'global:member'
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot May 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Role filter uses current user role, not role at key creation. Keys created by members can be missed after role changes. Use a key-selection rule that does not depend on mutable current role.

According to linked Linear issue LIGO-550, this does not fully match the migration target.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/@n8n/db/src/migrations/postgresdb/1784000000009--RemoveInsightsReadScopeFromMemberApiKeys.ts, line 25:

<comment>Role filter uses current user role, not role at key creation. Keys created by members can be missed after role changes. Use a key-selection rule that does not depend on mutable current role.

According to linked Linear issue LIGO-550, this does not fully match the migration target.</comment>

<file context>
@@ -0,0 +1,46 @@
+			SELECT ${userApiKeysTable}.${idCol}
+			FROM ${userApiKeysTable}
+			JOIN ${userTable} ON ${userApiKeysTable}.${userIdCol} = ${userTable}.${idCol}
+			WHERE ${userTable}.${roleSlugCol} = 'global:member'
+			AND ${userApiKeysTable}.${createdAtCol} >= '2026-04-06'
+			AND ${userApiKeysTable}.${scopesCol}::jsonb @> '["insights:read"]'::jsonb
</file context>
Fix with Cubic

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optimizing for user role changes in this migration that removes a scope that gives access to non-sensitive data would be a bit too much.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for clarifying the scope here.

Comment thread packages/@n8n/db/src/migrations/postgresdb/index.ts Outdated
@n8n-assistant n8n-assistant Bot added the n8n team Authored by the n8n team label May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed n8n team Authored by the n8n team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant