From 4a394d975e9170de86348f89ee6bbb7d995b515a Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Fri, 8 May 2026 15:59:21 +0200 Subject: [PATCH 1/5] fix: Assert expected hooks for restricted method specifications --- packages/snaps-rpc-methods/src/permissions.ts | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/snaps-rpc-methods/src/permissions.ts b/packages/snaps-rpc-methods/src/permissions.ts index bed80afdec..c39f5d0ac3 100644 --- a/packages/snaps-rpc-methods/src/permissions.ts +++ b/packages/snaps-rpc-methods/src/permissions.ts @@ -1,4 +1,4 @@ -import { selectHooks } from '@metamask/json-rpc-engine/v2'; +import { selectHooks, assertExpectedHooks } from '@metamask/json-rpc-engine/v2'; import { createRestrictedMethodMessenger, type PermissionConstraint, @@ -70,8 +70,20 @@ export const buildSnapRestrictedMethodSpecifications = ( excludedPermissions: string[], hooks: Record, messenger: RestrictedMethodMessenger, -) => - Object.values(restrictedMethodPermissionBuilders).reduce< +) => { + const permissionBuilders = Object.values(restrictedMethodPermissionBuilders); + + const expectedHookNames = new Set( + permissionBuilders.flatMap((builder) => + builder.methodHooks + ? Object.getOwnPropertyNames(builder.methodHooks) + : [], + ), + ); + + assertExpectedHooks(hooks, expectedHookNames); + + return permissionBuilders.reduce< Record >( ( @@ -94,3 +106,4 @@ export const buildSnapRestrictedMethodSpecifications = ( }, {}, ); +}; From 1453f3a148291d2cf546a9dba4b16875f9cf1396 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Mon, 11 May 2026 10:30:25 +0200 Subject: [PATCH 2/5] Fix issues after asserting hooks --- packages/snaps-rpc-methods/src/permissions.test.ts | 9 ++++++++- packages/snaps-simulation/src/methods/specifications.ts | 4 +++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/snaps-rpc-methods/src/permissions.test.ts b/packages/snaps-rpc-methods/src/permissions.test.ts index 013f5587a3..55e9fb1a67 100644 --- a/packages/snaps-rpc-methods/src/permissions.test.ts +++ b/packages/snaps-rpc-methods/src/permissions.test.ts @@ -197,7 +197,14 @@ describe('buildSnapRestrictedMethodSpecifications', () => { it('returns the expected object', () => { const specifications = buildSnapRestrictedMethodSpecifications( [], - {}, + { + getUnlockPromise: jest.fn(), + getClientCryptography: jest.fn(), + isOnPhishingList: jest.fn(), + maybeUpdatePhishingList: jest.fn(), + getSnapKeyring: jest.fn(), + getPreferences: jest.fn(), + }, new Messenger({ namespace: 'SnapsRestrictedMethods' }), ); expect(specifications).toMatchInlineSnapshot(` diff --git a/packages/snaps-simulation/src/methods/specifications.ts b/packages/snaps-simulation/src/methods/specifications.ts index 9754ec4f2b..36579c42a9 100644 --- a/packages/snaps-simulation/src/methods/specifications.ts +++ b/packages/snaps-simulation/src/methods/specifications.ts @@ -73,6 +73,7 @@ export function getPermissionSpecifications({ hooks, options, }: GetPermissionSpecificationsOptions): PermissionSpecificationMap { + const { getClientCryptography } = hooks; return { [caip25EndowmentBuilder.targetName]: caip25EndowmentBuilder.specificationBuilder({}), @@ -81,11 +82,12 @@ export function getPermissionSpecifications({ EXCLUDED_SNAP_PERMISSIONS, { // Shared hooks. - ...hooks, + getClientCryptography, // Snaps-specific hooks. getPreferences: getGetPreferencesMethodImplementation(options), getUnlockPromise: asyncResolve(true), + getSnapKeyring: asyncResolve(null), // TODO: Allow the user to specify the result of this function. isOnPhishingList: resolve(false), From 7c9ad72eb5d07a3c90b8690da3914464aa1d0c79 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Mon, 11 May 2026 11:06:29 +0200 Subject: [PATCH 3/5] Update coverage --- packages/snaps-rpc-methods/jest.config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/snaps-rpc-methods/jest.config.js b/packages/snaps-rpc-methods/jest.config.js index 9d6aa634ac..9fd3f0d8ca 100644 --- a/packages/snaps-rpc-methods/jest.config.js +++ b/packages/snaps-rpc-methods/jest.config.js @@ -10,8 +10,8 @@ module.exports = deepmerge(baseConfig, { ], coverageThreshold: { global: { - branches: 97.28, - functions: 98.84, + branches: 97.3, + functions: 98.85, lines: 99.14, statements: 98.81, }, From 4616290244339cd1827a494bd7de1ffee8f7bdfe Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Mon, 11 May 2026 11:14:46 +0200 Subject: [PATCH 4/5] Filter out excluded permissions before asserting hooks --- .../snaps-rpc-methods/src/permissions.test.ts | 17 ++++++++++++ packages/snaps-rpc-methods/src/permissions.ts | 26 +++++++++---------- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/packages/snaps-rpc-methods/src/permissions.test.ts b/packages/snaps-rpc-methods/src/permissions.test.ts index 55e9fb1a67..068f6b8743 100644 --- a/packages/snaps-rpc-methods/src/permissions.test.ts +++ b/packages/snaps-rpc-methods/src/permissions.test.ts @@ -323,4 +323,21 @@ describe('buildSnapRestrictedMethodSpecifications', () => { } `); }); + + it('excludes the specified permissions', () => { + const specifications = buildSnapRestrictedMethodSpecifications( + ['snap_dialog'], + { + getUnlockPromise: jest.fn(), + getClientCryptography: jest.fn(), + isOnPhishingList: jest.fn(), + maybeUpdatePhishingList: jest.fn(), + getSnapKeyring: jest.fn(), + getPreferences: jest.fn(), + }, + new Messenger({ namespace: 'SnapsRestrictedMethods' }), + ); + + expect(specifications.snap_dialog).toBeUndefined(); + }); }); diff --git a/packages/snaps-rpc-methods/src/permissions.ts b/packages/snaps-rpc-methods/src/permissions.ts index c39f5d0ac3..a974957022 100644 --- a/packages/snaps-rpc-methods/src/permissions.ts +++ b/packages/snaps-rpc-methods/src/permissions.ts @@ -71,7 +71,9 @@ export const buildSnapRestrictedMethodSpecifications = ( hooks: Record, messenger: RestrictedMethodMessenger, ) => { - const permissionBuilders = Object.values(restrictedMethodPermissionBuilders); + const permissionBuilders = Object.values( + restrictedMethodPermissionBuilders, + ).filter((builder) => !excludedPermissions.includes(builder.targetName)); const expectedHookNames = new Set( permissionBuilders.flatMap((builder) => @@ -90,18 +92,16 @@ export const buildSnapRestrictedMethodSpecifications = ( specifications, { targetName, specificationBuilder, methodHooks, actionNames }, ) => { - if (!excludedPermissions.includes(targetName)) { - specifications[targetName] = specificationBuilder({ - methodHooks: selectHooks(hooks, methodHooks), - messenger: createRestrictedMethodMessenger({ - namespace: targetName, - rootMessenger: messenger, - actionNames: actionNames as readonly [ - RestrictedMethodActions['type'], - ], - }), - }); - } + specifications[targetName] = specificationBuilder({ + methodHooks: selectHooks(hooks, methodHooks), + messenger: createRestrictedMethodMessenger({ + namespace: targetName, + rootMessenger: messenger, + actionNames: actionNames as readonly [ + RestrictedMethodActions['type'], + ], + }), + }); return specifications; }, {}, From 6640a8d20269b199e4c42233826756f2c9af664d Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Mon, 11 May 2026 11:16:49 +0200 Subject: [PATCH 5/5] Update coverage --- packages/snaps-rpc-methods/jest.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/snaps-rpc-methods/jest.config.js b/packages/snaps-rpc-methods/jest.config.js index 9fd3f0d8ca..7756db68a4 100644 --- a/packages/snaps-rpc-methods/jest.config.js +++ b/packages/snaps-rpc-methods/jest.config.js @@ -10,7 +10,7 @@ module.exports = deepmerge(baseConfig, { ], coverageThreshold: { global: { - branches: 97.3, + branches: 97.29, functions: 98.85, lines: 99.14, statements: 98.81,