Skip to content

Commit d1ec2f0

Browse files
committed
feat(evidence): report each definition's validitySeconds in explain
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
1 parent 8a2270a commit d1ec2f0

4 files changed

Lines changed: 43 additions & 2 deletions

File tree

‎crates/registry-evidencectl/src/normalized.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ pub(crate) fn inspect(root: &Path, target: Option<&Path>, command: &str) -> Resu
203203
.context("canonicalizing effective grants")?;
204204
authority = json!({"target":target.id,"effectiveGrantDigest":registry_platform_config::sha256_uri(&effective),"authorityRevision":format!("sha256:{}", hex::encode(domain_separated_sha256(b"registry.evidence.target-authority/v1\0", &canonical))),"digest":registry_platform_config::sha256_uri(&canonical),"accessProfiles":document["accessProfiles"],"effectiveCeilings":project.assertion_definitions.iter().map(|(id,d)| (id.as_str(),json!({"grantCeiling":d.grant_ceiling,"purpose":d.purpose,"subjects":d.subjects,"representations":d.representations,"subjectBinding":d.subject_binding}))).collect::<BTreeMap<_,_>>()});
205205
}
206-
let definitions = project.assertion_definitions.iter().map(|(id, definition)| json!({"id":id,"label":definition.label,"description":definition.description,"question":definition.question,"requirement":definition.semantics.requirement,"acquisition":definition.acquisition,"derive":definition.derive,"outputs":definition.outputs,"grantCeiling":definition.grant_ceiling,"representations":definition.representations,"subjectBinding":definition.subject_binding})).collect::<Vec<_>>();
206+
let definitions = project.assertion_definitions.iter().map(|(id, definition)| json!({"id":id,"label":definition.label,"description":definition.description,"question":definition.question,"requirement":definition.semantics.requirement,"acquisition":definition.acquisition,"derive":definition.derive,"outputs":definition.outputs,"grantCeiling":definition.grant_ceiling,"representations":definition.representations,"subjectBinding":definition.subject_binding,"validitySeconds":definition.validity_seconds})).collect::<Vec<_>>();
207207
Ok(Checked {
208208
report: crate::report::success(
209209
command,

‎crates/registry-evidencectl/tests/explain_sources.rs‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,39 @@ fn malformed_project_is_refused_without_printing_private_source_values() {
7676
assert!(!printed.contains(CANARY), "{printed}");
7777
assert!(!printed.contains("Source coverage-record"), "{printed}");
7878
}
79+
80+
#[test]
81+
fn explain_json_reports_each_definitions_validity_seconds() {
82+
let temporary = tempfile::tempdir().expect("temporary project");
83+
copy_tree(&project("standalone"), temporary.path());
84+
let manifest = temporary.path().join("evidence.yaml");
85+
let authored = fs::read_to_string(&manifest).expect("read project manifest");
86+
let changed = authored.replacen("validitySeconds: 300", "validitySeconds: 900", 1);
87+
assert_ne!(changed, authored, "fixture mutation must apply");
88+
fs::write(&manifest, changed).expect("write project manifest");
89+
90+
let output = Command::new(env!("CARGO_BIN_EXE_evidencectl"))
91+
.args(["--format", "json", "explain"])
92+
.arg(temporary.path())
93+
.output()
94+
.expect("run evidencectl explain");
95+
let stdout = String::from_utf8_lossy(&output.stdout);
96+
let stderr = String::from_utf8_lossy(&output.stderr);
97+
assert!(output.status.success(), "{stdout}{stderr}");
98+
let report: serde_json::Value = serde_json::from_str(&stdout).expect("explain JSON report");
99+
let definitions = report["assertionDefinitions"]
100+
.as_array()
101+
.unwrap_or_else(|| panic!("assertionDefinitions array in {stdout}"));
102+
assert!(definitions.len() >= 2, "{stdout}");
103+
let validities: Vec<_> = definitions
104+
.iter()
105+
.map(|definition| definition["validitySeconds"].as_u64())
106+
.collect();
107+
assert_eq!(validities[0], Some(900), "{validities:?}");
108+
assert!(
109+
validities[1..]
110+
.iter()
111+
.all(|validity| *validity == Some(300)),
112+
"{validities:?}"
113+
);
114+
}

‎products/evidence/CHANGELOG.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
## Unreleased
44

5+
- `evidencectl explain` JSON reports each assertion definition's
6+
`validitySeconds` beside its `representations` and `subjectBinding`. The
7+
field is additive; the report `apiVersion` is unchanged.
58
- A normalized target document accepts an optional
69
`signing.maximumAssertionValiditySeconds` (1 to 31,536,000, default 300) so a
710
definition with a longer `validitySeconds`, such as a seven-day holder-bound

‎products/evidence/README.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,9 @@ bounded source/extraction/derivation path using supplied synthetic responses.
102102
`explain` shows each definition's ordered source operations, preparation and
103103
extraction Functions, private fact names, derivation and output names, with
104104
connection identifiers and source limits. Sources not referenced by a definition
105-
are listed separately. The human report contains no source values or credentials.
105+
are listed separately. The JSON report's `assertionDefinitions` entries also
106+
carry each definition's `validitySeconds`, so a reader can compare credential
107+
lifetimes without compiling. The human report contains no source values or credentials.
106108

107109
`evidencectl check --file <file>` checks one tooling file offline, including a
108110
client profile, local access client registration, reviewed contracts, development state or source-import document.

0 commit comments

Comments
 (0)