Skip to content

Commit 2b31c5d

Browse files
committed
refactor: use BTreeMap for canonical JSON key ordering
Replace manual format string with BTreeMap serialization to guarantee alphabetical key ordering per JCS RFC 8785. This prevents bugs if fields are added in the future — BTreeMap handles ordering automatically.
1 parent f553c11 commit 2b31c5d

2 files changed

Lines changed: 8 additions & 27 deletions

File tree

.claude/worktrees/pr361-pp-fix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit d5a137ca384d3c117b969466c082a95e971a9123

cc-eventlog/src/runtime_events.rs

Lines changed: 7 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -140,35 +140,15 @@ impl RuntimeEvent {
140140

141141
/// Construct JCS (RFC 8785) canonical JSON for a runtime event.
142142
///
143-
/// Keys are sorted alphabetically: `event`, `event_type`, `payload`.
143+
/// Uses `BTreeMap` to guarantee alphabetical key ordering per JCS.
144144
/// The payload is hex-encoded for human readability.
145-
///
146-
/// Output: `{"event":"<name>","event_type":<type>,"payload":"<hex>"}`
147145
pub fn canonical_event_json(event: &str, event_type: u32, payload: &[u8]) -> String {
148-
// Per JCS, strings must use minimal JSON escaping.
149-
let escaped_event = json_escape_string(event);
150-
let hex_payload = hex::encode(payload);
151-
format!(r#"{{"event":"{escaped_event}","event_type":{event_type},"payload":"{hex_payload}"}}"#,)
152-
}
153-
154-
/// Minimal JSON string escaping per RFC 8259.
155-
fn json_escape_string(s: &str) -> String {
156-
let mut out = String::with_capacity(s.len());
157-
for ch in s.chars() {
158-
match ch {
159-
'"' => out.push_str("\\\""),
160-
'\\' => out.push_str("\\\\"),
161-
'\n' => out.push_str("\\n"),
162-
'\r' => out.push_str("\\r"),
163-
'\t' => out.push_str("\\t"),
164-
c if c < '\x20' => {
165-
use std::fmt::Write;
166-
let _ = write!(out, "\\u{:04x}", c as u32);
167-
}
168-
c => out.push(c),
169-
}
170-
}
171-
out
146+
use std::collections::BTreeMap;
147+
let mut map = BTreeMap::new();
148+
map.insert("event", serde_json::Value::String(event.to_string()));
149+
map.insert("event_type", serde_json::Value::Number(event_type.into()));
150+
map.insert("payload", serde_json::Value::String(hex::encode(payload)));
151+
serde_json::to_string(&map).unwrap_or_default()
172152
}
173153

174154
/// Replay event logs

0 commit comments

Comments
 (0)