nigig-org/crates/apps/nigig-site/tests/support/nimanyatta_fixture.rs
Arena Agent 5d2d890f70
Some checks failed
nigig-site / Owned paths and honest test contracts (push) Has been cancelled
nigig-site / Cargo check-all-targets (push) Has been cancelled
nigig-site / Cargo clippy-site-owned (push) Has been cancelled
nigig-site / Cargo contained-media-export-fixtures (push) Has been cancelled
nigig-site / Cargo containment-storage-crypto (push) Has been cancelled
nigig-site / Cargo integration-non-live (push) Has been cancelled
nigig-site / Cargo production-dependency-containment (push) Has been cancelled
nigig-site / Cargo unit (push) Has been cancelled
nigig-site / Runtime UI (explicitly skipped until enabled) (push) Has been cancelled
nigig-site / Migration and recovery (explicitly skipped until enabled) (push) Has been cancelled
nigig-site / Media limits (explicitly skipped until enabled) (push) Has been cancelled
nigig-site / Real server interoperability (explicitly skipped until enabled) (push) Has been cancelled
nigig-site / Security and supply-chain baseline (push) Has been cancelled
nigig-site / Release capability gate (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
doc-engine / engine (push) Has been cancelled
doc-engine / coverage (push) Has been cancelled
doc-engine / consumer (push) Has been cancelled
email / gates (push) Has been cancelled
email / email-domain (push) Has been cancelled
email / nigig-email (push) Has been cancelled
email / supply-chain (push) Has been cancelled
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
nigig-build (CAD) / cad-widget-coverage (push) Has been cancelled
nigig-map / test (push) Has been cancelled
sms / gates (push) Has been cancelled
sms / robius-sms (push) Has been cancelled
sms / android (push) Has been cancelled
sms / nigig-sms (push) Has been cancelled
sms / supply-chain (push) Has been cancelled
spreadsheet / engine-coverage (push) Has been cancelled
spreadsheet / ui-controller-coverage (push) Has been cancelled
traffic / gates (push) Has been cancelled
traffic / nigig-traffic (push) Has been cancelled
traffic / supply-chain (push) Has been cancelled
feat(nigig-site): enforce SITE-01 fail-closed containment
Contain production capabilities, remove the production sync surface, and keep legacy media/export/transport implementations test-only.

Require authenticated existing-key storage with preservation-first recovery and sticky write disablement, backed by deterministic fault and concurrency tests plus dependency and workflow contracts.
2026-09-12 15:46:30 +00:00

106 lines
4 KiB
Rust

//! Defensive, pure parsers retained for the explicit test-only server contract.
//!
//! SITE-01 contains production project transport by omission: this module has
//! no URL configuration, credentials, request constructors, HTTP dispatch,
//! response callback, or store mutation. Secure authenticated transport must
//! be introduced from scratch under SITE-12 gates.
/// One text line out of a timeline event, or `None` for non-message events.
/// Shapes handled: `content.Text.body`, `content.body`, and bare `body`.
/// Anything else is skipped rather than guessed.
pub fn event_text(event: &serde_json::Value) -> Option<(String, String)> {
if event.get("type").and_then(|value| value.as_str()) != Some("message") {
return None;
}
let body = event
.get("content")
.and_then(|content| {
content
.get("Text")
.and_then(|text| text.get("body"))
.or_else(|| content.get("body"))
})
.or_else(|| event.get("body"))
.and_then(|body| body.as_str())?;
let sender = event
.get("sender")
.and_then(|sender| sender.as_str())
.unwrap_or("?")
.to_string();
Some((sender, body.to_string()))
}
/// Extract timeline bodies defensively for the ignored interoperability test.
pub fn timeline_bodies(payload: &str) -> Vec<String> {
let Ok(value) = serde_json::from_str::<serde_json::Value>(payload) else {
return Vec::new();
};
let Some(events) = value.get("events").and_then(|events| events.as_array()) else {
return Vec::new();
};
events
.iter()
.filter_map(|event| event_text(event).map(|(_, body)| body))
.collect()
}
/// Parse a test-server `/sync` fixture into per-room message lines.
/// Unknown or malformed shapes return an empty collection and never panic.
pub fn sync_timelines(payload: &str) -> Vec<(String, Vec<String>)> {
let Ok(value) = serde_json::from_str::<serde_json::Value>(payload) else {
return Vec::new();
};
let Some(rooms) = value.get("joined_rooms").and_then(|rooms| rooms.as_array()) else {
return Vec::new();
};
rooms
.iter()
.filter_map(|room| {
let room_id = room.get("room_id").and_then(|id| id.as_str())?;
let timeline = room
.get("timeline")
.and_then(|timeline| timeline.as_array())?;
let lines: Vec<String> = timeline
.iter()
.filter_map(|event| {
event_text(event).map(|(sender, body)| format!("{sender}: {body}"))
})
.collect();
(!lines.is_empty()).then(|| (room_id.to_string(), lines))
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn timeline_parsers_ignore_malformed_and_non_message_content() {
let payload = serde_json::json!({
"joined_rooms": [
{
"room_id": "room_abc123",
"timeline": [
{"type": "message", "sender": "alice", "content": {"Text": {"body": "slab done", "formatted_body": null, "mentions": []}}},
{"type": "membership", "sender": "alice"},
{"type": "message", "sender": "bob", "content": {"body": "noted"}},
{"type": "message", "sender": "x", "content": {"Image": {"body": "pic"}}}
]
},
{"room_id": "room_empty", "timeline": []}
]
})
.to_string();
let timelines = sync_timelines(&payload);
assert_eq!(timelines.len(), 1);
assert_eq!(timelines[0].0, "room_abc123");
assert_eq!(
timelines[0].1,
vec!["alice: slab done".to_string(), "bob: noted".to_string()]
);
assert!(sync_timelines("{}").is_empty());
assert!(sync_timelines("garbage").is_empty());
assert!(timeline_bodies("garbage").is_empty());
}
}