Proof of concept mechanical port of ircnet/ircd to Rust as part of a bit about C being insecure for network services
1//! Boot-level golden for **MONITOR live S2S propagation** (P11 slice 124), end-to-end through the
2//! real `leveva` binary.
3//!
4//! `MONITOR` is purely client-local in IRCnet (the C oracle has no `WATCH`/`MONITOR`), so this is
5//! leveva-native — there is no oracle differential. The fix hooks the existing remote
6//! online/offline/rename S2S seams to push `730 RPL_MONONLINE` / `731 RPL_MONOFFLINE` to a local
7//! watcher of a **remote** nick.
8//!
9//! Builds on `golden_s2s_away` (handshake + burst). A local `alice` monitors two nicks that don't
10//! exist yet (`rover`, `landrover` → an initial `731`). Then a peer links and drives `rover`
11//! through every transition:
12//!
13//! - **online** — the peer bursts `rover` (`UNICK`) → alice is pushed `730` with rover's hostmask;
14//! - **rename** — the peer renames `rover`→`landrover` (`NICK`) → alice is pushed `731 rover`
15//! (gone) then `730 landrover` (online);
16//! - **offline** — the peer quits `landrover` (`QUIT`) → alice is pushed `731 landrover`.
17//!
18//! Determinism mirrors `golden_s2s_away` (pinned identity `leveva.test`/`0ABC`, peer `1ZZZ`,
19//! rover `1ZZZAAAAA`, fixed host `rover.host`); nothing volatile rides these lines, so
20//! [`canonicalize`] suffices.
21
22mod harness;
23use harness::{boot_fixture, canonicalize, Client, Peer};
24
25/// The S2S `server-only` listener port (matches `s2s.kdl`).
26const S2S_PORT: u16 = 16701;
27
28/// Keep only the `730`/`731` MONITOR notify lines from a transcript (canonicalized), labelled.
29fn keep_into(transcript: &mut String, label: &str, src: &str) {
30 for line in canonicalize(src).lines() {
31 if line.contains(" 730 ") || line.contains(" 731 ") {
32 transcript.push_str(label);
33 transcript.push_str(line);
34 transcript.push('\n');
35 }
36 }
37}
38
39#[test]
40fn s2s_monitor_pushes_730_731_on_remote_transitions() {
41 let _srv = boot_fixture("s2s.kdl", harness::PORT);
42
43 // alice registers, then monitors two not-yet-existing nicks → an initial 731 (both offline).
44 let mut alice = Client::connect();
45 alice.send("NICK alice");
46 alice.send("USER alice 0 * :Alice Tester");
47 alice.read_until(" 422 ");
48 alice.send("MONITOR + rover,landrover");
49 let initial = alice.read_until(" 731 ");
50
51 // The peer links and absorbs our handshake + burst + EOB.
52 let mut peer = Peer::connect(S2S_PORT);
53 peer.send("PASS linkpw 2.11 IRC|");
54 peer.send("SERVER peer.test 1 1ZZZ :A Peer Server");
55 peer.read_until(":0ABC EOB");
56
57 // --- online: the peer bursts rover → alice gets a 730 with rover's hostmask. ---
58 peer.send(":1ZZZ UNICK rover 1ZZZAAAAA ro rover.host 198.51.100.7 +i :Rover Remote");
59 peer.send(":1ZZZ EOB");
60 peer.read_until("EOBACK");
61 let online = alice.read_until(" 730 ");
62
63 // --- rename: rover → landrover → alice gets a 731 (old) and a 730 (new). ---
64 peer.send(":1ZZZAAAAA NICK landrover");
65 let rename_off = alice.read_until(" 731 alice :rover");
66 let rename_on = alice.read_until(" 730 alice :landrover");
67
68 // --- offline: the peer quits landrover → alice gets a 731. ---
69 peer.send(":1ZZZAAAAA QUIT :gone");
70 let offline = alice.read_until(" 731 alice :landrover");
71
72 let mut transcript = String::new();
73 keep_into(&mut transcript, "INIT: ", &initial);
74 keep_into(&mut transcript, "ONLINE: ", &online);
75 keep_into(&mut transcript, "RENAME: ", &rename_off);
76 keep_into(&mut transcript, "RENAME: ", &rename_on);
77 keep_into(&mut transcript, "OFFLINE:", &offline);
78
79 insta::assert_snapshot!(transcript);
80}