Release Trust and Loader
ReleaseLoader is the shared verifier for local packaged releases, compiled publication previews, PostgreSQL-backed release snapshots, and MCP runtime scopes. It is implemented in src/rimthan_workflow_registry/loader.py and relies on canonical JSON, digest checks, path safety, schema validation, instruction linting, workflow catalogue validation, and optional Ed25519 trust roots.
Load flow
This flow applies before an active release can be served by MCP or inserted as a compiled release.
Path and byte safety
The loader is constructed with an explicit release_root. It rejects a symlink release root, resolves the path, requires it to be a directory, and reads manifest.json with a configurable maximum size. Artifact loading uses safe relative paths from the manifest, byte limits, and digest/size verification. JSON artifacts must be canonical JSON with trailing newline and must match their manifest identity fields.
Registry assets get an extra content check: the asset's embedded content string is encoded as UTF-8, and its byte_length and sha256 must match. Non-schema instruction assets are linted through security.lint_instructions.
Manifest sections
ReleaseLoader.load supports both legacy and workflow-engine manifest sections:
modulesintoModuleDefinition;presentation_bundlesintoPresentationBundle;workflow_definitionsinto immutable JSON artifacts keyed by workflow ID/version;workflow_stepskeyed by workflow ID/version/step ID;registry_assetskeyed by kind/asset ID/version;validator_definitionskeyed by validator ID/version.
It checks ordering, duplicate identities, one presentation bundle per route/locale, orphaned steps, alias collisions, and then delegates workflow cross-reference and graph invariants to validate_workflow_catalogue in rimthan_workflow_registry.workflow_engine.
Trust roots and signatures
Published release trust is implemented in src/rimthan_workflow_registry/trust.py and documented in docs/reference/release-trust.md. The signed payload is:
rimthan.workflow-registry.manifest.v1 + NUL + canonical_json(manifest with signatures = [])verify_manifest_signatures validates the trust-root schema, rejects duplicate key IDs and duplicate physical Ed25519 public keys, requires manifest signatures sorted by key ID with no duplicates, ignores unknown/revoked/out-of-scope/invalid signatures, and succeeds only when the number of verified active signatures meets minimum_valid_signatures.
Keys are scoped to explicit registry IDs and publishers. Public keys and signatures use unpadded base64url with exact byte-length checks. Ed25519ManifestSigner in src/rimthan_publication/signer.py is the narrow signing counterpart used by Admin API publication.
Local versus published releases
Local development releases can be trusted by explicit path and optional --trusted-manifest-sha256. They may have no signatures. Published releases must have source revision, canonical manifest bytes, and enough valid signatures for the configured trust root. A manifest digest pin does not substitute for signature verification on a published release.
The CLI exposes this through rimthan-workflow verify-release --registry ... --trust-root ... and optional --trusted-manifest-sha256. When a release verifies, RegistryRelease.verified_signing_key_ids carries the trusted key IDs into downstream resolution/materialization: legacy ProjectMaterializer.build_lock writes registry_verified_signing_key_ids into workflow.lock.json, and workflow-engine Resources/checkpoints expose the verified release identity and manifest digest rather than trusting unverified bytes.
Runtime relationships
- Publication Pipeline compilers verify compiled releases by writing a temporary release directory and loading it with
ReleaseLoaderbefore insertion. - PostgreSQL Store reconstructs database releases into temporary exact-byte snapshots and loads them with
ReleaseLoaderfor MCP. McpScope.loadusesReleaseLoaderfor local and database-backed scopes.ImmutableResourceCatalogueserves only bytes from a loadedRegistryRelease.
Tests
tests/test_loader.pycovers release loading, manifest and artifact integrity, canonical encoding, and path safety.tests/test_trust.pycovers signature verification, trust-root scoping, threshold behavior, duplicate keys, revoked/unknown keys, and invalid signatures.tests/test_workflow_engine.pycovers workflow catalogue validation, immutable workflow resources, and corrupt active refresh retaining last-good scope.tests/test_postgres_publication_e2e.pycovers database byte and artifact identity triggers in addition to loader verification.
Focused validation
uv run pytest tests/test_loader.py tests/test_trust.pyuv run pytest tests/test_workflow_engine.py -k "corrupt_active_refresh or compiles_to_verified"- CLI smoke:
uv run rimthan-workflow verify-release --registry registry/releases/0.2.0for a local release path that is not excluded in the current checkout.