feat: enforce signed target maturity evidence
Dependency Audit / dependency-audit (push) Failing after 9s
Deployment Installer / deployment-installer (push) Successful in 6s
Security Audit / security-audit (push) Failing after 8s

This commit is contained in:
2026-08-02 03:41:09 +02:00
parent be8ba10ae3
commit 2c56a0fc11
12 changed files with 1245 additions and 15 deletions
+22
View File
@@ -503,6 +503,20 @@ Signatures cover UTF-8 JSON with the `signatures` member omitted, object keys
sorted, compact `,`/`:` separators and non-ASCII characters escaped, matching
the tool's deterministic canonicalization.
`tools/assessments/boundary-evidence.py` is the bounded issuance path. It
accepts a private target-run manifest conforming to
[`capability-fit-boundary-run.schema.json`](capability-fit-boundary-run.schema.json),
hashes each retained result file without following a final-component symlink,
and excludes all paths and raw results from the signed receipt. Issuance is
refused unless an independently trusted catalog, exact installed payload,
signed installer receipt, and role-scoped installer authority already pass.
Every claim must be covered by a supplied Ed25519 private key whose public key
is authorized for the full proof interval; catalog and installer key reuse is
rejected. The command immediately verifies its own result and atomically writes
both the proof and a sanitized review. The complete operator procedure and
recovery measurement definition are in
[`TARGET_MATURITY_EVIDENCE_RUNBOOK.md`](TARGET_MATURITY_EVIDENCE_RUNBOOK.md).
```bash
./.venv/bin/python tools/assessments/capability-fit.py \
--public \
@@ -513,6 +527,14 @@ the tool's deterministic canonicalization.
--expected-external-provider-subject provider-production
```
Promotion automation must opt into its required boundaries. Add
`--require-reference-readiness` to require all six target scopes,
`--require-external-provider-proof` when the product depends on a provider, and
`--require-production-approval` for production admission. These switches turn
missing, expired, revoked, mismatched, negative, or otherwise unchecked claims
into a blocking exit status rather than merely reporting them as an unproven
boundary.
With `--installed-evidence`, this command performs comparison and proof-binding
diagnostics. Without an installer receipt, the imported document remains
unsigned, so neither it nor the boundary claim becomes accepted proof. Direct
@@ -61,7 +61,7 @@ accepted as the current baseline and must not be reopened as greenfield work.
| Acting identity, function assignment, mandate, and ownership recovery | Implemented foundations span Identity, Organizations, IDM, Access, Mandates, generic ownership transfer/recovery, and audit provenance. Effective competence now resolves through a tenant-bound Mandate capability. |
| Governed data foundations | Connectors, Datasources, Dataflow, Reporting, and Search now exist. Datasources already provides live/cached/static modes, staging, immutable materializations, and publication contracts. |
| Task-focused projections and configured documentation | Views, view-surface declarations, configurable dashboards, and manifest-driven user/admin documentation exist. Rollout and content depth remain incremental. |
| Encryption as an optional capability | Core defines provider-neutral contracts; `govoplan-identity-trust` persists public device keys, key epochs and assurance evidence; and `govoplan-encryption` persists opaque vault/key lifecycle, versioned protection envelopes, quorum recovery authorization, outcome-unknown reconciliation, and disable preflight. No concrete cipher/provider or E2EE claim is bundled. |
| Encryption as an optional capability | Core defines provider-neutral contracts; `govoplan-identity-trust` persists public device keys, key epochs and assurance evidence; and `govoplan-encryption` persists opaque vault/key lifecycle, versioned protection envelopes, quorum recovery authorization, outcome-unknown reconciliation, and disable preflight. A bundled local AES-256-GCM server-envelope provider now stores wrapped key material and supports Files/Postbox protection, rotation, revocation, destruction, rewrap, tamper detection, and fail-closed restore behavior. It is explicitly neither E2EE nor a certified KMS/HSM. |
| Search without mandatory OpenSearch | PostgreSQL-backed, permission-aware search and module provider contracts exist; OpenSearch remains an optional adapter. |
| Scale-out and recovery architecture | Stateless API/worker, shared database/object storage, event delivery, deployment, and recovery contracts are documented and partly exercised. Production profiles and drills remain active work. |
@@ -83,10 +83,10 @@ were proven now have independent persistent owners:
| External providers | Core validates provider objects/field groups, operations, integration maturity, source authority, bounded reads, freshness/health, idempotency, conflicts, outcome-unknown handling, evidence, correction, reconciliation, outage, classification, purpose, retention, and secret handling. Addresses/CardDAV, Files remote storage, Mail SMTP/IMAP, Calendar CalDAV/ICS/Graph/EWS, and Connectors tabular/sanctions providers declare the contract and tenant-bounded secret-free runtime state. | Registry validation rejects any declared external provider without a sanitized state provider. Future adapters must cross the same gate before activation. |
| Institutional context | Core provides versioned temporal, actor/representation, institution/unit/function/task/mandate/jurisdiction/service/case/party/work-item/workflow/approval/decision/record, legal-basis, evidence, information-governance, external-source, presentation, and geographic references. Events, automation actions, audit records, and the transactional Audit outbox preserve the envelope. | Owning modules must progressively require the relevant subset for consequential operations. |
| Semantic provider contracts | Provider-neutral DTOs and protocols cover Mandate resolution, versioned Service definitions, procedure Parties/representation, and formal Decisions. `govoplan-mandates`, `govoplan-services`, `govoplan-parties`, and `govoplan-decisions` now persist immutable revisions behind those contracts with tenant isolation, bounded reads, replay safety, OCC, migrations, uninstall guards, permissions, APIs, capability documentation, and recovery documentation. | The owners are deliberately headless. Procedure-specific UI remains with consuming modules. |
| Formal-outcome proof | Committee persists bodies, meetings, agenda items, minutes, lifecycle events, and an optional protected local Decision projection. Voting separately owns immutable ballot definitions, frozen electorates, recorded casting/replacement, deterministic tally, certification, challenge, annulment, and provider-backed assurance profiles. Committee consumes `voting.ballots` and retains only deliberation linkage and verified aggregate outcome. | Native recorded ballots are reconstructable, not secret. A concrete confidential/secret/certified provider and deployment assurance still require protocol/custody/legal decisions and target evidence. |
| Formal-outcome proof | Committee persists bodies, meetings, agenda items, minutes, lifecycle events, and an optional protected local Decision projection. Voting separately owns immutable ballot definitions, frozen electorates, recorded casting/replacement, deterministic tally, certification, challenge, annulment, and provider-backed assurance profiles. Committee consumes `voting.ballots` and retains only deliberation linkage and verified aggregate outcome. A bundled `local_confidential` reference provider encrypts server-readable casts outside native ballot rows and exposes only receipts plus aggregate evidence to Committee. | Native recorded ballots remain reconstructable, and the reference confidential provider is neither secret nor certified: its server can decrypt casts while tallying. Secret/electronic-ballot protocol selection, custody, legal acceptance, independent review, and target evidence remain explicit product decisions. |
| Service-to-case proof | Services owns the persistent exact definitions consumed by Portal discovery and Cases intake. Forms owns immutable multi-page/conditional/localized schemas, accessibility assessment and package fragments. Forms Runtime owns definition-aware drafts, validation, submission receipts, status/evidence history, and durable native Case/Workflow handoffs with intent-before-effect and outcome-unknown reconciliation. Portal delegates URL, Case, Form, or Workflow launch to an installed owner while retaining exact Service/Form provenance. | Anonymous intake and concrete attachment/signature providers remain product depth. Portal and Runtime fail closed and explain any absent launcher, target capability, or provider prerequisite. |
| Generic approvals and process execution | Approvals persists exact-subject chains, delegation, separation of duties, quorum, signatures-as-evidence, escalation, OCC, and replay-safe decisions. Campaign proves an exact-version delivery gate. Workflow Engine owns immutable definitions/instances plus API, schedule, event and parent triggers, durable timer/event waits, scale-out claims, current-authority rechecks, and idempotent starts independently of the optional editor. | Policy-authored Approval template selection, concrete signature providers, cron adapters, and broader BPMN execution profiles are product/provider depth on explicit contracts. |
| Device trust and content protection | Identity Trust separates public device keys, epochs, assurance and key-access decisions from login and Access. Encryption separates resource ownership from opaque provider key custody, versioned envelopes, migration evidence, quorum recovery authorization and uninstall proof. Files/Postbox fixtures prove the optional boundary. | Concrete reviewed KMS/HSM/client providers, feature adapters, backup/restore/key-loss drills, and E2EE interoperability/certification remain required before a deployment protection claim. |
| Device trust and content protection | Identity Trust separates public device keys, epochs, assurance and key-access decisions from login and Access. Encryption separates resource ownership from opaque provider key custody, versioned envelopes, migration evidence, quorum recovery authorization and uninstall proof. Its local server-envelope provider and Files/Postbox adapters prove ciphertext persistence, integrity, rotation/rewrap and fail-closed key loss without leaking plaintext keys across the capability boundary. | Reviewed KMS/HSM/client providers, more owner adapters, target backup/restore/key-loss drills, and E2EE interoperability/certification remain required before stronger deployment claims. |
| Procedure-party proof | Parties persists effective procedure roles, frozen contact snapshots, and representation powers. Existing powers cannot disappear or be silently rewritten; explicit OCC-guarded revocation is required. Cases resolves the provider capability and excludes expired/revoked authority from downstream delivery. | Procedure modules still decide which contextual fields and actions to present. |
| Integrated institutional journey | The executable `product.service-to-decision` fixture uses real SQL-backed Services, Cases, Parties, Mandates, Committee, and Decisions providers. It carries one exact Service version through persisted Case intake, representation and frozen delivery authority, effective Mandate resolution, a body/meeting/agendum/vote/minute sequence, a persisted formal Decision, confirmed Postbox effect, Audit/record evidence, remedy/review, and protected reconstruction. A second executable path proves Portal to exact Form revision, persisted submission, and idempotent replay. | This is architecture and composition evidence. Signed, release-bound target accessibility, privacy, security, operator, delivery-provider, and recovery-drill evidence is still required before the package may claim `reference_ready`. |
| Governed data catalogue | Datasources stores typed governance metadata, exposes bounded tenant-scoped filters and update APIs/UI, carries governance through staging, and snapshots it into immutable materializations. Reporting now persists immutable dataset, semantic-model, report, quality-plan, saved-view, and schedule revisions; executes typed semantic queries with quality gates, access checks, replay, pivoting, export/import assessment, and provenance; and exposes the governed analytical WebUI. | Rich dependency/impact traversal, additional expression functions, and policy-specific field visibility can grow on the established contracts without moving connector, transformation, or source ownership. |
@@ -464,7 +464,10 @@ truthfully completed by adding generic platform code:
must produce signed, expiring accessibility, privacy, security, operator,
provider, backup/restore, rollback, and recovery-drill evidence. The verifier
and schemas are implemented; the actual claims require those real runs.
The pinned-release evidence run is tracked in
A bounded issuer now hashes retained reports, checks role-scoped signing
authority and exact installed-release origin, emits sanitized signed
receipts, verifies them immediately, and exposes admission-enforcing CLI
gates. The real pinned-release evidence run is tracked in
[GovOPlaN #37](https://git.add-ideas.de/GovOPlaN/govoplan/issues/37).
Forms and Forms Runtime no longer constitute an architecture gap. Conditional
@@ -533,8 +536,9 @@ Its implementation work packages and resulting owners are:
- `govoplan-voting`: governed recorded ballots plus fail-closed provider-backed
assurance profiles consumed by Committee; and
- Identity Trust #1 and Encryption #1-#3: public device trust, provider-neutral
key/protection lifecycle, recovery authorization and disable proof, while
concrete provider conformance remains separately gated.
key/protection lifecycle, recovery authorization and disable proof, plus a
bounded local server-envelope provider and Files/Postbox fixtures; external
KMS/HSM/client-provider conformance remains separately gated.
Existing Projects #1, Reporting #4, Portal #1, Cases #1, Datasources #1,
Risk Compliance #2, GovOPlaN #14, and GovOPlaN #19 carry product-depth and
+153
View File
@@ -0,0 +1,153 @@
# Target Maturity Evidence Runbook
This runbook turns retained target-environment results into a sanitized,
signed GovOPlaN capability-fit proof. It does not make a deployment suitable,
certified, supported, or production-approved by itself. The proof records what
independent authorities assessed against one exact installed release.
## Roles and custody
Use separate trust domains for release signing, installation receipts,
boundary assessment, and production approval. A private proof key must be
provisioned outside the assessed application and its matching public key must
already exist in a separately managed
`capability-fit-proof-authority-keyring.schema.json` document. Do not store
private keys, raw reports, credentials, personal data, backup material, or
target endpoints in Git.
Each authority key lists only the scopes that role may attest. At least one
supplied signing key must cover every claim, and the issuer rejects a key that:
- is absent, inactive, expired, or revoked in the authority keyring;
- expires before the proof;
- does not match its independently provisioned public key;
- reuses release-catalog or installer-authority key material.
## Target run
Install one pinned catalog release and issue its installed-composition receipt
with `tools/assessments/installer-receipt.py`. Exercise the actual target
topology, including:
- PostgreSQL and Redis as shared state services;
- shared S3-compatible object storage;
- at least two stateless API replicas and the intended worker topology;
- fenced singleton work, ingress, certificates, proxy headers, and the real
network/trust boundary;
- provider health and freshness for every provider required by the product;
- monitoring, alerting, failure response, accessibility, privacy, and security
controls;
- backup, isolated restore, failed-deployment rollback, and forward recovery.
For the recovery claim, retain the observed recovery point, measured RPO and
RTO, database/object-store consistency result, and semantic reconstruction of
the institutional and Service/Form reference journeys. Measure RPO from the
last acknowledged durable effect that survives recovery and RTO until service
health plus semantic reconstruction pass. Failed runs are evidence too and
must use a negative result.
The private reports stay in the approved evidence store. Give each report an
opaque artifact ID and each evaluated control a versioned opaque control ID.
## Private claim manifest
Create a private manifest conforming to
`capability-fit-boundary-run.schema.json`. Relative artifact paths resolve from
the manifest directory. Paths are read and hashed by the issuer and are never
copied into the signed output.
```json
{
"$schema": "./capability-fit-boundary-run.schema.json",
"schema_version": "0.1.0",
"evidence_kind": "govoplan.capability-fit-boundary-run",
"proof_id": "target:production:20260802",
"expires_at": "2026-09-01T00:00:00Z",
"claims": [
{
"scope": "target_environment",
"result": "passed",
"control_ids": ["topology:shared-state-v1"],
"artifacts": [
{"artifact_id": "target:run-20260802", "path": "private/target.json"}
]
},
{
"scope": "recovery",
"result": "passed",
"control_ids": ["recovery:restore-rollback-v1"],
"artifacts": [
{"artifact_id": "recovery:run-20260802", "path": "private/recovery.json"}
]
}
]
}
```
Reference readiness needs positive `target_environment`, `accessibility`,
`privacy`, `security`, `operations`, and `recovery` claims. Provider acceptance
and production approval are separate scopes. A production-approval authority
must not approve its own unreviewed target run.
## Issue and verify
Issue only while the signed installer observation is current. Repeat
`--signing-key` when multiple independent roles are needed. The command first
verifies the catalog, independent catalog trust root, exact installed payload,
installer receipt, and installer authority. It then hashes artifacts, signs the
sanitized proof, verifies it immediately, and writes both proof and review with
atomic private-file permissions.
```bash
./.venv/bin/python tools/assessments/boundary-evidence.py \
--assessment /srv/govoplan/assessment.json \
--catalog /srv/govoplan/catalogs/stable.json \
--keyring /srv/govoplan/catalogs/keyring.json \
--trusted-keyring /srv/govoplan/trust/catalog-keyring.json \
--installed-evidence /srv/govoplan/evidence/installed.json \
--installer-receipt /srv/govoplan/evidence/installer-receipt.json \
--installer-authority-keyring /srv/govoplan/trust/installer-authorities.json \
--claims /srv/govoplan/evidence/private/target-run.json \
--authority-keyring /srv/govoplan/trust/proof-authorities.json \
--signing-key authority-target=/run/secrets/target-proof-ed25519.pem \
--output /srv/govoplan/evidence/target-proof.json \
--review-output /srv/govoplan/evidence/target-proof-review.json
```
Add `--expected-external-provider-subject provider-production` when the claim
manifest contains `external_providers`. This value is an opaque deployment ID,
not a URL or credential.
## Promotion gate
The general verifier can now be made admission-enforcing. These switches return
a blocking exit status when a required claim is absent, expired, negative,
revoked, or bound to another assessment, release, installation, or subject:
```bash
./.venv/bin/python tools/assessments/capability-fit.py \
--catalog /srv/govoplan/catalogs/stable.json \
--keyring /srv/govoplan/catalogs/keyring.json \
--trusted-keyring /srv/govoplan/trust/catalog-keyring.json \
--installed-evidence /srv/govoplan/evidence/installed.json \
--installer-receipt /srv/govoplan/evidence/installer-receipt.json \
--installer-authority-keyring /srv/govoplan/trust/installer-authorities.json \
--boundary-evidence /srv/govoplan/evidence/target-proof.json \
--boundary-authority-keyring /srv/govoplan/trust/proof-authorities.json \
--require-reference-readiness \
--require-production-approval \
--output /srv/govoplan/evidence/admission-review.json
```
Use `--require-external-provider-proof` as well when the promoted product
requires an external provider. Live admission must not use
`--verification-time`; that switch is only for clearly labelled historical
review.
## Renewal and failure
Renew evidence after release, installed composition, deployment, control, or
provider changes and before expiry. Revoke an authority key immediately after
custody loss and rerun the affected assessment with a new independent key.
Never copy a previous positive claim to a new release. Preserve negative and
superseded receipts according to the approved evidence-retention policy.
@@ -0,0 +1,103 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://git.add-ideas.de/GovOPlaN/govoplan/src/branch/main/docs/capability-fit-boundary-run.schema.json",
"title": "GovOPlaN private target-run claim manifest",
"type": "object",
"additionalProperties": false,
"required": [
"schema_version",
"evidence_kind",
"proof_id",
"expires_at",
"claims"
],
"properties": {
"$schema": {
"type": "string",
"format": "uri-reference"
},
"schema_version": {
"const": "0.1.0"
},
"evidence_kind": {
"const": "govoplan.capability-fit-boundary-run"
},
"proof_id": {
"$ref": "#/$defs/opaque_id"
},
"expires_at": {
"type": "string",
"format": "date-time"
},
"claims": {
"type": "array",
"minItems": 1,
"maxItems": 8,
"items": {
"$ref": "#/$defs/claim"
}
}
},
"$defs": {
"opaque_id": {
"type": "string",
"minLength": 1,
"maxLength": 160,
"pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]*$"
},
"claim": {
"type": "object",
"additionalProperties": false,
"required": ["scope", "result", "control_ids", "artifacts"],
"properties": {
"scope": {
"enum": [
"target_environment",
"external_providers",
"accessibility",
"privacy",
"security",
"operations",
"recovery",
"production_approval"
]
},
"result": {
"enum": ["passed", "failed", "approved", "rejected"]
},
"control_ids": {
"type": "array",
"minItems": 1,
"maxItems": 256,
"uniqueItems": true,
"items": {
"$ref": "#/$defs/opaque_id"
}
},
"artifacts": {
"type": "array",
"minItems": 1,
"maxItems": 256,
"items": {
"$ref": "#/$defs/artifact"
}
}
}
},
"artifact": {
"type": "object",
"additionalProperties": false,
"required": ["artifact_id", "path"],
"properties": {
"artifact_id": {
"$ref": "#/$defs/opaque_id"
},
"path": {
"type": "string",
"minLength": 1,
"maxLength": 4096
}
}
}
}
}