contextgraph-conformance 2.0.0

Public Context Graph Protocol conformance suite (host- and provider-side) plus the contextgraph-inspect debugging binary, analogous to MCP's inspector.
Documentation
//! Every attestation this repository ships is genuine
//! (`SPEC.md` §6.5.5, F11–F13;
//! [ADR 0014](../../docs/adr/0014-attestations-on-the-wire.md)).
//!
//! `schema/validate-examples.py` proves the attested transcripts are the right
//! *shape*, and `examples_roundtrip.rs` proves the Rust types accept them. A
//! signature satisfies both while being a hundred and twenty-eight random hex
//! characters. That is the exact failure mode attestation exists to eliminate,
//! so shipping an example of it would be worse than shipping no example: a
//! provider author in another language reconciles against these bytes, and a
//! forged reference makes every implementation that matches it wrong.
//!
//! So this recomputes every commitment from the frames in hand, rebuilds the
//! Merkle root, replays every inclusion proof, and checks every signature
//! against the published example key — offline, exactly as §6.5.4 says an
//! auditor would, with no provider and no network.
//!
//! # The example key
//!
//! The example provider signs with an Ed25519 key derived from a seed of
//! thirty-two `0x2a` bytes. It is published here on purpose: an example
//! signature nobody can verify demonstrates nothing. It signs the fixtures in
//! this repository and must never sign anything else.

use std::path::PathBuf;

use contextgraph_host::wire::Envelope;
use contextgraph_types::attest::{
    AttestationVerdict, ProvenanceAttestation, digest_string, frame_commitment, public_key_for,
    result_set_commitments, result_set_root, root_from_proof,
};
use contextgraph_types::{ContextQueryResult, FrameId};

/// The seed behind every signature in `examples/`. Documented in
/// `examples/README.md` so a reimplementation can reproduce them byte for byte.
const EXAMPLE_SEED: [u8; 32] = [0x2a; 32];

/// The provider that signs the attested example exchange.
const EXAMPLE_PROVIDER: &str = "repo-graph";

fn repo_root() -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .parent()
        .expect("workspace root")
        .to_path_buf()
}

/// Every attested `frames` envelope committed anywhere in the repository,
/// paired with the file it came from.
///
/// Collected by scanning rather than by listing, so a new attested fixture is
/// held to this bar the moment it lands instead of when someone remembers to
/// add it here.
fn attested_results() -> Vec<(String, ContextQueryResult)> {
    let root = repo_root();
    let mut found = Vec::new();

    for relative in [
        "examples/full-stdio-session.ndjson",
        // Generated by `reference_vectors.rs` from the reference Rust types, so
        // this is the one surface whose bytes are the serializer's own output
        // rather than a human's transcription of it.
        "schema/reference-vectors.ndjson",
    ] {
        let path = root.join(relative);
        let raw = std::fs::read_to_string(&path)
            .unwrap_or_else(|e| panic!("could not read {}: {e}", path.display()));
        let name = relative.rsplit('/').next().expect("a file name");
        for (index, line) in raw.lines().filter(|l| !l.trim().is_empty()).enumerate() {
            let envelope: Envelope = serde_json::from_str(line).expect("valid envelope");
            if let Envelope::Frames { result, .. } = envelope
                && result.is_attested()
            {
                found.push((format!("{name} line {}", index + 1), result));
            }
        }
    }

    let messages = root.join("examples/reference-messages.json");
    let raw = std::fs::read_to_string(&messages).expect("reference messages readable");
    let values: Vec<serde_json::Value> = serde_json::from_str(&raw).expect("a JSON array");
    for (index, value) in values.iter().enumerate() {
        let envelope: Envelope = serde_json::from_value(value.clone()).expect("valid envelope");
        if let Envelope::Frames { result, .. } = envelope
            && result.is_attested()
        {
            found.push((format!("reference-messages.json message {index}"), result));
        }
    }

    found
}

/// The verdict for one attestation over an already-known commitment.
fn verdict(commitment: &[u8; 32], attestation: &ProvenanceAttestation) -> AttestationVerdict {
    contextgraph_types::attest::verify_commitment(
        commitment,
        attestation,
        &public_key_for(&EXAMPLE_SEED),
    )
}

#[test]
fn the_repository_ships_at_least_one_attested_wire_example() {
    // GOVERNANCE.md makes a wire example the witness for a normative change,
    // and every assertion below is vacuous without one. A fixture set that
    // quietly lost its attested member would turn this whole file green.
    let found = attested_results();
    assert!(
        !found.is_empty(),
        "no attested `frames` envelope found in examples/ — SPEC.md §6.5.5 is \
         specified with nothing demonstrating it"
    );
}

#[test]
fn every_shipped_per_frame_attestation_signs_the_commitment_it_claims() {
    for (source, result) in attested_results() {
        for entry in &result.frame_attestations {
            let Some(attestation) = &entry.attestation else {
                continue;
            };
            let frame = result
                .frames
                .iter()
                .find(|f| f.identity(&entry.frame.provider_id) == entry.frame)
                .unwrap_or_else(|| {
                    panic!(
                        "{source}: attestation names a frame the example does not carry: {:?}",
                        entry.frame
                    )
                });
            let expected = frame_commitment(&entry.frame.provider_id, frame);
            assert_eq!(
                attestation.signed_commitment,
                digest_string(&expected),
                "{source}: frame {} signs the wrong commitment (F7). Recompute it with \
                 contextgraph_types::attest::frame_commitment.",
                entry.frame.frame_id,
            );
            assert_eq!(
                verdict(&expected, attestation),
                AttestationVerdict::Valid,
                "{source}: frame {} carries a signature the example key does not produce",
                entry.frame.frame_id,
            );
        }
    }
}

#[test]
fn every_shipped_result_attestation_signs_the_root_over_exactly_the_frames_carried() {
    // F12. A root over a larger candidate set the provider truncated away is
    // unverifiable by construction, and an unverifiable root is worse than
    // none: it looks like evidence.
    for (source, result) in attested_results() {
        let Some(attestation) = &result.result_attestation else {
            continue;
        };
        let provider = result
            .frame_attestations
            .first()
            .map(|entry| entry.frame.provider_id.clone())
            .unwrap_or_else(|| EXAMPLE_PROVIDER.to_string());
        let root = result_set_root(&provider, &result.frames);
        assert_eq!(
            attestation.signed_commitment,
            digest_string(&root),
            "{source}: result_attestation does not sign the Merkle root over the frames it \
             travels with"
        );
        assert_eq!(
            verdict(&root, attestation),
            AttestationVerdict::Valid,
            "{source}: the result attestation is not a signature the example key produces"
        );
    }
}

#[test]
fn every_shipped_inclusion_proof_recomputes_the_signed_root() {
    for (source, result) in attested_results() {
        let Some(attestation) = &result.result_attestation else {
            continue;
        };
        let mut proofs_checked = 0;
        for entry in &result.frame_attestations {
            let Some(proof) = &entry.inclusion_proof else {
                continue;
            };
            let frame = result
                .frames
                .iter()
                .find(|f| f.identity(&entry.frame.provider_id) == entry.frame)
                .expect("the entry names a carried frame");
            let commitment = frame_commitment(&entry.frame.provider_id, frame);
            assert_eq!(
                root_from_proof(&commitment, proof).map(|root| digest_string(&root)),
                Some(attestation.signed_commitment.clone()),
                "{source}: the inclusion proof for {} does not recompute the signed root",
                entry.frame.frame_id,
            );
            assert_eq!(
                proof.leaf_count,
                result.frames.len(),
                "{source}: the proof for {} states a tree size the answer contradicts — a \
                 verifier that ignores leaf_count can be shown a proof from a differently \
                 shaped tree",
                entry.frame.frame_id,
            );
            proofs_checked += 1;
        }
        assert!(
            proofs_checked > 0,
            "{source}: a signed result set with no inclusion proof teaches the selective \
             disclosure half of §6.5.3 by omission"
        );
    }
}

#[test]
fn no_shipped_attestation_names_a_frame_the_example_does_not_carry() {
    // F11. Evidence for a frame nobody was shown is not evidence, and a host
    // that counted entries rather than matching them would report an answer as
    // more thoroughly attested than it is.
    for (source, result) in attested_results() {
        let provider = result
            .frame_attestations
            .first()
            .map(|entry| entry.frame.provider_id.clone())
            .unwrap_or_else(|| EXAMPLE_PROVIDER.to_string());
        let orphans: Vec<&FrameId> = result.orphaned_attestations(&provider);
        assert!(
            orphans.is_empty(),
            "{source}: attestations name frames the result does not carry: {orphans:?}"
        );
        for entry in &result.frame_attestations {
            assert!(
                entry.carries_evidence(),
                "{source}: the entry for {} names a frame and asserts nothing about it",
                entry.frame.frame_id
            );
        }
    }
}

#[test]
fn a_tampered_frame_is_caught_as_a_commitment_mismatch_not_a_bad_signature() {
    // The reason the example is worth shipping: it detects the tamper a bare
    // F5 digest cannot, because a tamperer rewrites the digest too. Reporting
    // it as a bad signature would send an operator hunting a key-management
    // bug when the finding is tampering (§6.5.4).
    let (source, result) = attested_results()
        .into_iter()
        .find(|(_, r)| r.frame_attestations.iter().any(|e| e.attestation.is_some()))
        .expect("an example with a per-frame signature");

    let entry = result
        .frame_attestations
        .iter()
        .find(|e| e.attestation.is_some())
        .expect("checked above");
    let attestation = entry.attestation.as_ref().expect("checked above");
    let mut frame = result
        .frames
        .iter()
        .find(|f| f.identity(&entry.frame.provider_id) == entry.frame)
        .expect("the entry names a carried frame")
        .clone();

    // Rewrite the cited source and its digest — internally consistent, and a
    // fabrication.
    frame.provenance[0].uri = Some("file:///repo/docs/not-the-source.md".into());
    frame.provenance[0].digest = Some(format!("sha256:{}", "ff".repeat(32)));

    let recomputed = frame_commitment(&entry.frame.provider_id, &frame);
    assert!(
        matches!(
            verdict(&recomputed, attestation),
            AttestationVerdict::CommitmentMismatch { .. }
        ),
        "{source}: rewriting the provenance of an attested frame must be reported as a \
         commitment mismatch"
    );
}

#[test]
fn the_signed_root_is_a_function_of_canonical_order_not_arrival_order() {
    // §6.5.3 leaves are ordered by FrameId, so a host and a provider that
    // received the frames in different orders still compute the same root. If
    // this were arrival order, relaying a result would destroy its evidence.
    let (_, result) = attested_results()
        .into_iter()
        .find(|(_, r)| r.result_attestation.is_some() && r.frames.len() > 1)
        .expect("a multi-frame signed example");

    let provider = &result.frame_attestations[0].frame.provider_id;
    let forward = result_set_root(provider, &result.frames);
    let mut shuffled = result.frames.clone();
    shuffled.reverse();
    assert_eq!(
        forward,
        result_set_root(provider, &shuffled),
        "the root must not depend on the order the frames happened to arrive in"
    );

    let ordered: Vec<FrameId> = result_set_commitments(provider, &result.frames)
        .into_iter()
        .map(|(id, _)| id)
        .collect();
    let mut expected = ordered.clone();
    expected.sort();
    assert_eq!(
        ordered, expected,
        "the leaves must be in canonical FrameId order"
    );
}