#![cfg(test)]
use std::collections::BTreeSet;
use std::path::{Path, PathBuf};
const PRODUCED_UNPUBLISHED: &[(&str, &str)] = &[
(
"https://trusttasks.org/spec/vta/attestation/status/1.0",
"Found by this census on the day it was written, which is the case \
for having it: REST-routed rather than dispatched, so the served-URI \
harness never saw it. Unauthenticated and internet-reachable — the \
thing a verifier checks *before* deciding to trust this VTA — and \
the one surface here whose counterparty is not the operator. \
Tracked in #1177.",
),
(
"https://trusttasks.org/spec/vta/attestation/report/1.0",
"Same family and same route as `attestation/status/1.0`; publishing \
one without the other leaves a verifier able to ask the question but \
not read the answer. Tracked in #1177.",
),
];
const NOT_PRODUCED: &[(&str, &str)] = &[(
"https://trusttasks.org/spec/does-not-exist/9.9",
"Negative fixture: `class_for` must return `None` for an unknown URI, and \
`method_not_found` must reject an unknown *family* as `unsupportedType` \
rather than as a version skew. Deliberately names nothing.",
)];
fn workspace_root() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("vta-service has a parent directory")
.to_path_buf()
}
fn spec_uri_literals(dir: &Path) -> BTreeSet<String> {
fn walk(dir: &Path, out: &mut BTreeSet<String>) {
for entry in std::fs::read_dir(dir).expect("read source dir") {
let path = entry.expect("dir entry").path();
if path.is_dir() {
walk(&path, out);
} else if path.extension().is_some_and(|e| e == "rs") {
let text = std::fs::read_to_string(&path).expect("read source file");
for (idx, _) in text.match_indices(PREFIX) {
if idx == 0 || !text[..idx].ends_with('"') {
continue;
}
let rest = &text[idx..];
let Some(end) = rest.find('"') else { continue };
let uri = rest[..end].split('#').next().expect("split has a head");
if uri.ends_with('/') || uri.contains('{') {
continue;
}
out.insert(uri.to_owned());
}
}
}
}
let mut found = BTreeSet::new();
walk(dir, &mut found);
found
}
const PREFIX: &str = "https://trusttasks.org/spec/";
#[test]
fn every_produced_uri_is_published_or_tracked() {
let root = workspace_root();
let named = spec_uri_literals(&root.join("vta-service/src"));
let served: BTreeSet<String> = super::dispatched_uris()
.into_iter()
.map(str::to_owned)
.collect();
let tracked: BTreeSet<&str> = PRODUCED_UNPUBLISHED.iter().map(|(u, _)| *u).collect();
let not_produced: BTreeSet<&str> = NOT_PRODUCED.iter().map(|(u, _)| *u).collect();
let untracked: Vec<&String> = named
.iter()
.filter(|u| trust_tasks_rs::schema_index::schema_for(u).is_none())
.filter(|u| !u.starts_with("https://trusttasks.org/spec/trust-task-error/"))
.filter(|u| !served.contains(*u))
.filter(|u| !tracked.contains(u.as_str()))
.filter(|u| !not_produced.contains(u.as_str()))
.collect();
assert!(
untracked.is_empty(),
"these Trust Task URIs are produced by vta-service with no published \
schema, and nothing tracks them:\n{}\n\nA produced document with no \
spec has no validation on either side and no page a peer could \
implement from. Publish the spec upstream, or — if it genuinely \
cannot be published yet — add it to PRODUCED_UNPUBLISHED with the \
reason and a tracking issue.",
untracked
.iter()
.map(|u| format!(" {u}"))
.collect::<Vec<_>>()
.join("\n")
);
}
#[test]
fn no_tracked_entry_outlives_its_spec() {
let published: Vec<&str> = PRODUCED_UNPUBLISHED
.iter()
.map(|(u, _)| *u)
.filter(|u| trust_tasks_rs::schema_index::schema_for(u).is_some())
.collect();
assert!(
published.is_empty(),
"these have a published spec now and must be removed from \
PRODUCED_UNPUBLISHED:\n{}",
published
.iter()
.map(|u| format!(" {u}"))
.collect::<Vec<_>>()
.join("\n")
);
}
#[test]
fn every_tracked_entry_states_why() {
for (uri, reason) in PRODUCED_UNPUBLISHED.iter().chain(NOT_PRODUCED) {
assert!(
reason.len() > 40,
"{uri}: the reason must say why this cannot be published yet and \
where it is tracked"
);
}
}
const RENDERED_TO_A_HUMAN: &[(&str, &str)] = &[(
"https://trusttasks.org/spec/consent/approve-request/0.1",
"vta-service/src/trust_tasks/consent.rs",
)];
const SIGNING_MARKERS: &[&str] = &["DataIntegrityProof::sign", "\"issuer\"", "\"recipient\""];
#[test]
fn a_prompt_a_person_answers_is_signed_and_addressed() {
let root = workspace_root();
for (uri, file) in RENDERED_TO_A_HUMAN {
let path = root.join(file);
let text = std::fs::read_to_string(&path).unwrap_or_else(|e| {
panic!("`{file}` is named by RENDERED_TO_A_HUMAN but cannot be read: {e}")
});
for marker in SIGNING_MARKERS {
assert!(
text.contains(marker),
"`{uri}` is shown to a person and answered by them, but `{file}` \
does not contain `{marker}`. A prompt that reaches a phone \
authenticated by nothing the device can check is #1177; if this \
document moved, move its entry in RENDERED_TO_A_HUMAN with it."
);
}
}
}
#[test]
fn every_human_facing_entry_still_names_a_produced_uri() {
let root = workspace_root();
let named = spec_uri_literals(&root.join("vta-service/src"));
for (uri, file) in RENDERED_TO_A_HUMAN {
assert!(
named.contains(*uri),
"RENDERED_TO_A_HUMAN lists `{uri}` (in `{file}`), but no source \
literal under `vta-service/src` names it any more. Remove the \
entry, or restore the document it was guarding."
);
}
}