Sync wiki from project files

2026-07-07 15:06:45 +02:00
parent c0a193e577
commit 5607aaf1ab
3 changed files with 264 additions and 12 deletions

@@ -0,0 +1,191 @@
<!-- codex-wiki-sync:36e407f77dd59c0601fa5063 -->
> Mirrored from `/mnt/DATA/git/govoplan-core/docs/CATALOG_TRUST_AND_LICENSING.md`.
> Origin: `repository`.
> Active tasks and changing state belong in Gitea issues; this wiki page is durable project context.
---
# Module Catalog Trust And Licensing
GovOPlaN module install and uninstall must remain operator-controlled. The
running server may plan and validate package changes, but package mutation is
performed by the separate installer daemon or an operator shell during
maintenance mode.
## Roles
`govoplan-web` is the public static distribution surface for official catalog
resources:
- signed module package catalogs, grouped by release channel
- public catalog keyrings
- public license verification keyrings
- examples and operator-facing download paths
`govoplan-core` is the verifier and orchestrator:
- fetches a local or remote module catalog
- verifies catalog signatures against configured trusted keys
- enforces approved release channels
- rejects expired or not-yet-valid catalogs
- records accepted catalog sequence numbers for replay protection
- checks catalog entry license feature requirements before planning installs
- writes installer plans and request records
Feature and platform modules own their package artifacts, manifests, migration
metadata, retirement providers, and optional lifecycle behavior.
## Catalog Source
Core accepts either a local catalog file or a remote URL:
```bash
GOVOPLAN_MODULE_PACKAGE_CATALOG=/srv/govoplan/catalogs/stable.json
GOVOPLAN_MODULE_PACKAGE_CATALOG_URL=https://govoplan.example/catalogs/v1/channels/stable.json
GOVOPLAN_MODULE_PACKAGE_CATALOG_CACHE=/srv/govoplan/runtime/catalog-cache/stable.json
```
If both file and URL are set, the URL wins. The cache is used when a remote
fetch fails, so an operator can still inspect the last known catalog. A cached
catalog must still pass signature, freshness, channel, and replay validation.
## Catalog Shape
An official catalog is a JSON object with:
- `catalog_version`
- `channel`
- `sequence`
- `generated_at`
- `not_before` when delayed activation is needed
- `expires_at`
- `modules`
- `signatures`
Each module entry can declare:
- backend package name and pinned install reference
- WebUI package name and pinned install reference
- display metadata and tags
- `license_features`, the feature entitlements required to plan that install
The signature is Ed25519 over canonical JSON with both `signature` and
`signatures` removed. Core accepts the legacy single `signature` field and the
new `signatures` array.
## Keyrings And Rotation
Trusted catalog keys are configured locally:
```bash
GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS_FILE=/srv/govoplan/trust/catalog-keyring.json
GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS='{"release-key-1":"<base64 public key>"}'
```
For development or tightly controlled deployments, a keyring can be read from a
URL and cached:
```bash
GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS_URL=https://govoplan.example/catalogs/v1/keyring.json
GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS_CACHE=/srv/govoplan/runtime/catalog-cache/keyring.json
```
Production installations should pin the trusted keyring locally or ship it
through deployment configuration. Fetching trusted keys from the same public
origin as the catalog is convenient, but that origin must not become the only
trust root.
Keyring entries support:
- `key_id`
- `public_key` or `public_key_base64`
- `status`: `active`, `next`, `retired`, `revoked`, or `disabled`
- `not_before`
- `not_after`
Rotation process:
1. Add the next public key to the local trusted keyring with status `next`.
2. Publish catalogs signed by both current and next keys.
3. Upgrade installations so the next key is locally trusted.
4. Promote the next key to `active`.
5. Retire the old key only after every supported installation trusts the new
key.
6. Mark a compromised key `revoked` and publish a higher sequence catalog
signed by an uncompromised key.
## Replay And Freshness
Use replay state in production:
```bash
GOVOPLAN_MODULE_PACKAGE_CATALOG_SEQUENCE_STATE=/srv/govoplan/runtime/catalog-sequences.json
GOVOPLAN_MODULE_PACKAGE_CATALOG_ENFORCE_SEQUENCE=true
```
Core records the accepted sequence per channel after a catalog entry is planned
from the admin interface. With strict sequence enforcement, a previously
accepted sequence is rejected; without strict enforcement, only older sequences
are rejected.
Catalogs should always expire. Long-lived catalogs make rollback and key
compromise harder to reason about.
## Release Channels
Approved channels are deployment policy:
```bash
GOVOPLAN_MODULE_PACKAGE_CATALOG_APPROVED_CHANNELS=stable,lts
GOVOPLAN_MODULE_PACKAGE_CATALOG_REQUIRE_SIGNATURE=true
```
The admin UI can display other catalog metadata, but core rejects catalogs from
unapproved channels when validation is configured.
## Licensing
Catalog entries can require license features:
```json
"license_features": ["module.mail", "support.standard"]
```
Core checks those requirements against an offline license file before allowing
the entry into the install plan.
```bash
GOVOPLAN_LICENSE_FILE=/srv/govoplan/license.json
GOVOPLAN_LICENSE_ENFORCEMENT=true
GOVOPLAN_LICENSE_TRUSTED_KEYS_FILE=/srv/govoplan/trust/license-keyring.json
```
License files are JSON objects with:
- `license_id`
- `subject`
- `features`
- `valid_from`
- `valid_until`
- `signature`
License enforcement can run in observe-only mode by leaving
`GOVOPLAN_LICENSE_ENFORCEMENT` unset. In that mode, missing or invalid license
data is surfaced as a warning but does not block planning.
Licensing is intentionally separate from open-source code licensing. The
catalog/license mechanism can govern support channels, official release
eligibility, hosted update access, professional support, or commercial
entitlements without changing the source license of the repositories.
## Production Gaps
The current implementation validates signed catalog metadata and offline
license entitlements. Production-grade distribution still needs:
- artifact digest verification for package archives or registry artifacts
- SBOM/provenance fields and verification workflow
- hardened catalog publishing pipeline in `govoplan-web`
- automated key rotation runbook and emergency revocation procedure
- license issuance and renewal tooling
- tests for remote catalog cache fallback and replay-state upgrades

@@ -1,4 +1,4 @@
<!-- codex-wiki-sync:97f252ae80996d8ee236fd44 -->
<!-- codex-wiki-sync:24b67ceb3231203599e59944 -->
> Mirrored from `/mnt/DATA/git/govoplan-core/docs/MODULE_ARCHITECTURE.md`.
> Origin: `repository`.
@@ -31,6 +31,7 @@ The kernel target owns:
- the server entry point and platform configuration
- module discovery, manifest validation, registry validation, route aggregation, and platform metadata APIs
- database engine/session lifecycle and module migration orchestration
- module install-plan validation, signed catalog verification, license entitlement checks, and installer request orchestration
- capability registry, command/event contracts, and lifecycle hooks
- shared WebUI shell contracts, generic WebUI components, and module route/nav rendering
- centralized mapping from serializable icon names to renderable frontend icons
@@ -160,6 +161,7 @@ A module owns:
- module migrations and migration metadata
- module permissions and role templates
- module-specific schemas, policies, and domain rules
- module package metadata and retirement providers used by install/uninstall preflight
- WebUI pages, feature-specific components, API clients, route contributions, and navigation metadata
A module should not own generic platform UI. If a component is useful outside one module, move it to `@govoplan/core-webui` and parameterize it there before reusing it.
@@ -215,6 +217,34 @@ Rules:
should compare the database heads to the configured script heads instead of
assuming one linear revision when multiple modules are enabled.
## Install, Uninstall, And Catalogs
Core owns the install plan, signed catalog validation, license entitlement
check, maintenance-mode guard, replay state, and installer request queue.
Package mutation is performed by `govoplan-module-installer` outside the
FastAPI request process.
Official catalogs can be served as static JSON from `govoplan-web`, but core
does not trust the website by location alone. A catalog must pass the configured
signature, channel, freshness, and replay rules before a catalog entry can be
planned. Catalog entries may declare `license_features`; core checks those
against the configured offline license before adding the entry to the install
plan.
Modules should provide:
- pinned backend and WebUI package refs for official catalog entries
- compatibility metadata in the module manifest
- lifecycle hooks when a runtime enable/disable action needs module-specific
work
- uninstall guards for persistent data, active workers, schedulers, or external
bindings
- retirement providers when destructive uninstall can safely drop or retire
module-owned data
Uninstall remains non-destructive unless the operator explicitly requests
`destroy_data` and the module provides a retirement provider that supports it.
## WebUI Contract
A WebUI module exports a `PlatformWebModule` from its package. The object contributes local/fallback metadata and route render functions.

@@ -1,4 +1,4 @@
<!-- codex-wiki-sync:874f18ab843f9c893d212d76 -->
<!-- codex-wiki-sync:e178a363f47dd4c65d49cb2c -->
> Mirrored from `/mnt/DATA/git/govoplan-core/docs/RELEASE_DEPENDENCIES.md`.
> Origin: `repository`.
@@ -198,19 +198,30 @@ govoplan-module-installer --cancel-request <request-id> --format json
govoplan-module-installer --retry-request <request-id> --format json
```
Package catalogs are file-backed. Set `GOVOPLAN_MODULE_PACKAGE_CATALOG` to a
JSON file matching `docs/module-package-catalog.example.json`; the admin UI will
show those entries and can save them into the install plan. This keeps the
release approval decision outside the running server while avoiding hand-typed
package refs. Validate the catalog before handing it to operators:
Package catalogs can be local files or remote static resources, for example
served by `govoplan-web`. Set `GOVOPLAN_MODULE_PACKAGE_CATALOG` for a local file
or `GOVOPLAN_MODULE_PACKAGE_CATALOG_URL` for a remote catalog matching
`docs/module-package-catalog.example.json`; the admin UI will show those entries
and can save them into the install plan. This keeps the release approval
decision outside the running server while avoiding hand-typed package refs.
Remote catalogs can be cached for offline inspection:
```bash
GOVOPLAN_MODULE_PACKAGE_CATALOG_URL=https://govoplan.example/catalogs/v1/channels/stable.json
GOVOPLAN_MODULE_PACKAGE_CATALOG_CACHE=/srv/govoplan/runtime/catalog-cache/stable.json
```
Validate the catalog before handing it to operators:
```bash
govoplan-module-installer --validate-package-catalog docs/module-package-catalog.example.json --format json
```
Release catalogs should be signed and channel-gated. The supported signing
format is an Ed25519 signature over the canonical catalog JSON object with the
`signature` field removed. Sign a catalog with:
Release catalogs should be signed, channel-gated, expiring, and sequence
tracked. The supported signing format is an Ed25519 signature over the
canonical catalog JSON object with the `signature` and `signatures` fields
removed. Core accepts the legacy single `signature` field and the newer
`signatures` array used during key rotation. Sign a catalog with:
```bash
govoplan-module-installer \
@@ -238,10 +249,30 @@ GOVOPLAN_MODULE_PACKAGE_CATALOG=/path/to/catalog.json
GOVOPLAN_MODULE_PACKAGE_CATALOG_REQUIRE_SIGNATURE=true
GOVOPLAN_MODULE_PACKAGE_CATALOG_APPROVED_CHANNELS=stable
GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS='{"release-key-1":"<base64-ed25519-public-key>"}'
GOVOPLAN_MODULE_PACKAGE_CATALOG_SEQUENCE_STATE=/srv/govoplan/runtime/catalog-sequences.json
GOVOPLAN_MODULE_PACKAGE_CATALOG_ENFORCE_SEQUENCE=true
```
Unsigned catalogs remain usable for local development when signature
enforcement is off, but the admin UI labels them as unsigned.
Trusted keys can also be loaded from
`GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS_FILE`. A URL-backed keyring is
supported for development and tightly controlled deployments through
`GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS_URL` plus
`GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS_CACHE`, but production systems
should pin trusted keys locally.
Catalog entries can declare `license_features`. If
`GOVOPLAN_LICENSE_ENFORCEMENT=true`, core blocks planning catalog installs
whose required features are not present in the configured offline license:
```bash
GOVOPLAN_LICENSE_FILE=/srv/govoplan/license.json
GOVOPLAN_LICENSE_TRUSTED_KEYS_FILE=/srv/govoplan/trust/license-keyring.json
GOVOPLAN_LICENSE_ENFORCEMENT=true
```
See `docs/CATALOG_TRUST_AND_LICENSING.md` for key rotation, replay protection,
and licensing details. Unsigned catalogs remain usable for local development
when signature enforcement is off, but the admin UI labels them as unsigned.
Install rows must use tagged package/git refs or registry packages, not local
`file:` or workspace links. The installer daemon can run `npm install` and