Prepare GovOPlaN self-hosted release workflow
Some checks failed
Dependency Audit / dependency-audit (push) Failing after 50s
Module Matrix / module-matrix (push) Failing after 49s

This commit is contained in:
2026-07-10 21:57:22 +02:00
parent 8dd5123aab
commit 94236a7d7e
51 changed files with 3576 additions and 803 deletions

View File

@@ -107,6 +107,15 @@ cd /mnt/DATA/git/govoplan-core
scripts/push-release-tag.sh --version 0.1.6
```
`scripts/generate-release-catalog.py` reads installed/discovered
`ModuleManifest` objects while writing catalog entries. When a manifest is
available, the catalog entry uses the manifest version, points package refs at
`v<manifest.version>`, and copies `provides_interfaces` /
`requires_interfaces` from the manifest. If a manifest cannot be discovered,
the entry falls back to the release version passed with `--version` and omits
interface metadata. This keeps the catalog aligned with independently
versioned module packages instead of relying on a hardcoded compatibility table.
The script also includes GovOPlaN roadmap/scaffold module repositories that do
not yet have package metadata. Those repositories are committed, tagged, and
pushed with the same release tag, but they are tag-only until they contain
@@ -196,10 +205,109 @@ Each module entry can declare:
- WebUI package name and pinned install reference
- display metadata and tags
- `license_features`, the feature entitlements required to plan that install
- `provides_interfaces`, named interface contracts exported by this module
- `requires_interfaces`, named interface contracts and version ranges required
by this module
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.
When `APP_ENV` is `prod` or `production`, module package catalog signature
verification is required by default unless
`GOVOPLAN_MODULE_PACKAGE_CATALOG_REQUIRE_SIGNATURE=false` is set explicitly.
### Independent Module Versions And Interface Ranges
Modules do not need to ship on the same version number. Release catalogs should
pin each package to the exact backend/WebUI ref being installed and declare any
cross-module API compatibility through named interfaces.
Provider shape:
```json
"provides_interfaces": [
{ "name": "files.campaign_attachments", "version": "1.4.0" }
]
```
Requirement shape:
```json
"requires_interfaces": [
{
"name": "files.campaign_attachments",
"version_min": "1.0.0",
"version_max_exclusive": "2.0.0"
}
]
```
`version_min` is inclusive. `version_max_exclusive` is exclusive, so the range
above means `>= 1.0.0` and `< 2.0.0`. Use this for SemVer major-version
compatibility lines. Set `"optional": true` only when the module can operate
without that interface being present. If a provider is installed but its
version is outside the declared optional range, activation is still blocked.
Catalog validation normalizes these fields and warns when catalog entries do
not satisfy each other's ranges. Registry activation and installer preflight
perform the blocking checks against the discovered installed manifests before
the desired module set is activated.
The admin module-management UI shows catalog warnings in the package catalog
section and repeats them as warning-level installer preflight issues while a
package install is planned.
Install-plan items carry a `source` field. Manually entered items use
`source: "manual"`; entries planned from the package catalog use
`source: "catalog"`. Catalog-sourced items also carry a `catalog` metadata
object with the validation snapshot used when the item was planned: catalog
source/path, source type, cache path, channel, sequence, generated/validity
timestamps, signature state, trusted key id, and cache state where available.
Catalog provenance changes preflight severity:
- catalog-sourced installs require a configured, valid package catalog before
activation
- invalid, untrusted, expired, not-yet-valid, replayed, or unapproved-channel
catalogs block catalog-sourced installs
- the same catalog validation failures remain warnings for manual install
plans, so operators can still use offline or emergency package refs
- valid-catalog warnings, such as intentionally unsigned local catalogs when
signature enforcement is disabled, remain warnings
- selected catalog entries with unsatisfied non-optional named interface ranges
block activation before the installer runs
### Update Paths
Package updates are target-state operations, not one-module-at-a-time runtime
toggles. The safe unit of planning is a desired module version set plus a
catalog validation snapshot. The installer may install multiple packages into
the environment before activation, then validate the discovered manifests and
activate the resulting set together.
This avoids circular "upgrade A first / upgrade B first" traps: named interface
requirements are solved against the target set, not against each intermediate
package-install moment. If the target set cannot satisfy all non-optional
interfaces and module dependencies at once, the plan is invalid. Operators
should add the necessary module updates to the same plan instead of trying to
force an order.
Live data upgrades need an even stricter rule:
- migrations must be idempotent and ordered by module migration metadata
- destructive schema/data changes need an explicit retirement or cleanup plan,
not an automatic package update side effect
- cross-module data migrations must be compatible with both the old and target
provider interface until activation finishes
- rollback must restore the package set and database state together, or be
documented as forward-only with a tested recovery procedure
- if two modules require mutually incompatible live-data states, the catalog
must publish an intermediate compatibility release rather than a circular
update chain
In practice, circular dependencies are avoided by designing interfaces with
compatibility windows and by publishing bridge releases. A bridge release keeps
the old interface while introducing the new one, allowing dependent modules to
move first; a later release can retire the old interface after every dependent
module has a compatible target version.
Trusted catalog keys are configured locally: