Some checks failed
CI / Auth e2e pack (push) Waiting to run
CI / Import/export fidelity gate (push) Waiting to run
CI / Build container images (push) Waiting to run
CD / Build and push images (push) Failing after 1m33s
CD / Deploy to Test (push) Has been skipped
CD / Smoke tests against Test (push) Has been skipped
CD / Promote to Int (push) Has been skipped
CI / Lint, typecheck, test (push) Has been cancelled
Backend for installing plugin ZIPs (ADR 0008, plugin-architecture.md §Lifecycle, security.md §Plugins). Consumes the #70 SDK for validation. - Schema: `plugins` (id, name, version, apiVersion, kind, mode, manifest jsonb, removedAt soft-delete) + `pond_plugins` (per-pond activation) + `PluginInstanceMode` enum; migration 20260710130000_plugins. - `PluginPackageService`: pure, stateless ZIP → validated package via fflate — structure check, manifest validation (SDK), apiVersion gate, kind/bundle/styles rules, CSS sanitation (no @import / external url() / expression()), zip-slip and unpacked-size guards. Each failure carries a stable PluginErrorCode; manifest issues travel as ApiError details. - `PluginStorageService`: on-disk layout `<PLUGINS_DIR>/<id>/<version>/`; atomic writeVersion (staging dir + rename, no 404 window mid-update), removeVersion/removePlugin, traversal-safe asset resolution, dropzone + quarantine dirs. - `PluginsService`: install/update (update only to a strictly higher version, preserving the admin's instance mode; files land before the metadata pointer flips) / uninstall (refused while required; soft-delete + files removed + pond activations dropped) / list / get. - `POST/GET/DELETE /admin/plugins` (SiteAdminGuard, multer memory upload), error→HTTP-status mapping. Public version-pinned static serving at `GET /plugins/:id/:version/*rest` with immutable cache + nosniff, only for the installed current version. - `PluginWatcherService`: watches `<PLUGINS_DIR>/_dropzone/`, runs the same validation, installs valid drops and quarantines invalid ones with the error logged; inert under NODE_ENV=test (tests drive processDropped). - SDK: `compareVersions`/`isHigherVersion`. shared: `PluginView`, `PluginInstanceMode`, `PLUGIN_ERROR_CODES`, `PLUGINS_DIR` env, plugin error i18n (de+en). Compose: `plugins` volume + `PLUGINS_DIR`. - Tests: package unit test (valid + each invalid class) and an e2e DB test (GUI install + immutable serving, non-admin 403, invalid-manifest details, dropzone install + quarantine, atomic higher-only update, required-guarded uninstall that removes files and tombstones metadata). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EwZ4jR4KFAPvpjWevfUGX1
36 lines
1.2 KiB
SQL
36 lines
1.2 KiB
SQL
-- CreateEnum
|
|
CREATE TYPE "PluginInstanceMode" AS ENUM ('DISABLED', 'OPTIONAL', 'REQUIRED');
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "plugins" (
|
|
"id" TEXT NOT NULL,
|
|
"name" TEXT NOT NULL,
|
|
"version" TEXT NOT NULL,
|
|
"api_version" TEXT NOT NULL,
|
|
"kind" TEXT NOT NULL,
|
|
"mode" "PluginInstanceMode" NOT NULL DEFAULT 'DISABLED',
|
|
"manifest" JSONB NOT NULL,
|
|
"installed_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updated_at" TIMESTAMP(3) NOT NULL,
|
|
"removed_at" TIMESTAMP(3),
|
|
|
|
CONSTRAINT "plugins_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
-- CreateTable
|
|
CREATE TABLE "pond_plugins" (
|
|
"pond_id" TEXT NOT NULL,
|
|
"plugin_id" TEXT NOT NULL,
|
|
"enabled" BOOLEAN NOT NULL DEFAULT true,
|
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updated_at" TIMESTAMP(3) NOT NULL,
|
|
|
|
CONSTRAINT "pond_plugins_pkey" PRIMARY KEY ("pond_id","plugin_id")
|
|
);
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "pond_plugins" ADD CONSTRAINT "pond_plugins_pond_id_fkey" FOREIGN KEY ("pond_id") REFERENCES "ponds"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
-- AddForeignKey
|
|
ALTER TABLE "pond_plugins" ADD CONSTRAINT "pond_plugins_plugin_id_fkey" FOREIGN KEY ("plugin_id") REFERENCES "plugins"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|