feat: add controlled plugin marketplace lifecycle
This commit is contained in:
@@ -4,7 +4,8 @@ This directory contains the independent administrator-only control plane for
|
||||
Business Plugins. It is deliberately separate from Sub2API Core and from the
|
||||
existing `.s2plugin` OpenAI OAuth transport runtime.
|
||||
|
||||
The control plane owns the plugin catalog, signed package verification,
|
||||
The control plane owns the installed-plugin registry, a constrained marketplace
|
||||
catalog, signed package verification,
|
||||
revision directories, lifecycle state, encrypted configuration metadata,
|
||||
menu preview/apply, and its own audit log. Core remains authoritative for
|
||||
users, administrator roles, balances, subscriptions, billing, and audit
|
||||
@@ -41,10 +42,13 @@ session and encrypted plugin configuration.
|
||||
GET /healthz
|
||||
GET /readyz
|
||||
POST /login POST /login/2fa POST /logout
|
||||
GET /api/marketplace POST /api/marketplace/install (JSON: plugin_id, version)
|
||||
GET /api/me GET /api/plugins GET /api/plugins/{id}
|
||||
POST /api/plugins/install (multipart field: package)
|
||||
POST /api/plugins/{id}/install (multipart field: package)
|
||||
POST /api/plugins/{id}/upgrade (multipart field: package)
|
||||
POST /api/plugins/{id}/enable|disable|rollback|uninstall
|
||||
DELETE /api/plugins/{id} (same delete operation as uninstall)
|
||||
GET|PUT /api/plugins/{id}/config
|
||||
POST /api/plugins/{id}/menu-preview|menu-apply
|
||||
POST /api/menu-items/preview|apply (JSON: {"plugin_id":"..."})
|
||||
@@ -52,9 +56,53 @@ GET /api/audit
|
||||
```
|
||||
|
||||
Every mutation requires the plugin CSRF token and an `Idempotency-Key`. A
|
||||
mutation returns an operation ID even when it completes synchronously. Failed
|
||||
installation and upgrade never replace the active revision. Uninstall is
|
||||
allowed only after disable and removes plugin files, not Core data.
|
||||
mutation returns an operation ID even when it completes synchronously. A local
|
||||
upload or marketplace download only verifies and stages the package in the
|
||||
registry (`disabled` / “已入库,待启用”); it never starts a process. The
|
||||
administrator must configure the service and click **enable**. Only a
|
||||
successful health and readiness check changes the plugin to `healthy` and
|
||||
installs its runtime/menu. Failed installation and upgrade never replace the
|
||||
active revision. Delete/uninstall is allowed only after disable and removes
|
||||
plugin files, not Core data.
|
||||
|
||||
## Marketplace catalog
|
||||
|
||||
The marketplace is server-side only. The browser receives metadata and sends a
|
||||
plugin ID/version; it never receives an archive URL and cannot request an
|
||||
arbitrary download. Set `PLUGIN_MARKETPLACE_INDEX` to a local JSON file (the
|
||||
default) or an HTTPS index URL. Remote indexes and archives are restricted to
|
||||
the exact hosts in `PLUGIN_MARKETPLACE_ALLOWED_HOSTS`; HTTP is accepted only
|
||||
for loopback sources in `PLUGIN_ENV=development`. Redirects, credentials,
|
||||
queries, fragments, oversized responses, path escapes, and hash mismatches are
|
||||
rejected. The package must still pass the normal manifest signature, file hash,
|
||||
and Core compatibility checks.
|
||||
|
||||
Catalog format (schema version 1):
|
||||
|
||||
```json
|
||||
{
|
||||
"schema_version": 1,
|
||||
"source": "internal-release-catalog",
|
||||
"entries": [
|
||||
{
|
||||
"plugin_id": "example.plugin",
|
||||
"name": "Example Plugin",
|
||||
"version": "1.0.0",
|
||||
"description": "Administrator extension",
|
||||
"archive_url": "example.plugin-1.0.0.s2plugin",
|
||||
"archive_sha256": "SHA256_OF_ARCHIVE",
|
||||
"archive_size": 12345,
|
||||
"publisher_key_id": "publisher-key-id",
|
||||
"core_api_baseline": "sub2api-0.1.183",
|
||||
"tested_core_versions": ["0.1.183"],
|
||||
"capabilities": ["example.v1"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
An entry is never an implicit upgrade. If the plugin ID is already registered,
|
||||
use the existing upgrade flow, then enable it explicitly.
|
||||
|
||||
## Plugin package
|
||||
|
||||
|
||||
Reference in New Issue
Block a user