Connects TREK to the static GitHub registry (mauriceboe/TREK-Plugins). The
registry repo + CI gates were already live; this is the server side.
- registry.service: fetches the single aggregated dist/index.json (never
per-plugin GitHub API calls — the HACS rate-limit lesson), caches it 30 min,
soft-fails to a stale/empty registry, and installs a pinned version through
the M4 pipeline: safe download -> sha256 verify -> slip-safe extract ->
manifest re-validate -> native re-scan -> atomic move -> discover (inactive),
recording repo/commit/sha provenance. Handles the codeload {repo}-{sha}/
wrapper directory.
- Admin endpoints: GET /api/admin/plugins/registry (browse metadata) and
POST /api/admin/plugins/install { id, version }. Install never executes code;
activation stays a separate, deliberate step.
Plugins placed on the /plugins volume are now discovered, validated and registered
as inactive, ready to activate.
- manifest.ts: strict trek-plugin.json validation (id/version/type, known
permissions only, egress required with http:outbound, native modules rejected).
- discovery.ts: scans the volume on startup + on demand (POST /api/admin/plugins/
rescan), upserts rows INACTIVE, refreshes settings-field descriptors, and never
downgrades or wipes an already-installed plugin's status / grants / config.
Invalid or native-carrying plugins are skipped and logged.
- Activation now grants the DECLARED permissions (the consent gate) and persists
them before spawning.
- install/ utilities for the registry installer (M5), each independently tested:
- safe-fetch: host allowlist (GitHub only) + private-IP refusal + manual
redirect following + size cap + sha256 (constant-time compare).
- safe-extract: zip/tar-slip-safe extraction with its own minimal tar.gz + zip
readers; rejects traversal, absolute paths, symlinks, oversized/too-many
entries, and unsupported formats.
- native-scan: refuses .node / binding.gyp / prebuilds, never follows symlinks.