sandbox-conformance: hold the committed pack to what the builders emit #422

Merged
dcharlot merged 1 commit from fix/sandbox-vector-drift into main 2026-10-22 06:51:31 -04:00
4 changed files with 44 additions and 44 deletions

View file

@ -258,7 +258,9 @@ pub struct Attestation {
pub audit_prev: Option<ContentId>,
/// How confinement was established (SPEC §7.9). Meaningful at S1–S5, where
/// the tier is otherwise host-asserted with no in-band evidence; MUST be
/// absent at S0, which is unconfined by definition.
/// absent at S0, which is unconfined by definition. Omitted from the
/// serialized form when absent, as from the signed core (§7.9).
#[serde(default, skip_serializing_if = "Option::is_none")]
pub mechanism: Option<Mechanism>,
/// Evidence bounding where the run could **not** have executed (SPEC §7.7).
///

View file

@ -12,51 +12,11 @@ use sandbox_conformance::vectors;
fn main() -> std::io::Result<()> {
let dir = vectors::vectors_dir();
std::fs::create_dir_all(&dir)?;
let write = |name: &str, json: String| -> std::io::Result<()> {
for (name, bytes) in vectors::rendered() {
let path = dir.join(name);
std::fs::write(&path, json + "\n")?;
std::fs::write(&path, bytes)?;
println!("wrote {}", path.display());
Ok(())
};
write(
"content_addressing.json",
serde_json::to_string_pretty(&vectors::content_vectors()).unwrap(),
)?;
write(
"capability.json",
serde_json::to_string_pretty(&vectors::capability_vectors()).unwrap(),
)?;
write(
"receipt.json",
serde_json::to_string_pretty(&vectors::receipt_vector()).unwrap(),
)?;
write(
"attestation.json",
serde_json::to_string_pretty(&vectors::attestation_vector()).unwrap(),
)?;
write(
"tier.json",
serde_json::to_string_pretty(&vectors::tier_vectors()).unwrap(),
)?;
write(
"durable.json",
serde_json::to_string_pretty(&vectors::durable_vector()).unwrap(),
)?;
write(
"negative.json",
serde_json::to_string_pretty(&vectors::negative_pack()).unwrap(),
)?;
write(
"confidential.json",
serde_json::to_string_pretty(&vectors::confidential_pack()).unwrap(),
)?;
write(
"flow.json",
serde_json::to_string_pretty(&vectors::flow_vectors()).unwrap(),
)?;
}
println!("\nRegenerated conformance vectors. Verify with `cargo test -p sandbox-conformance`.");
Ok(())
}

View file

@ -714,6 +714,25 @@ mod tests {
assert_eq!(report.results.len(), 13);
}
/// The committed pack is exactly what the builders emit, file for file
/// and byte for byte. The file-backed checks prove each committed file is
/// valid; this proves it is the current one. Without it, a change to a
/// builder or to a type's serialized shape left the published pack behind,
/// and nothing noticed: `"mechanism": null` sat unpublished in the
/// attestation and negative packs for a release.
#[test]
fn the_committed_pack_is_what_the_builders_emit() {
use vectors::*;
let rendered = rendered();
let names: Vec<&str> = rendered.iter().map(|(n, _)| *n).collect();
let listed: Vec<&str> = FILES.iter().map(|(n, _)| *n).collect();
assert_eq!(names, listed, "the rendered set is the listed set");
for (name, bytes) in rendered {
let committed = std::fs::read_to_string(vectors_dir().join(name)).unwrap();
assert!(committed == bytes, "{name} differs from what the builders emit: run gen_vectors and commit the result");
}
}
#[test]
fn vector_builders_round_trip_in_memory() {
// The reference's own vector builders must satisfy their own checkers

View file

@ -997,6 +997,25 @@ pub fn vectors_dir() -> std::path::PathBuf {
.join("../../../conformance/v1")
}
/// Every committed vector file, by name, as the `gen_vectors` binary writes
/// it: the pretty JSON of its builder and a final newline. A test holds the
/// committed pack to this, so the builders and the published files cannot
/// part.
pub fn rendered() -> Vec<(&'static str, String)> {
let pretty = |v: serde_json::Result<String>| v.expect("a vector serializes") + "\n";
vec![
("content_addressing.json", pretty(serde_json::to_string_pretty(&content_vectors()))),
("capability.json", pretty(serde_json::to_string_pretty(&capability_vectors()))),
("receipt.json", pretty(serde_json::to_string_pretty(&receipt_vector()))),
("attestation.json", pretty(serde_json::to_string_pretty(&attestation_vector()))),
("tier.json", pretty(serde_json::to_string_pretty(&tier_vectors()))),
("durable.json", pretty(serde_json::to_string_pretty(&durable_vector()))),
("negative.json", pretty(serde_json::to_string_pretty(&negative_pack()))),
("confidential.json", pretty(serde_json::to_string_pretty(&confidential_pack()))),
("flow.json", pretty(serde_json::to_string_pretty(&flow_vectors()))),
]
}
pub const FILES: [(&str, &str); 9] = [
("content_addressing.json", "C1"),
("capability.json", "C2"),