Harden registryctl governed live evidence validation#462
Conversation
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 50dc91a6ab
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| - Sanitized run result: [link to the schema-valid public result] | ||
| - Frozen Registry Stack candidate: [link to the published release] | ||
| - Immutable Solmara release and release-pin evidence: [link] |
There was a problem hiding this comment.
Remove the Solmara-only gate from this generic template
This template is linked from the external integration evidence README, whose scope is the OpenCRVS and DHIS2 integration profiles, but this required evidence item makes every pilot report depend on an immutable Solmara release. For an OpenCRVS or DHIS2 pilot, that release is unrelated, so following the template either blocks valid closing evidence or records a false prerequisite; make this field profile-neutral or move the Solmara-specific gate to the Solmara packet.
Useful? React with 👍 / 👎.
| "programme-code", | ||
| "household-reference" | ||
| ], | ||
| "format": "application/vnd.registry-notary.claim-result+json", |
There was a problem hiding this comment.
Make the live request acceptable to Notary
With this exact request body, registryctl test --live will post to Notary with Accept: application/json from execute_governed_live_test, but Notary's negotiate_request_format rejects a non-empty body format unless the Accept header permits that same media type. Following the runbook therefore fails with format_unsupported before any owner evidence is collected; omit this field from the live request example or have the live runner send the claim-result media type in Accept.
Useful? React with 👍 / 👎.
| Unset all four variables after the run. | ||
|
|
||
| Repeat the live command with separate private request and expected-result files | ||
| for each owner-approved match or no-match case. |
There was a problem hiding this comment.
Don't label no-match live runs as matches
When an operator follows this instruction for an owner-approved no-match case, the appended live FixtureReport is still hard-coded to outcome: "match" in execute_governed_live_test, so any retained JSON report records the opposite outcome even though the expected no-match fields passed. That corrupts the match/no-match evidence this packet asks maintainers to review; derive the outcome from the expected claims or use a neutral outcome before recommending no-match live runs.
Useful? React with 👍 / 👎.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 36459f2071
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| Each claim value must be a non-empty object containing only the exact `value`, | ||
| `satisfied`, or `disclosure` fields that the owner intends to verify. |
There was a problem hiding this comment.
Don't rely on partial expected fields for redaction evidence
When the owner uses this expected-result shape to prove predicate or redacted disclosure, validate_live_response only iterates the fields present in the expected object and never rejects extra fields returned by Notary, so a response that includes an unexpected value can still pass as long as satisfied/disclosure match. That can turn a live run with over-disclosure into closing evidence; tighten the live validator to reject unapproved result fields or require the expected file to enumerate forbidden fields before using this runbook for redaction evidence.
AGENTS.md reference: AGENTS.md:L79-L81
Useful? React with 👍 / 👎.
| want the full multi-service country demo. Solmara Lab does not yet have an immutable release. The | ||
| final 1.0 release-candidate reader run remains gated in | ||
| [GH#198](https://github.com/registrystack/registry-stack/issues/198) on a tagged Registry Stack | ||
| candidate and an atomically pinned Solmara Lab release. |
There was a problem hiding this comment.
Anchor the Solmara release-gate claim
This paragraph updates a current tutorial with live source-repo/release-gate facts but only backs them with a GitHub issue link; in the docs subtree, source-repo claims need code, tests, fixtures, OpenAPI, or an upstream standard, or a TODO[evidence] marker. Without that anchor, the published tutorial can present an unverified Solmara release status as current guidance, so cite a stable source artifact or mark/demote the claim.
AGENTS.md reference: docs/site/AGENTS.md:L25-L28
Useful? React with 👍 / 👎.
|
|
||
| ## Closing evidence | ||
|
|
||
| - Sanitized run result: [link to the schema-valid public result] |
There was a problem hiding this comment.
Require runner-validated public results
This closing-evidence slot asks only for a schema-valid public result, but the schema does not prove the candidate signatures/provenance, canary scan, source-access classifications, or generated-file comparisons that integration-e2-runner.py validate enforces before a result can close the release evidence gate. In pilot reports that follow the template literally, a merely schema-valid JSON artifact could be cited as closing evidence without the release-provenance checks; make this say the result was validated by the public runner.
AGENTS.md reference: AGENTS.md:L79-L81
Useful? React with 👍 / 👎.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5e1a9f9bb8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| The live runner rejects keys outside its accepted result, reference, and | ||
| provenance structures; does not accept provenance `pack_id` or `pack_version` | ||
| keys; requires exact `value`, `satisfied`, and `disclosure` matches; requires | ||
| an empty `derived_from` array; and requires a non-zero Relay consultation |
There was a problem hiding this comment.
Validate provenance constants before accepting live evidence
When an owner run uses this as closing evidence, validate_live_response only deserializes the provenance shape and checks derived_from/Relay count, so a response with provenance.schema_version or generated_by.type set to any arbitrary string still passes as long as the disclosed fields match. That can record invalid or stale provenance as a successful live evaluation even though the public claim-result schema constrains those constants; make the runner compare them to CLAIM_PROVENANCE_SCHEMA_VERSION and PROVENANCE_GENERATED_BY_CLAIM_EVALUATION before treating the evidence as valid.
AGENTS.md reference: AGENTS.md:L79-L81
Useful? React with 👍 / 👎.
| } | ||
|
|
||
| #[derive(Debug, Clone, Serialize, Deserialize)] | ||
| #[serde(deny_unknown_fields)] |
There was a problem hiding this comment.
Split cross-area changes before merging
This commit changes crate runtime/client validation, a docs-site tutorial, and release conformance materials together, which crosses three owning areas in one review unit. That makes it harder to apply the different verification gates and security-review notes for adopter evidence versus Notary model behavior; split the crate, docs, and release changes into scoped changes before merging.
AGENTS.md reference: AGENTS.md:L77-L78
Useful? React with 👍 / 👎.
| let result_view: registry_notary_core::ClaimResultView = | ||
| serde_json::from_value(result.clone()).map_err(|_| { | ||
| anyhow!( | ||
| "governed Notary result does not match the closed public claim-result schema" | ||
| ) | ||
| })?; |
There was a problem hiding this comment.
Require expires_at in live claim results
When a candidate response omits expires_at instead of returning null, this deserialization still succeeds because expires_at is an Option, and the subsequent fixture comparison only checks value, satisfied, and disclosure. The runbook says the live runner validates the closed claim-result envelope, but the public schema requires expires_at, so a non-conforming response can still become successful live evidence; explicitly require that key before returning success.
AGENTS.md reference: AGENTS.md:L79-L81
Useful? React with 👍 / 👎.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 121be1b100
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if result_view.provenance.schema_version | ||
| != registry_notary_core::CLAIM_PROVENANCE_SCHEMA_VERSION | ||
| || result_view.provenance.generated_by.entry_type | ||
| != registry_notary_core::PROVENANCE_GENERATED_BY_CLAIM_EVALUATION |
There was a problem hiding this comment.
Bind live provenance to the returned result
When a live Notary or proxy returns claim fields that match the expected file but provenance.generated_by.evaluation_id, claim_id, or claim_version names a different result, this validator still passes because it only checks the provenance constants and relay count. That can turn source-backed provenance for another evaluation or claim into accepted closing evidence for the requested claim; compare the generated_by identifiers to result_view before accepting the live run.
AGENTS.md reference: AGENTS.md:L79-L81
Useful? React with 👍 / 👎.
| registryctl test --project-dir . --environment <owner-environment> --live | ||
| ``` | ||
|
|
||
| The command refuses a production environment. |
There was a problem hiding this comment.
Narrow the production-refusal guarantee
For an owner environment named production-us or another live name whose YAML still has deployment.profile: local, this guarantee is broader than the implementation: execute_governed_live_test blocks only exact prod/production, prod-*, *-prod, or Production/EvidenceGrade profiles before sending the live request. Operators following this may believe the CLI will catch every production target; either narrow the wording to the exact guard or enforce the non-production classification/origin before the request.
AGENTS.md reference: AGENTS.md:L79-L81
Useful? React with 👍 / 👎.
| let result_view: registry_notary_core::ClaimResultView = | ||
| serde_json::from_value(result.clone()).map_err(|_| { | ||
| anyhow!( | ||
| "governed Notary result does not match the closed public claim-result schema" | ||
| ) |
There was a problem hiding this comment.
Validate live result timestamps
When a candidate response uses arbitrary strings for issued_at or non-null expires_at, this serde_json::from_value check still succeeds because ClaimResultView stores both as plain strings, and the later checks never parse them. The public claim-result schema marks those fields as date-time, so a response with invalid freshness metadata can be accepted as live evidence; parse issued_at and any non-null expires_at as RFC3339 before returning success.
AGENTS.md reference: AGENTS.md:L79-L81
Useful? React with 👍 / 👎.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3a4ff20273
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| } | ||
| for field in expected_result.keys() { | ||
| if result.get(field) != expected_result.get(field) { | ||
| for field in ["value", "satisfied", "disclosure"] { |
There was a problem hiding this comment.
Reject schema-excluded redaction fields in live results
When a live redaction run returns a redacted_fields member, this comparison still passes because the new closed-shape check deserializes into ClaimResultView, where redacted_fields is a known Rust field, and then compares only value, satisfied, and disclosure. Fresh evidence after the earlier over-disclosure fix is that current Notary can populate redacted_fields for redacted disclosures while the public ClaimResultView OpenAPI schema has additionalProperties: false and no redacted_fields, so registryctl can accept a schema-nonconforming/redaction-detail-bearing result as closing evidence; reject that member here or add it to the public schema/expected file before accepting the run.
AGENTS.md reference: AGENTS.md:L79-L81
Useful? React with 👍 / 👎.
| let result_view: registry_notary_core::ClaimResultView = | ||
| serde_json::from_value(result.clone()).map_err(|_| { | ||
| anyhow!( | ||
| "governed Notary result does not match the closed public claim-result schema" | ||
| ) | ||
| })?; |
There was a problem hiding this comment.
Reject nulls for optional public result fields
When a live response includes explicit null for optional fields such as requester_ref or provenance.generated_by.policy_id, this closed-shape check still succeeds because those members are modeled as Option, and the later validation only checks the provenance constants and Relay count. The public claim-result schema makes those properties optional but non-null when present, so a schema-nonconforming provenance/reference result can still be accepted as governed live evidence; either validate against the public schema or explicitly reject null for these optional members before returning success.
AGENTS.md reference: AGENTS.md:L79-L81
Useful? React with 👍 / 👎.
| if result_view.provenance.schema_version | ||
| != registry_notary_core::CLAIM_PROVENANCE_SCHEMA_VERSION | ||
| || result_view.provenance.generated_by.entry_type | ||
| != registry_notary_core::PROVENANCE_GENERATED_BY_CLAIM_EVALUATION | ||
| { |
There was a problem hiding this comment.
Check the result format before accepting live evidence
When a candidate Notary or proxy returns an otherwise matching result with format set to some other media type, this validation still passes because the new constant check only covers provenance. The governed runner sends Accept: application/vnd.registry-notary.claim-result+json and Notary only renders this { results: [...] } envelope on the claim-result path, so accepting a result that self-identifies as a different format can record an inconsistent/non-claim-result response as live evidence; compare result_view.format to FORMAT_CLAIM_RESULT_JSON before accepting the run.
AGENTS.md reference: AGENTS.md:L79-L81
Useful? React with 👍 / 👎.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 50d4197f82
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // The transport model carries these fields, but the closed public | ||
| // ClaimResultView schema does not expose them. | ||
| const LIVE_RESULT_SCHEMA_EXCLUDED_PATHS: &[&str] = &[ | ||
| "/redacted_fields", |
There was a problem hiding this comment.
Don’t reject Notary’s redaction marker
When the live case uses a redacted or field-redacted disclosure, current Notary populates redacted_fields in view_claim for those results (crates/registry-notary-server/src/runtime/disclosure.rs lines 110-117), and the new OpenSPP runbook includes a redacted expected claim. Fresh evidence after the earlier thread is that this commit now hard-rejects /redacted_fields before comparing the claim, so any real redaction evidence run fails against the generated Notary instead of producing closing evidence; either stop emitting the field on the public response/add it to the public schema, or don’t reject the current Notary shape here.
AGENTS.md reference: AGENTS.md:L79-L81
Useful? React with 👍 / 👎.
| "claims": [ | ||
| "social-registry-record-exists", | ||
| "social-registry-active", | ||
| "programme-code", | ||
| "household-reference" |
There was a problem hiding this comment.
Split the sample live request by disclosure
With this exact claim list and no disclosure, Notary picks one disclosure profile for the whole evaluation from the first requested claim; here that is predicate, while programme-code and household-reference are authored as value and redacted with downgrade: deny in the generated Notary config, so the request fails with DisclosureNotAllowed before any governed live evidence is returned. Split the example into per-disclosure live requests, or make the request use only claims that can all be rendered under the same disclosure mode.
Useful? React with 👍 / 👎.
| let generated_by = &result_view.provenance.generated_by; | ||
| if generated_by.evaluation_id != result_view.evaluation_id | ||
| || generated_by.claim_id != result_view.claim_id | ||
| || generated_by.claim_version != result_view.claim_version |
There was a problem hiding this comment.
When multiple claims are requested, this loop only verifies that each provenance record matches its own result, so a candidate proxy or stale cache can assemble a response where claim A comes from one evaluation_id and claim B from another and still pass as one successful live-evaluation fixture if the claim values match. The Notary evaluation path creates one evaluation for the whole request, so record the first result_view.evaluation_id and reject any subsequent mismatch before accepting the evidence.
AGENTS.md reference: AGENTS.md:L79-L81
Useful? React with 👍 / 👎.
| if !result_view.provenance.derived_from.is_empty() { | ||
| bail!("governed Notary result provenance derived_from must remain empty"); | ||
| } | ||
| let claim_id = result_view.claim_id.as_str(); |
There was a problem hiding this comment.
Bind claim versions to the project
After deserializing the result, the validator only checks claim_id against the requested set and never compares result_view.claim_version to the version authored for that project claim. If a stale Notary deployment or replayed response still has the same claim IDs and values but an older claim version, this live run is accepted as current closing evidence even though it did not exercise the exact generated project contract; carry expected claim versions out of validate_live_request and reject mismatches here.
AGENTS.md reference: AGENTS.md:L79-L81
Useful? React with 👍 / 👎.
| } | ||
|
|
||
| #[derive(Debug, Clone, Serialize, Deserialize)] | ||
| #[serde(deny_unknown_fields)] |
There was a problem hiding this comment.
This commit message has no Signed-off-by: trailer, but the repository requires every commit to carry a DCO sign-off. As-is, the change can be blocked by the DCO gate even if the code is correct, so recreate the commit with git commit -s or otherwise add the sign-off before merging.
AGENTS.md reference: AGENTS.md:L70-L70
Useful? React with 👍 / 👎.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 623e1890c9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let generated_by = &result_view.provenance.generated_by; | ||
| if generated_by.evaluation_id != result_view.evaluation_id | ||
| || generated_by.claim_id != result_view.claim_id | ||
| || generated_by.claim_version != result_view.claim_version | ||
| { |
There was a problem hiding this comment.
Bind provenance to the generated Notary service
When the live origin points at a stale Notary or proxy for another generated deployment, this check accepts a result whose provenance.generated_by.service_id does not match the deployment.notary.service from the selected environment as long as the claim IDs, versions, and values match. The runtime populates that field from the Notary config's service id, so carrying the expected service id into validate_live_response and comparing it here would prevent evidence from being attributed to the wrong candidate service.
Useful? React with 👍 / 👎.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0ce574c244
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| || environment.starts_with("prod-") | ||
| || environment.starts_with("production-") | ||
| || environment.ends_with("-prod") | ||
| || environment.ends_with("-production") |
There was a problem hiding this comment.
Block prod names with every stable-id separator
When the owner environment is named prod_us, production.eu, eu_prod, etc. while deployment.profile is still local, this production check returns false even though those are valid environment stable IDs (the loader permits _ and .). Fresh evidence after the earlier production-name thread is that the current guard only covers hyphen-separated prod/production names, so registryctl test --live can still post governed live requests to a production-labeled environment; split/normalize on every allowed stable-id separator or require an explicit non-production profile before sending.
Useful? React with 👍 / 👎.
| let result_view: registry_notary_core::ClaimResultView = | ||
| serde_json::from_value(result.clone()).map_err(|_| { | ||
| anyhow!( | ||
| "governed Notary result does not match the closed public claim-result schema" | ||
| ) | ||
| })?; |
There was a problem hiding this comment.
Reject raw entity handles in live results
When a live Notary or proxy returns otherwise matching claim fields but puts a raw subject/requester identifier in target_ref.handle or requester_ref.handle, this closed-shape deserialize still accepts it because those handles are just strings and no later check constrains the pseudonymous rnref:v1: form that current Notary emits. That can turn a data-minimization failure into passing governed evidence; require public refs to use the Notary pseudonymous handle shape, or compare them with owner-approved expected refs, before accepting the run.
AGENTS.md reference: AGENTS.md:L79-L81
Useful? React with 👍 / 👎.
| if result.value.is_some() | ||
| || result.satisfied.is_some() | ||
| || result.redacted_fields.is_empty() |
There was a problem hiding this comment.
Validate full-redaction marker contents
When a redacted live result returns value: null and satisfied: null, this branch accepts any non-empty redacted_fields, so a proxy can include an empty string, duplicates, other-claim, or even a value-bearing marker such as ssn=123 and still pass as redaction evidence because the expected file only compares value, satisfied, and disclosure. Current Notary's marker is the claim id or top-level redacted field names, so apply the same bounded/top-level validation here before retaining the public evidence.
AGENTS.md reference: AGENTS.md:L79-L81
Useful? React with 👍 / 👎.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cc304b58b7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| || *field == "value" | ||
| || field.contains('.') | ||
| || field.contains('[') | ||
| || field.contains(']') | ||
| || value.contains_key(*field) |
There was a problem hiding this comment.
Constrain field-redaction markers before accepting evidence
When a value-disclosure result includes redacted_fields, this check only rejects path-like names, duplicates, value, and fields that still appear in the returned object; it does not apply the bounded stable-id check used for owner-approved full-redaction markers. A live Notary proxy could therefore return redacted_fields: ["ssn=123"] with that field removed from value and still pass as governed evidence, leaking a redacted value through metadata. Reuse the same bounded top-level marker validation for runtime field-redaction markers before accepting the result.
AGENTS.md reference: AGENTS.md:L79-L81
Useful? React with 👍 / 👎.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 970b168f44
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if OffsetDateTime::parse(&result_view.issued_at, &Rfc3339).is_err() | ||
| || result_view.expires_at.as_deref().is_some_and(|expires_at| { | ||
| OffsetDateTime::parse(expires_at, &Rfc3339).is_err() | ||
| }) |
There was a problem hiding this comment.
Reject stale live claim-result timestamps
When a candidate Notary proxy or stale cache replays an older response whose claim values, service id, and claim versions still match, these lines only parse issued_at/expires_at; they never require issued_at to fall within the current live run or a non-null expires_at to still be in the future. Even an already-expired result is accepted, so registryctl test --live can record passing live evidence without exercising the current candidate deployment; compare the timestamps to the request/run time before accepting the result.
AGENTS.md reference: AGENTS.md:L79-L81
Useful? React with 👍 / 👎.
| if !result_view.provenance.derived_from.is_empty() { | ||
| bail!("governed Notary result provenance derived_from must remain empty"); | ||
| } | ||
| validate_live_result_reference_handles(&result_view)?; |
There was a problem hiding this comment.
Reject mixed target refs in live evidence
When a multi-claim live response keeps the same evaluation_id but combines results for different target_ref or requester_ref handles, this validation only checks that each handle has the pseudonymous shape and then accepts the evidence if the claim values match. The Notary evaluation path renders all requested claims for one request target/requester, so a proxy or stale cache can splice facts from different subjects into one passing live-evaluation fixture; remember the first refs and reject subsequent mismatches before accepting the response.
Useful? React with 👍 / 👎.
| "/provenance/generated_by/policy_id", | ||
| "/provenance/generated_by/policy_version", | ||
| "/provenance/generated_by/policy_hash", |
There was a problem hiding this comment.
Reject policy provenance on API-key live runs
In registryctl test --live the evaluation is sent with the deployed x-api-key machine-client credential, and current Notary leaves policy_id, policy_version, and policy_hash unset for non-subject-access evaluations; this check only rejects explicit nulls, so a proxy can return otherwise matching results from a subject-access or other named-policy evaluation and still have them accepted as governed live evidence for the API-key run. Require these optional policy fields to be absent, or compare them with an owner-approved expected policy, before accepting the result.
AGENTS.md reference: AGENTS.md:L79-L81
Useful? React with 👍 / 👎.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
What changed
redacted_fieldspublic field.redacted_fieldsset in that claim's expected-result entry.rnref:v1:(hmac-sha256|sha256):<64 lowercase hex>pseudonym shape before evidence is accepted.expires_atremains valid.expires_at, non-null optional fields when present, and production-classified environment refusal. Environment names are classified by exactprodorproductiontokens across every stable-ID separator:-,_, and..Why
The OpenSPP holdout must produce reviewable evidence through the generic Registry project path without accepting replayed, expired, cross-subject, or mixed evaluation results, responses from another generated Notary service, wrong evaluation policy provenance, raw entity handles, unbound redaction markers, schema drift, disclosure-incompatible requests, or structurally nonconforming Notary output.
Implementer impact
Implementers get early, value-free validation errors when a live request or result diverges from the generated project contract. Existing expected-result files remain valid for Notary's default claim-ID redaction marker. Deployments that configure top-level redaction fields add one bounded owner-approved
redacted_fieldsset to the affected fully redacted claim expectation. The documented examples match Notary's one-disclosure-per-evaluation behavior.Security review
The validator fails closed before evidence acceptance on unknown fields, stale/future/expired timestamps, inconsistent evaluation refs, unexpected named policy provenance, misbound service/result identifiers or versions, mixed evaluation IDs, invalid format, omitted required keys, forbidden nulls, raw or malformed public handles, stale provenance constants, inconsistent or unbound redaction semantics, and over-disclosure relative to the owner-approved expectation.
Validation
spin 0.9.8yanked warning remainsgit diff --checkIssue status
Progresses #357 but does not close it. Closure still requires the product-owner live OpenSPP journey against an exact version and operation through the final generated Relay-to-Notary path.