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
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.
106 lines
4 KiB
Rust
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());
|
|
}
|
|
}
|