ADR-013 Phase 1: signed plugin artifacts (pack/validate/keygen)
Packaging + provenance for the plugin marketplace. No runtime behavior change yet - verification is available on demand; enforcing it at plugin load/migrate and pulling from a shelf are Phase 2. - signing.py: ed25519 key pairs + provenance. Provenance is a sorted per-file SHA-256 map plus metadata; the detached signature covers the exact serialized provenance bytes, so verifying is re-hash files, re-serialize, check signature. verify() accepts any of several trusted keys (rotation). Uses cryptography (already a dependency). - packaging.py: pack() builds a signed <name>-<version>.shopdbplugin (zip + PROVENANCE.json + PROVENANCE.sig). verify_artifact()/verify_dir() re-hash and check the signature, and flag a tampered file, an unexpected file, a wrong/absent key - all fail closed. - CLI: `flask plugin keygen` (publisher key pair), `flask plugin pack <name> --key` (validates then signs), and `flask plugin validate` extended to a signed artifact by path (--pubkey, else PLUGIN_TRUSTED_KEYS). - config PLUGIN_TRUSTED_KEYS: os.pathsep-separated public-key PEM paths, delivered with the site config, never read from the shelf. .env.example documents it. - docs/PLUGIN-SIGNING.md: curator flow (keygen offline, review, pack, publish, pin keys, rotate). The signature proves an artifact is exactly what a curator signed, not that the code is safe - human review before signing is the control. 11 tests: sign/verify round trip, wrong key, provenance excludes noise, serialize determinism, pack + verify, tamper -> hash mismatch, extra file, no-key fail-closed, verify_dir. 1028 pass, naming green.
This commit is contained in:
@@ -60,6 +60,16 @@ class Config:
|
||||
# API key for the unattended PowerShell collector scripts
|
||||
COLLECTOR_API_KEY = os.environ.get('COLLECTOR_API_KEY', '')
|
||||
|
||||
# Trusted plugin publisher public keys (ADR-013). os.pathsep-separated PEM
|
||||
# file paths, delivered out-of-band with the deployed config - NEVER read
|
||||
# from the plugin shelf. Used to verify signed plugin artifacts. Empty on a
|
||||
# site that does not adopt marketplace plugins.
|
||||
PLUGIN_TRUSTED_KEYS = [
|
||||
path.strip()
|
||||
for path in os.environ.get('PLUGIN_TRUSTED_KEYS', '').split(os.pathsep)
|
||||
if path.strip()
|
||||
]
|
||||
|
||||
ZABBIX_ENABLED = os.environ.get('ZABBIX_ENABLED', 'false').lower() == 'true'
|
||||
ZABBIX_URL = os.environ.get('ZABBIX_URL', '')
|
||||
ZABBIX_TOKEN = os.environ.get('ZABBIX_TOKEN', '')
|
||||
|
||||
Reference in New Issue
Block a user