Phase 2: define plugin contract surface and add compliance tests
Locks the public surface plugin authors at sister sites depend on.
Contract version (shopdb/__init__.py):
- __contract_version__ = '0.1.0'. Per ADR-002, plugins declare a
compatible range in manifest.json `core_version`. Pre-1.0 signals
the contract is still settling; sister sites should pin tightly.
BasePlugin hook changes (shopdb/plugins/base.py):
- Add get_collector_schema() per ADR-006. Returns JSON Schema (with
identityfield + fields) describing the payload of an external
collector pushing to /api/collector/<pluginname>. Defaults to None
(no auto-registered endpoint).
- Remove get_event_handlers(). Event bus deferred indefinitely per
ADR-001 (no real use case yet; add via new ADR if it appears).
Hook reference (docs/PLUGIN-HOOKS.md):
- Canonical reference for the contract: required hooks (meta,
get_blueprint, get_models), optional hooks (init_app,
get_cli_commands, get_services, get_dashboard_widgets,
get_navigation_items, get_searchable_fields, get_collector_schema),
lifecycle hooks (on_install, on_uninstall, on_enable, on_disable),
helpers exposed in shopdb.api (audit_log, Setting,
resolve_asset_position).
- Versioning rules + change-classification guidance.
Compliance tests (tests/test_plugin_contract.py):
- 8 distinct contract assertions parametrized over 6 bundled plugins
(computers, equipment, network, notifications, printers, usb).
- Asserts: subclasses BasePlugin; manifest has required fields; meta
returns valid PluginMeta; get_blueprint returns Blueprint or None;
get_models returns model classes; get_collector_schema returns
None or {identityfield, fields}; get_navigation_items and
get_searchable_fields return list.
- Plus 3 framework-level: __contract_version__ is valid semver,
get_event_handlers absent, get_collector_schema present.
Test count: 15 -> 66 passing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -73,9 +73,21 @@ class BasePlugin(ABC):
|
||||
"""Return dict of service name -> service class."""
|
||||
return {}
|
||||
|
||||
def get_event_handlers(self) -> Dict[str, callable]:
|
||||
"""Return dict of event name -> handler function."""
|
||||
return {}
|
||||
def get_collector_schema(self) -> Optional[Dict]:
|
||||
"""Return JSON Schema describing the collector payload for this plugin.
|
||||
|
||||
Return None if the plugin does not accept collector input.
|
||||
|
||||
See ADR-006 for the contract. The schema must include:
|
||||
- 'identityfield': name of the field that uniquely identifies an
|
||||
asset across submissions (e.g., 'hostname' for PCs,
|
||||
'macaddress' for network devices). Used for idempotent upsert.
|
||||
- 'fields': JSON Schema definitions for the rest of the payload.
|
||||
|
||||
Plugins returning a non-None schema have an endpoint at
|
||||
/api/collector/<pluginname> auto-registered by the loader.
|
||||
"""
|
||||
return None
|
||||
|
||||
def on_install(self, app: Flask) -> None:
|
||||
"""Called when plugin is installed via CLI."""
|
||||
|
||||
Reference in New Issue
Block a user