Skip to content

Commit 55ce10f

Browse files
committed
refactor: rename v2 canonical JSON fields to name/type/content
Change the hashed v2 canonical JSON from {"event":"...","event_type":134217729,"payload":"hex..."} to {"name":"...","type":134217729,"content":"hex..."} Generic names match the wire-level intent better for third-party consumers ("event_type"/"payload" are dstack-schema terms; generic content descriptors are easier to align with policy languages like ITA's CEL expressions). Note: JCS key ordering changes — content < name < type — so the on-wire byte sequence (and therefore v2 digests) are different. This is a breaking change to the v2 digest format; safe because v2 is not yet released.
1 parent 90765a3 commit 55ce10f

3 files changed

Lines changed: 22 additions & 25 deletions

File tree

cc-eventlog/src/runtime_events.rs

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ impl RuntimeEvent {
113113
/// Compute the digest of the event.
114114
///
115115
/// - V1: `SHA(event_type_le || ":" || event_name || ":" || payload)`
116-
/// - V2: `SHA(canonical_json({"event":"...","event_type":134217729,"payload":"hex..."}))`
116+
/// - V2: `SHA(canonical_json({"name":"...","type":134217729,"content":"hex..."}))`
117117
pub fn digest<H: Hasher>(&self) -> H::Output {
118118
H::hash([self.hash_input().as_slice()])
119119
}
@@ -154,9 +154,9 @@ impl RuntimeEvent {
154154
/// hashed content.
155155
pub fn canonical_event_json_v2(event: &str, payload: &[u8]) -> String {
156156
let obj = serde_json::json!({
157-
"event": event,
158-
"event_type": DSTACK_RUNTIME_EVENT_TYPE,
159-
"payload": hex::encode(payload),
157+
"name": event,
158+
"type": DSTACK_RUNTIME_EVENT_TYPE,
159+
"content": hex::encode(payload),
160160
});
161161
serde_jcs::to_string(&obj).or_panic("canonical JSON serialization failed")
162162
}
@@ -207,7 +207,7 @@ mod tests {
207207
let canonical = canonical_event_json_v2(&event.event, &event.payload);
208208
assert_eq!(
209209
canonical,
210-
r#"{"event":"compose-hash","event_type":134217729,"payload":"abcd"}"#
210+
r#"{"content":"abcd","name":"compose-hash","type":134217729}"#
211211
);
212212
let digest = event.digest::<Sha384>();
213213
let expected = Sha384::hash([canonical.as_bytes()]);
@@ -268,7 +268,7 @@ mod tests {
268268
// Exact bytewise output — JCS must be deterministic
269269
assert_eq!(
270270
canonical,
271-
r#"{"event":"event\"with\\special\nchars","event_type":134217729,"payload":"ff"}"#
271+
r#"{"content":"ff","name":"event\"with\\special\nchars","type":134217729}"#
272272
);
273273
}
274274

@@ -277,20 +277,17 @@ mod tests {
277277
// JCS RFC 8785 requires keys sorted by UTF-16 code unit order.
278278
// For ASCII keys, this is alphabetical.
279279
let canonical = canonical_event_json_v2("test", &[0x01]);
280-
let event_pos = canonical.find(r#""event":"#).unwrap();
281-
let event_type_pos = canonical.find(r#""event_type":"#).unwrap();
282-
let payload_pos = canonical.find(r#""payload":"#).unwrap();
283-
assert!(event_pos < event_type_pos);
284-
assert!(event_type_pos < payload_pos);
280+
let content_pos = canonical.find(r#""content":"#).unwrap();
281+
let name_pos = canonical.find(r#""name":"#).unwrap();
282+
let type_pos = canonical.find(r#""type":"#).unwrap();
283+
assert!(content_pos < name_pos);
284+
assert!(name_pos < type_pos);
285285
}
286286

287287
#[test]
288288
fn canonical_json_empty_event_and_payload() {
289289
let canonical = canonical_event_json_v2("", &[]);
290-
assert_eq!(
291-
canonical,
292-
r#"{"event":"","event_type":134217729,"payload":""}"#
293-
);
290+
assert_eq!(canonical, r#"{"content":"","name":"","type":134217729}"#);
294291
}
295292

296293
#[test]
@@ -315,25 +312,25 @@ mod tests {
315312
assert!(canonical.contains("测试-emoji-🦀"), "got: {canonical}");
316313
// Must still be parseable and roundtrip
317314
let parsed: serde_json::Value = serde_json::from_str(&canonical).unwrap();
318-
assert_eq!(parsed["event"].as_str().unwrap(), "测试-emoji-🦀");
315+
assert_eq!(parsed["name"].as_str().unwrap(), "测试-emoji-🦀");
319316
}
320317

321318
#[test]
322319
fn canonical_json_control_character_escaping() {
323320
// JCS (via RFC 8259) uses short escapes for \b \f \n \r \t and \uXXXX for other controls.
324321
let canonical = canonical_event_json_v2("\x08\x0c\n\r\t\x01", &[]);
325322
assert!(
326-
canonical.contains(r#""event":"\b\f\n\r\t\u0001""#),
323+
canonical.contains(r#""name":"\b\f\n\r\t\u0001""#),
327324
"got: {canonical}"
328325
);
329326
}
330327

331328
#[test]
332-
fn canonical_json_payload_lowercase_hex() {
333-
// Payload must be hex-encoded lowercase for determinism.
329+
fn canonical_json_content_lowercase_hex() {
330+
// Content payload must be hex-encoded lowercase for determinism.
334331
let canonical = canonical_event_json_v2("test", &[0xAB, 0xCD, 0xEF]);
335332
assert!(
336-
canonical.contains(r#""payload":"abcdef""#),
333+
canonical.contains(r#""content":"abcdef""#),
337334
"got: {canonical}"
338335
);
339336
}

cc-eventlog/src/tdx.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::{
1919
///
2020
/// For dstack runtime events (`event_type == DSTACK_RUNTIME_EVENT_TYPE`), the digest is:
2121
/// - V1: `sha384(event_type_le || ":" || event || ":" || payload)`
22-
/// - V2: `sha384(canonical_json({"event":"...","event_type":134217729,"payload":"hex..."}))`
22+
/// - V2: `sha384(canonical_json({"name":"...","type":134217729,"content":"hex..."}))`
2323
#[derive(Clone, Debug, Serialize, Deserialize, Encode, Decode)]
2424
pub struct TdxEvent {
2525
/// IMR index, starts from 0
@@ -184,9 +184,9 @@ mod tests {
184184
let input = hex::decode(input_hex).unwrap();
185185
let input_str = std::str::from_utf8(&input).unwrap();
186186
// V2 hash_input is the canonical JSON (version is carried out-of-band)
187-
assert!(input_str.contains(r#""event":"compose-hash""#));
188-
assert!(input_str.contains(r#""event_type":134217729"#));
189-
assert!(input_str.contains(r#""payload":"abcd""#));
187+
assert!(input_str.contains(r#""name":"compose-hash""#));
188+
assert!(input_str.contains(r#""type":134217729"#));
189+
assert!(input_str.contains(r#""content":"abcd""#));
190190
assert!(!input_str.contains(r#""version""#));
191191
// And hashing it reproduces the digest
192192
let actual = Sha384::hash([input.as_slice()]);

dstack-types/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub enum EventLogVersion {
1919
#[default]
2020
V1,
2121
/// JSON canonical digest (JCS RFC 8785):
22-
/// `SHA({"event":"...","event_type":134217729,"payload":"hex..."})`
22+
/// `SHA({"name":"...","type":134217729,"content":"hex..."})`
2323
V2,
2424
}
2525

0 commit comments

Comments
 (0)