lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

commit fd8ac5539de80b0984f754dd072dc7d909671070
parent 2aa953aa7c49a133daaef0407fc1b21074aec399
Author: triesap <tyson@radroots.org>
Date:   Thu, 30 Jul 2026 01:54:35 +0000

event-codec: complete package conformance coverage

- execute every knowledge manifest and verified-decode conformance vector
- keep the package fixture byte-identical to its canonical contract corpus
- assert canonical exports, no-std intent, and forbidden host dependency paths
- qualify every feature combination, supported target, doctest, and fuzz target

Diffstat:
Acrates/event_codec/tests/fixtures/knowledge_manifest_and_decode.v1.json | 156+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcrates/event_codec/tests/knowledge_fixtures.rs | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcrates/event_codec/tests/package_boundary.rs | 42+++++++++++++++++++++++++++++++++++++++++-
3 files changed, 316 insertions(+), 1 deletion(-)

diff --git a/crates/event_codec/tests/fixtures/knowledge_manifest_and_decode.v1.json b/crates/event_codec/tests/fixtures/knowledge_manifest_and_decode.v1.json @@ -0,0 +1,156 @@ +{ + "suite": "knowledge_manifest_and_decode", + "contract_version": "1.0.0", + "vectors": [ + { + "id": "knowledge_manifest_fields_valid_001", + "kind": "knowledge.contract_manifest_json.valid", + "input": { + "registry": "radroots_event_contract_registry_v7" + }, + "expected": { + "schema_version": 2, + "registry_version": 7, + "required_fields": [ + "schema_version", + "registry_version", + "radroots_event_version", + "radroots_event_codec_version", + "contract_id", + "kind", + "class", + "standard", + "stability", + "privacy", + "content_schema", + "discriminators", + "tag_contracts", + "codec_support", + "sdk_builder_support", + "sdk_draft_support", + "wasm_tag_builder_support", + "wasm_verified_decode_support", + "deprecated", + "replaced_by", + "introduced_at" + ] + } + }, + { + "id": "knowledge_verify_decode_claim_valid_002", + "kind": "knowledge.verify_and_decode_event.valid", + "input": { + "fixture": "knowledge_claim_valid" + }, + "expected": { + "contract_id": "radroots.knowledge.claim.v1", + "decoded_variant": "KnowledgeClaim" + } + }, + { + "id": "knowledge_missing_contract_invalid_003", + "kind": "knowledge.verify_and_decode_event.invalid", + "input": { + "fixture": "missing_contract_id" + }, + "expected": { + "error_class": "decode_error", + "stage": "contract_validation" + } + }, + { + "id": "knowledge_nip54_wiki_article_fork_defer_valid_004", + "kind": "knowledge.nip54.wiki_article_tags.valid", + "input": { + "fixture": "wiki_article_valid" + }, + "expected": { + "fork_address_tag": [ + "a", + "30818:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:soil-health", + "wss://relay.example.com", + "fork" + ], + "fork_event_tag": [ + "e", + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "wss://relay.example.com", + "fork" + ], + "defer_address_tag": [ + "a", + "30818:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:soil-health-v2", + "wss://relay.example.com", + "defer" + ], + "defer_event_tag": [ + "e", + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", + "wss://relay.example.com", + "defer" + ] + } + }, + { + "id": "knowledge_nip54_redirect_valid_005", + "kind": "knowledge.nip54.wiki_redirect_tags.valid", + "input": { + "fixture": "wiki_redirect_valid" + }, + "expected": { + "target_tag": [ + "a", + "30818:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:soil-health", + "wss://relay.example.com" + ] + } + }, + { + "id": "knowledge_nip54_merge_request_valid_006", + "kind": "knowledge.nip54.wiki_merge_request.valid", + "input": { + "fixture": "wiki_merge_request_valid" + }, + "expected": { + "content": "Merge synthetic soil article updates", + "target_tag": [ + "a", + "30818:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:soil-health", + "wss://relay.example.com" + ], + "destination_tag": [ + "p", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + ], + "base_event_tag": [ + "e", + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "" + ], + "source_event_tag": [ + "e", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "", + "source" + ] + } + }, + { + "id": "knowledge_nip54_merge_request_without_base_valid_007", + "kind": "knowledge.nip54.wiki_merge_request.valid", + "input": { + "fixture": "wiki_merge_request_without_base_valid" + }, + "expected": { + "content": "Merge synthetic soil article updates", + "base_version_event_id": null, + "source_event_tag": [ + "e", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "", + "source" + ] + } + } + ] +} diff --git a/crates/event_codec/tests/knowledge_fixtures.rs b/crates/event_codec/tests/knowledge_fixtures.rs @@ -27,6 +27,8 @@ use radroots_event_codec::verification::{ RadrootsDecodeError, RadrootsDecodedEvent, RadrootsNip01VerificationError, verify_and_decode_radroots_event, }; +#[cfg(feature = "manifests")] +use radroots_event_codec::{contract_manifest_json, knowledge_contract_manifest}; use radroots_test_fixtures::RELAY_PRIMARY_WSS; use radroots_test_fixtures::knowledge::{ RADROOTS_KNOWLEDGE_ADVERSARIAL_FIXTURES, RADROOTS_KNOWLEDGE_VALID_CONTRACT_IDS, @@ -560,3 +562,120 @@ fn verified_decode_exposes_representative_public_surface_events() { } } } + +#[cfg(feature = "manifests")] +#[test] +fn checked_in_manifest_and_decode_vectors_execute_every_declared_case() { + const PACKAGED_VECTORS: &str = include_str!("fixtures/knowledge_manifest_and_decode.v1.json"); + let workspace_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) + .join("../../contracts/conformance/vectors/knowledge/manifest_and_decode.v1.json"); + if let Ok(workspace_vectors) = std::fs::read_to_string(workspace_path) { + assert_eq!(PACKAGED_VECTORS, workspace_vectors); + } + + let suite: serde_json::Value = serde_json::from_str(PACKAGED_VECTORS).expect("vector suite"); + assert_eq!(suite["suite"], "knowledge_manifest_and_decode"); + assert_eq!(suite["contract_version"], "1.0.0"); + let vectors = suite["vectors"].as_array().expect("vectors"); + assert_eq!(vectors.len(), 7); + + let fixtures = knowledge_valid_fixtures(); + for vector in vectors { + let id = vector["id"].as_str().expect("vector id"); + let kind = vector["kind"].as_str().expect("vector kind"); + let expected = vector["expected"].as_object().expect("expected object"); + match kind { + "knowledge.contract_manifest_json.valid" => { + let manifest_json = contract_manifest_json().expect("manifest JSON"); + let manifest: serde_json::Value = + serde_json::from_str(manifest_json.as_str()).expect("manifest value"); + assert_eq!( + manifest["schema_version"], expected["schema_version"], + "{id}" + ); + assert_eq!( + manifest["registry_version"], expected["registry_version"], + "{id}" + ); + let contracts = manifest["contracts"].as_array().expect("contracts"); + assert_eq!( + contracts.len(), + knowledge_contract_manifest().contracts.len(), + "{id}" + ); + for field in expected["required_fields"] + .as_array() + .expect("required fields") + { + let field = field.as_str().expect("field name"); + assert!( + manifest.get(field).is_some() + || contracts + .iter() + .all(|contract| contract.get(field).is_some()), + "{id}: missing required manifest field {field}" + ); + } + } + "knowledge.verify_and_decode_event.valid" => { + let fixture_id = vector["input"]["fixture"].as_str().expect("fixture id"); + let signed = sign_parts(parts_for_fixture( + &fixture_by_id(&fixtures, fixture_id).data, + )); + let decoded = verify_and_decode_radroots_event(signed).expect("decoded event"); + assert!( + matches!(decoded, RadrootsDecodedEvent::KnowledgeClaim(_)), + "{id}" + ); + assert_eq!(expected["decoded_variant"], "KnowledgeClaim", "{id}"); + assert_eq!( + expected["contract_id"], RADROOTS_KNOWLEDGE_CLAIM_SCHEMA, + "{id}" + ); + } + "knowledge.verify_and_decode_event.invalid" => { + let mut parts = knowledge_claim_to_wire_parts(&knowledge_claim()).expect("parts"); + parts + .tags + .retain(|tag| tag.first().map(String::as_str) != Some("contract")); + let error = verify_and_decode_radroots_event(sign_parts(parts)) + .expect_err("missing contract must fail"); + assert!( + matches!(error, RadrootsDecodeError::ContractValidation(_)), + "{id}" + ); + assert_eq!(expected["error_class"], "decode_error", "{id}"); + assert_eq!(expected["stage"], error.code(), "{id}"); + } + "knowledge.nip54.wiki_article_tags.valid" + | "knowledge.nip54.wiki_redirect_tags.valid" + | "knowledge.nip54.wiki_merge_request.valid" => { + let fixture_id = vector["input"]["fixture"].as_str().expect("fixture id"); + let parts = parts_for_fixture(&fixture_by_id(&fixtures, fixture_id).data); + if let Some(content) = expected.get("content") { + assert_eq!(content, parts.content.as_str(), "{id}"); + } + for (field, value) in expected { + if field.ends_with("_tag") { + let expected_tag = value + .as_array() + .expect("expected tag") + .iter() + .map(|value| value.as_str().expect("tag value").to_owned()) + .collect::<Vec<_>>(); + assert!(parts.tags.contains(&expected_tag), "{id}: missing {field}"); + } + } + if expected.get("base_version_event_id") == Some(&serde_json::Value::Null) { + assert!( + !parts.tags.iter().any(|tag| { + tag == &vec!["e".to_owned(), hex_64('e'), String::new()] + }), + "{id}: unexpected base event tag" + ); + } + } + kind => panic!("{id}: unsupported vector kind {kind}"), + } + } +} diff --git a/crates/event_codec/tests/package_boundary.rs b/crates/event_codec/tests/package_boundary.rs @@ -45,13 +45,53 @@ fn crate_root_declares_every_approved_module() { } #[test] +fn canonical_root_exports_are_explicit_and_host_types_do_not_leak() { + for export in [ + "pub use codec::Codec;", + "pub use decode::DecodeError;", + "pub use encode::EncodeError;", + "pub use verify::VerificationError;", + ] { + assert!( + ROOT.contains(export), + "missing canonical root export {export}" + ); + } + + assert!(ROOT.contains("#![cfg_attr(not(feature = \"std\"), no_std)]")); + assert!(!ROOT.contains("pub trait ")); + for forbidden in [ + "nostr::", + "nostr_sdk::", + "reqwest::", + "sqlx::", + "tokio::", + "std::os::", + ] { + assert!( + !ROOT.contains(forbidden), + "crate root must not expose host path {forbidden}" + ); + } +} + +#[test] fn codec_runtime_is_protocol_neutral_and_host_free() { let features = table_keys(MANIFEST, "[features]"); let dependencies = table_keys(MANIFEST, "[dependencies]"); assert!(!features.contains("nostr")); assert!(dependencies.contains("secp256k1")); - for forbidden in ["nostr", "nostr-sdk", "reqwest", "sqlx", "tokio"] { + for forbidden in [ + "keyring", + "nostr", + "nostr-sdk", + "reqwest", + "sqlx", + "tokio", + "wasm-bindgen", + "web-sys", + ] { assert!( !dependencies.contains(forbidden), "codec runtime must not depend on {forbidden}"