Add the get_permissions plugin hook (contract 0.10.0)
Plugins declare their own RBAC permissions instead of core accumulating them: 36 permissions moved out of the core catalog into the 9 owning plugins (core keeps the 19 its own blueprints enforce). The catalog is resolved dynamically (core + enabled plugins) and feeds the roles grid, the token scope picker and ceiling, and flask seed permissions; installing or enabling a plugin seeds its permissions automatically. A disabled plugin drops out of the assignable catalog while existing role links keep working. New plugins - bundled or external - now bring their permissions with zero core edits. 781 tests pass; live-verified with a machines.edit-scoped token. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,7 @@ The contract is locked in [ADR-001](../docs/adr/ADR-001-asset-as-platform-contra
|
||||
The framework declares its contract version in `shopdb/__init__.py`:
|
||||
|
||||
```python
|
||||
__contract_version__ = '0.9.0'
|
||||
__contract_version__ = '0.10.0'
|
||||
```
|
||||
|
||||
Each plugin's `manifest.json` declares the range of contract versions it supports:
|
||||
@@ -216,6 +216,47 @@ Consumed by `GET /api/reports`, which merges plugin cards after the static core
|
||||
reports sorted into category groups by the frontend (disabled plugins are
|
||||
skipped; a broken plugin is isolated in prod, re-raised in dev/test).
|
||||
|
||||
### `get_permissions() -> List`
|
||||
|
||||
Returns the RBAC permissions this plugin owns. Added in contract 0.10.0. A
|
||||
plugin declares the permission names its own routes enforce via
|
||||
`require_permission`, instead of core accumulating every plugin's permissions in
|
||||
one catalog (plugin-is-the-product).
|
||||
|
||||
Each entry is a `(name, description, category)` tuple, matching the core
|
||||
permission catalog shape (dicts with those keys are also accepted). Names follow
|
||||
the naming convention (lowercase dotted, e.g. `machines.edit`).
|
||||
|
||||
```python
|
||||
class MachinesPlugin(BasePlugin):
|
||||
def get_permissions(self):
|
||||
return [
|
||||
('machines.view', 'View machines', 'machines'),
|
||||
('machines.create', 'Create machines', 'machines'),
|
||||
('machines.edit', 'Edit machines', 'machines'),
|
||||
('machines.delete', 'Delete machines', 'machines'),
|
||||
]
|
||||
```
|
||||
|
||||
Consumed by the core helper `full_permission_catalog()` (core permissions plus
|
||||
every ENABLED plugin's `get_permissions()`), which backs three consumers:
|
||||
|
||||
- `flask seed permissions` seeds the full catalog.
|
||||
- The role-management grid (`GET /api/users/permissions`) lists it, grouped by
|
||||
category.
|
||||
- API-token scope validation (`ApiToken.unknown_scope_names`) accepts a plugin
|
||||
permission as a scope only while that plugin is enabled.
|
||||
|
||||
Plugin install and enable also seed the plugin's own permissions idempotently,
|
||||
so enabling a fresh plugin creates its `Permission` rows without a separate seed
|
||||
pass.
|
||||
|
||||
Disabled-plugin edge case: a disabled plugin is skipped by the catalog, so its
|
||||
permissions are no longer offered for new scope grants or new role assignments.
|
||||
The `Permission` ROWS already in the database are NOT deleted, so roles that
|
||||
already reference them keep working until an admin edits the role. A broken
|
||||
plugin is isolated in prod and re-raised in dev/test.
|
||||
|
||||
### `get_settings_cards() -> List[Dict]`
|
||||
|
||||
Returns settings-catalog card definitions. Added in contract 0.7.0 (ADR-010).
|
||||
|
||||
Reference in New Issue
Block a user