fix(assessment): harden capability evidence trust

This commit is contained in:
2026-07-22 19:21:06 +02:00
parent 1dc9148ec3
commit 19c4b63ade
8 changed files with 1928 additions and 153 deletions

View File

@@ -360,7 +360,11 @@ windows. Only `active` and `next` entries are trusted; unknown statuses,
duplicate key IDs and malformed structured keyrings fail closed, while revoked,
disabled and retired entries are ignored. Do not establish this trust file by
downloading it in the same rerun. Public JSON responses are bounded to 16 MiB.
Use `--json` or `--output PATH` for automation.
Use `--json` or `--output PATH` for automation. Evidence and report files are
written through a bounded same-directory atomic replacement, with mode `0600`
and file and directory `fsync`. All parent directories must already exist, no
parent component may be a symlink, and an existing symlink or non-regular output
target is rejected.
Exit status `0` means the assessed release metadata is current, `2` means
explicit review is required, and `1` means the schema or trust checks are
@@ -385,7 +389,7 @@ that observation to the assessment and signed catalog:
--output /var/tmp/govoplan-fit-review.json
```
The collector follows the strict
The collector follows the strict version `0.2.0`
[`installed-composition-evidence.schema.json`](installed-composition-evidence.schema.json)
contract. It enumerates all installed distributions whose normalized name starts
with `govoplan-`, compares the enabled assessed package and module-manifest
@@ -395,11 +399,18 @@ entries and evidence-backed conclusions.
For each distribution, the collector also:
- verifies every supported SHA-256 entry in installed wheel `RECORD` metadata,
- verifies every supported SHA-256 immutable wheel-payload entry in installed
`RECORD` metadata,
within fixed limits of 256 GovOPlaN distributions, 10,000 files and 512 MiB
hashed per distribution, 50,000 files and 2 GiB hashed for one collection,
and 64 MiB for any single file;
- distinguishes immutable VCS commits and archive hashes from editable installs,
- accepts package-owned data-file targets below the installation prefix and
declared `console_scripts`, while rejecting other traversal, undeclared
scripts, paths outside the prefix and leaf symlinks before opening a file;
- reports pip-generated, unhashed `__pycache__/*.pyc` entries separately only
when their derived source is a hashed payload entry, including generated
files below a confined package-owned runtime-data prefix;
- distinguishes coherent PEP 610 Git commits and archive hashes from editable installs,
local directories, package-index/unknown origins and malformed metadata;
- compares a non-editable VCS commit with the assessment commit and, when one is
present, the signed catalog `selected_units` commit;
@@ -407,16 +418,29 @@ For each distribution, the collector also:
and stable error codes. It never writes direct URLs, paths, hostnames,
usernames, exception text or file contents.
`RECORD` agreement proves that the files agree with their installed metadata; it
does not make self-consistent metadata a trusted release origin. Similarly, a
version string is not artifact integrity. Editable and directory-backed installs
`RECORD` `verified` means complete matching coverage of the immutable wheel
payload, not every runtime byte. The proof scope exposes the aggregate count of
generated unhashed bytecode; runtime activation remains unchecked. `RECORD`
agreement proves that payload files agree with installed metadata, but does not
make self-consistent metadata a trusted release origin. Similarly, a version
string is not artifact integrity. PEP 610 VCS evidence is accepted only for
`vcs: git`, a full 4064 hexadecimal commit, one mutually exclusive provenance
form and a coherent bounded URL shape. Editable and directory-backed installs
remain mutable even when their small editable-install `RECORD` is valid. Archive
or index artifacts without a hash anchored by the assessed release remain
unanchored. These conditions cause review rather than being promoted to
immutable installed-release proof.
Use `--installed-evidence PATH` to review evidence collected in a separate
environment. Evidence input and output are bounded to 4 MiB. Collection loads
Only evidence produced in-process by `--collect-installed-evidence` is a local
observation, and it must be no more than five minutes old (with at most 30
seconds of future clock skew) at the selected verification time. Use
`--installed-evidence PATH` to compare evidence collected in a separate
environment. Imported JSON is unsigned and therefore always carries a blocker:
it can identify differences but cannot establish checked or valid installed
proof. A future signed collector-attestation format is required to cross that
boundary. The proof scope records observation mode, collection/evaluation time,
freshness, and whether evaluation used current time or an explicit historical
override. Evidence input and output are bounded to 4 MiB. Collection loads
the `govoplan.modules` entry-point factories in order to read module IDs and
manifest versions; that executes installed GovOPlaN manifest code. Run it only
inside the installation being assessed and with the same isolation expected for
@@ -453,16 +477,35 @@ the tool's deterministic canonicalization.
--trusted-keyring /srv/govoplan/trust/catalog-keyring.json \
--installed-evidence /srv/govoplan/evidence/installed.json \
--boundary-evidence /srv/govoplan/evidence/target-proof.json \
--boundary-authority-keyring /srv/govoplan/trust/proof-authorities.json
--boundary-authority-keyring /srv/govoplan/trust/proof-authorities.json \
--expected-external-provider-subject provider-production
```
With `--installed-evidence`, this command performs comparison and proof-binding
diagnostics only: the imported installed document is unsigned, so neither it nor
the boundary claim becomes accepted proof. An accepted boundary review requires
a trusted orchestrator to retain the direct in-process observation, obtain the
external signature over its digest, and call the review library within the
five-minute observation window. A future signed collector-attestation format
should make that exchange durable across processes.
Target-environment and production-approval claims must use the assessment's
`deployment_profile.id` as `subject_id`. External-provider claims require the
operator to supply a bounded opaque expected subject with
`--expected-external-provider-subject`; without it, such a claim remains
unchecked and blocks. Expected and observed IDs are retained in proof scope.
The authority keyring is a governance trust root. Do not download or generate it
from the proof bundle being checked, and do not reuse catalog signing authority
as implicit production authority. A target operator or approver must validate
from the proof bundle being checked. The checker rejects proof-authority public
keys reused by either the published or independently trusted catalog keyring,
and rejects the same proof public-key material assigned to multiple authority
IDs. Authority `not_after` is exclusive. A target operator or approver must validate
the referenced drill/result artifacts before signing. The rerun verifies the
attestation and its bindings; it does not fetch or reinterpret those artifacts.
`--verification-time` exists for reproducible historical review. Live admission
must use the actual current time.
`--verification-time` exists only for reproducible historical review. Supplying
it always marks the machine and human report as a **HISTORICAL override**; callers
cannot relabel it as current. Live admission must omit it and use the actual
current time.
No boundary bundle or production authority has been supplied for this current
assessment. Target environment, provider and production proof therefore remain

View File

@@ -20,7 +20,7 @@
"format": "uri-reference"
},
"schema_version": {
"const": "0.1.0"
"const": "0.2.0"
},
"evidence_kind": {
"const": "govoplan.installed-composition"
@@ -125,7 +125,7 @@
"required": ["kind", "commit"],
"properties": {
"kind": {
"enum": ["vcs-commit", "editable-vcs"]
"const": "vcs-commit"
},
"commit": {
"type": "string",
@@ -170,6 +170,7 @@
"status",
"hashed_file_count",
"permitted_unhashed_file_count",
"generated_unhashed_file_count",
"unverifiable_file_count",
"missing_file_count",
"mismatched_file_count"
@@ -190,6 +191,9 @@
"permitted_unhashed_file_count": {
"$ref": "#/$defs/count"
},
"generated_unhashed_file_count": {
"$ref": "#/$defs/count"
},
"unverifiable_file_count": {
"$ref": "#/$defs/count"
},
@@ -199,7 +203,51 @@
"mismatched_file_count": {
"$ref": "#/$defs/count"
}
}
},
"allOf": [
{
"if": { "properties": { "status": { "const": "verified" } } },
"then": {
"properties": {
"hashed_file_count": { "minimum": 1 },
"permitted_unhashed_file_count": { "minimum": 1 },
"unverifiable_file_count": { "const": 0 },
"missing_file_count": { "const": 0 },
"mismatched_file_count": { "const": 0 }
}
}
},
{
"if": { "properties": { "status": { "const": "partial" } } },
"then": {
"properties": {
"hashed_file_count": { "minimum": 1 },
"unverifiable_file_count": { "minimum": 1 },
"missing_file_count": { "const": 0 },
"mismatched_file_count": { "const": 0 }
}
}
},
{
"if": { "properties": { "status": { "const": "mismatch" } } },
"then": {
"anyOf": [
{ "properties": { "missing_file_count": { "minimum": 1 } } },
{ "properties": { "mismatched_file_count": { "minimum": 1 } } }
]
}
},
{
"if": { "properties": { "status": { "const": "unavailable" } } },
"then": {
"properties": {
"hashed_file_count": { "const": 0 },
"missing_file_count": { "const": 0 },
"mismatched_file_count": { "const": 0 }
}
}
}
]
},
"collection_issue": {
"type": "object",