From fd944072b6ada8585ae0d1adcbc0767448bef412 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Fri, 16 Oct 2026 04:33:27 +0200 Subject: [PATCH] cultnet-rs: three more refusals stop quoting received values; the networking descriptor's repeated key is pinned Co-Authored-By: Claude Opus 5.5 --- packages/cultnet-rs/src/contracts.rs | 6 ++--- packages/cultnet-rs/tests/decode_door.rs | 29 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/packages/cultnet-rs/src/contracts.rs b/packages/cultnet-rs/src/contracts.rs index 0a8f657a..bb1b1e57 100644 --- a/packages/cultnet-rs/src/contracts.rs +++ b/packages/cultnet-rs/src/contracts.rs @@ -1030,7 +1030,7 @@ fn parse_raw_cultnet_schema_message(input: &rmpv::Value) -> Result Err(anyhow!( - "Unsupported raw cultnet.schema.v0 schemaVersion {schema_version}" + "Unsupported raw cultnet.schema.v0 message" )), } } @@ -1489,7 +1489,7 @@ fn parse_gamecult_networking_message(input: &rmpv::Value) -> Result Err(anyhow!( - "Unsupported gamecult.networking.v0 union tag {tag}" + "Unsupported gamecult.networking.v0 union tag" )), } } @@ -1721,7 +1721,7 @@ fn require_legacy_schema_descriptor( "shared_contract" => CultNetSchemaKind::SharedContract, _ => { return Err(anyhow!( - "{field_name}.Kind has unsupported schema kind {kind}" + "{field_name}.Kind is not a supported schema kind" )); } }; diff --git a/packages/cultnet-rs/tests/decode_door.rs b/packages/cultnet-rs/tests/decode_door.rs index c421c040..03330beb 100644 --- a/packages/cultnet-rs/tests/decode_door.rs +++ b/packages/cultnet-rs/tests/decode_door.rs @@ -645,3 +645,32 @@ fn receive_errors_name_schema_never_values() { // A message with no schemaVersion at all says so. assert!(refusal(pairs(&[("messageId", "m".into())])).contains("no schemaVersion")); } + +#[test] +fn a_networking_schema_descriptor_with_a_repeated_key_is_refused_and_a_bad_kind_is_not_quoted() { + let canary = "CANARY-8c2d"; + let descriptor = |extra: &[(&str, rmpv::Value)]| { + let mut entries = pairs(&[("schemaId", "s".into()), ("kind", "wire_message".into()), ("contentHash", "h".into())]); + entries.extend(pairs(extra)); + rmpv::Value::Map(entries) + }; + let response = |descriptor: rmpv::Value| { + let union = rmpv::Value::Array(vec![ + 8.into(), + rmpv::Value::Array(vec!["m".into(), rmpv::Value::Array(vec![descriptor])]), + ]); + rmp_serde::to_vec(&union).unwrap() + }; + let decode = |bytes: Vec| { + on_stack(BIG, move || { + decode_cultnet_message_from_slice(&bytes, CultNetWireContract::GameCultNetworkingV0) + .map_err(|error| format!("{error:#}")) + }) + }; + decode(response(descriptor(&[]))).expect("the control decodes"); + let text = decode(response(descriptor(&[("schemaId", "t".into())]))).unwrap_err(); + assert!(text.contains("twice"), "{text}"); + let bad_kind = rmpv::Value::Map(pairs(&[("schemaId", "s".into()), ("kind", canary.into()), ("contentHash", "h".into())])); + let text = decode(response(bad_kind)).unwrap_err(); + assert!(text.contains("Kind") && !text.contains("CANARY"), "{text}"); +}