[base-controller] Controller constructors accept messengers with incomplete allowlists
- Dominant language
- TypeScript
- Stars
- 413
- Forks
- 308
- Avg merge
- 1d 4h
- Merged PRs (30d)
- 253
Description
## Problem
`BaseControllerV2` and its subclass controllers currently accept messengers as constructor options even if they are defined with incomplete or empty action/event allowlists.
Type errors are raised when the omitted actions/events are invoked. Runtime errors are also thrown when the `call`, `subscribe`, `unsubscribe` methods are invoked (or any method that uses the `#isAllowedAction`, `#isAllowedEvent` methods). However, these errors are produced by the messenger, not the controller.
Controller constructors do correctly raise type errors for messengers that allow actions or events that are not included in the controller's allowlists.
## Repro
```ts
/**
* Controller accepts messenger with "empty" allowlists
*/
const emptyAllowlistControllerMessenger =
new ControllerMessenger() // ControllerMessenger can be defined with any superset of the RestrictedControllerMessenger's empty allowlists
const emptyAllowlistMessenger = emptyAllowlistControllerMessenger.getRestricted({
name: '',
allowedActions: [],
allowedEvents: [],
})
const preferencesController = new PreferencesController({
messenger: emptyAllowlistMessenger, // No type or runtime error!
})
/**
* Controller accepts messenger with "incomplete" allowlists
*/
type TokenRatesControllerAllowedActions =
| PreferencesControllerGetStateAction
| NetworkControllerGetStateAction
| NetworkControllerGetNetworkClientByIdAction
| TokensControllerGetStateAction
type TokenRatesControllerAllowedEvents =
| TokensControllerStateChangeEvent
| PreferencesControllerStateChangeEvent
| NetworkControllerStateChangeEvent
const incompleteAllowlistControllerMessenger = new ControllerMessenger<
Exclude,
Exclude
>() // ControllerMessenger can be defined with any superset of the RestrictedControllerMessenger's incomplete allowlists
const incompleteAllowlistMessenger = incompleteAllowlistControllerMessenger.getRestricted({
name: 'TokenRatesController',
allowedActions: [
// 'NetworkController:getNetworkClientById',
'NetworkController:getState',
'PreferencesController:getState',
'TokensController:getState',
],
allowedEvents: [
// 'NetworkController:stateChange',
'PreferencesController:stateChange',
'TokensController:stateChange',
],
})
const incompleteTokenRatesController = new TokenRatesController({
messenger: incompleteAllowlistMessenger, // No type or runtime error!
tokenPricesService: buildMockTokenPricesService(),
})
```
> [**Playground link**](https://www.typescriptlang.org/play/?#code/JYWwDg9gTgLgBDAnmApnA3nAKhA1igOwGcBhCAmKCAG2pSgHEUYBlGAQxhQEEBjGYOQA02PIVLlKNOlDacUJABbsCAcxQBRAG6F4AXzgAzKiDgByAAIhm7EOyK4A9PaLMiAWl6SqtekTMAUKCQsBii+AQASvISFD4ycAbGEKaW1hx2Ds5ErjAeXnHSfoHB0PCYZIW+UACyKDmE6lCJRibmVjaZTgBG9iie3kVQJeBlCMhomAByzADu0LiVUtVMrBxcfALCcDMw81CLgyvMu-uL1MC6AEKIAJIAJpuCBCKnC0vx9HJcSirq2roWslUh0MvYnAQ5gsBlUZCMQvAkKgwgAFKAoQz0Qi8eofIarb48fjPERojFYgg42LLGSE35qTQ6ChAtppTrgxxgdGY9GU+owmn0eFjTBknnY3FHBJJVmg2wcrnk3lUgWfYZBUahJGTbBQFREdjE8h445reRPcgslLtdLyrKUfWGrYEVVDQIBRwAKk9ATgnrgJoShpxYDycGsDQZzVmwBgijgACIUOAkAm4OxaBBZhciHlfZ7HAEAgVc3Bk6HENxM9ngLnA-Q6pGmnAALxwX1wSGzANShv1VxRgA8kJ0UBEI-oAD4ABQASjgjkcPdhfab9DgvBUcG6aHuGOAkPucBjcfTBEQcCIAFdUFBcnAIIYEIo0JF6pRgPwUPd67V+40hSIMsUwvDNqCzHM8xLeByyQKtwJrXNGwHZs21gytq0g39kIAqAADp1BgN9cygT8uHuad0A7OBO1sFAAC5zDMIRqPTatvwtYhGIAbQAXRYmiaLArNvwBCgiB4-iOz0WcO2LchS0VcU+WpNVW07FBuzFCkqV-SiOwjFD6EY9D4Ig2sYBwqMWJkosvR9P1l0FZpgxQUMgMM3Dj1jeMEwPLxwDoLg02ExC8z9QsAm1cJCGiLhVKGMzZg4o1iHUjsAB8YuIX8CXWIlnUynYoQOXKThK85LgoG4Hk49saKyt5St7RhmEJTiiu05VJRXVqzQ2VL22inAIjinrnKS0SmTDNsiqaw5erpZQGTEmBOu5HTxrVJa-kZQEipG8Rfx2lbpvbeTiHgfyUjAIKeEwizsP-KN1K7Jy1SsppBw7DQAA9eGoK890HQ6ohiX9JseVKiFeCqypgeaSAua47ih51JxEH7-sB4HQbGhLqkh1aYeKvZ3havLzVSycAhnedF3eoZPvXTcCG3Xd90PbzTxUC9r1ve9H2fV931Ir8fxa5nhiA67AuYNBQsgogLtLWXbvlpLIKl9S1buzXHsl56mgI5hiI-cX9ME2jrEYsw8fBlrmNY0KUudCS4G41iaLtsQcpa+jCMJJ2rZohmzER-3CMR5HqtR4OQ-DuHI7a-L46tswuolAmZADlP5DTuApKtl37mJnivYXJdE7J5revo3N5HpdQC+9zOVN-ev8qblAW-MUHs+MhufmW5uBMEovElklWrspG67vt+Lf1ezTsvxvSqJozyo0Y3WNYepCjfoMeYF9tFP3qFh6C0c-GO6K9gGoe4aggXhcFBs+qUvqBr5xOcbKnwwV5KTOm3PfR+z9X7vzFhfK+585wYA7OiGAV4oBsw3oJewiBKRGGYLwRQUDz5EHgegq2SCUFoL0AAblYnoMeNEtAZmAPcRuygDwPBYDeBE35pwAH08HsDYfcRiQDcAECzAQWcjE+GsIIA8OAtY4AAAMAAMv0AAk6ASIHlUHoRRCCQ5wDIaghAUArwoGoVbWhrEGEXGYT8FBypEAcLAFwiifCHHYkQMIggojxGSLgO4qAjj5FAS0WofRIcjFs0oGYixgkrE0T0AEJJHpvT5kZtUOA9wID1B2AAeSwOmXgIZ4Bb2bCeXyatODAG6HQEK+9woFiLNBeRs9wDVNqfdBCWFDZrmaG2N6T0+nfRogvLaiV2Jo2eEBLKWA9TECdM8eG7VUqY1Gb7NeLUibTWVnTaerSApgA6XQfWB8+k6zaUcgQnTTkwCGUZfChEzZi3IpbQSBA6K2zGQPYYdC2IIVdtM8uBjq5nA7lHOGMcYA1XuL3UF5M66B1Tn81uG1uo-Nzv1HuKK+6+wxUi-OOK7bzINKlcFecuDMUromKp1y6lFMKlbCeQlJllw9hXeFtdnKdxYbtOFbddL+yHgoEe2KOX9w7sK7uBcJ62X2bSmpdBvlLwGSvZVLV9IMywBMcwzyyLfnubhQcCZ1W9QTKSNFWdln5Tqo1JOvVKYDRAXamuC1nKrGjlVaFqNbXZR+Y6gqzw4CzJJYs40FMKWBu2AK8Z1QTr-DOllPCya4AAEZwzQDQMmvCwbSZgpaiwbNZgQmdggPAFwwBVAfM6QgCA4xkQ+1Gg7XqUszB4Q9EuUZEwgJCy5BAW8SBzDolUBZegnEAASKh7hwnTOiA5N1jkoHbQzK22rUA9qfEcvU6Q-DmGWtOoUZ4jxmH3TO9gc6FWdOXZ2kOa60AZ0tSpQkub5rPtmXi46+Vc2mucm+uA3ArwnxqCodg6h7iet0IObNk5i0KLEeWnIlbq10FrfW+9MaiB-tfV+99EQfl-rmY6MlBacP-sAxAYDHywMQYoFB5NMHr0GMEne3FTbF4kfziW+D6ZENVvYDWk+aHzAYawxVAjH6ONcG-aG4ji1SMAaAyB6jkKvV0bwgx6cAAmAAzJpzTslN6HygDvS5i7blS2PqfaBmHYE4lvmAp+L835WcIV-H+KA-7JNnEAA)
## Acceptance Criteria
Controllers inheriting from `BaseControllerV2` must raise a type and/or runtime error if they are initialized with a messenger that does not explicitly allow ALL of the actions or events in the controller's allowlists.
## References
- Related: https://github.com/MetaMask/core/issues/4213 Requirements no. 2
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by locating the BaseControllerV2 constructor and its allowlist checks, then compare the PreferencesController and TokenRatesController construction paths. Add focused type and runtime coverage for empty and incomplete action/event allowlists; done when every BaseControllerV2-derived controller rejects messengers that do not explicitly allow all required actions and events.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend-api-design
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100