Skip to content

Commit 4cf928c

Browse files
committed
fix: address CI failures and PR review comments
- Replace expect() with manual JSON escaping to satisfy clippy::expect_used - Add #[codec(skip)] on RuntimeEvent.version to preserve scale binary compat with existing attestation fixtures - Pass EventLogVersion from caller in Attestation::quote_with_app_id - Read event_log_version from app-compose.json in extend-rtmr CLI instead of hardcoded default - from_u32 now returns Option, rejecting unknown version values
1 parent 32241ad commit 4cf928c

5 files changed

Lines changed: 45 additions & 17 deletions

File tree

cc-eventlog/src/runtime_events.rs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ pub struct RuntimeEvent {
3333
pub payload: Vec<u8>,
3434
/// Event log version
3535
#[serde(default, skip_serializing)]
36+
#[codec(skip)]
3637
pub version: EventLogVersion,
3738
}
3839

@@ -145,13 +146,29 @@ impl RuntimeEvent {
145146
/// Output: `{"event":"<name>","event_type":<type>,"payload":"<hex>"}`
146147
pub fn canonical_event_json(event: &str, event_type: u32, payload: &[u8]) -> String {
147148
// Per JCS, strings must use minimal JSON escaping.
148-
// We use serde_json to correctly escape the event name.
149-
let escaped_event = serde_json::to_string(event).expect("failed to serialize event name");
149+
let escaped_event = json_escape_string(event);
150150
let hex_payload = hex::encode(payload);
151-
format!(
152-
r#"{{"event":{},"event_type":{},"payload":"{}"}}"#,
153-
escaped_event, event_type, hex_payload
154-
)
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
155172
}
156173

157174
/// Replay event logs

dstack-attest/src/attestation.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,10 +1023,14 @@ impl Attestation {
10231023

10241024
/// Create an attestation from a report data
10251025
pub fn quote(report_data: &[u8; 64]) -> Result<Self> {
1026-
Self::quote_with_app_id(report_data, None)
1026+
Self::quote_with_app_id(report_data, None, EventLogVersion::default())
10271027
}
10281028

1029-
pub fn quote_with_app_id(report_data: &[u8; 64], app_id: Option<[u8; 20]>) -> Result<Self> {
1029+
pub fn quote_with_app_id(
1030+
report_data: &[u8; 64],
1031+
app_id: Option<[u8; 20]>,
1032+
event_log_version: EventLogVersion,
1033+
) -> Result<Self> {
10301034
// Lock to prevent concurrent quote generation (TDX driver doesn't support it)
10311035
let _guard = QUOTE_LOCK
10321036
.lock()
@@ -1039,7 +1043,7 @@ impl Attestation {
10391043
vec![RuntimeEvent::new(
10401044
"app-id".to_string(),
10411045
app_id.to_vec(),
1042-
EventLogVersion::V1,
1046+
event_log_version,
10431047
)]
10441048
} else {
10451049
vec![]

dstack-types/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use size_parser::human_size;
1313
///
1414
/// Using an enum ensures exhaustive matching — adding a new version
1515
/// forces all match sites to be updated.
16-
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Encode, Decode)]
16+
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
1717
pub enum EventLogVersion {
1818
/// Legacy binary digest: `SHA(event_type_le || ":" || name || ":" || payload)`
1919
#[default]

dstack-util/src/main.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,6 @@ struct ExtendArgs {
9090
#[clap(short, long)]
9191
/// hex encoded payload of the event
9292
payload: String,
93-
94-
#[clap(long, default_value_t = 1)]
95-
/// event log version (1 = legacy, 2 = JSON canonical)
96-
event_log_version: u32,
9793
}
9894

9995
#[derive(Parser)]
@@ -228,11 +224,22 @@ fn hex_decode(hex_str: &str) -> Result<Vec<u8>> {
228224

229225
fn cmd_extend(extend_args: ExtendArgs) -> Result<()> {
230226
let payload = hex_decode(&extend_args.payload).context("Failed to decode payload")?;
231-
let version = dstack_types::EventLogVersion::from_u32(extend_args.event_log_version)
232-
.context("unsupported event log version")?;
227+
let version = read_event_log_version();
233228
emit_runtime_event(&extend_args.event, &payload, version).context("Failed to extend RTMR")
234229
}
235230

231+
fn read_event_log_version() -> dstack_types::EventLogVersion {
232+
let path = std::path::Path::new(dstack_types::shared_filenames::HOST_SHARED_DIR)
233+
.join(dstack_types::shared_filenames::APP_COMPOSE);
234+
let Ok(data) = std::fs::read_to_string(&path) else {
235+
return Default::default();
236+
};
237+
let Ok(compose) = serde_json::from_str::<dstack_types::AppCompose>(&data) else {
238+
return Default::default();
239+
};
240+
compose.event_log_version
241+
}
242+
236243
fn cmd_rand(rand_args: RandArgs) -> Result<()> {
237244
let mut data = vec![0u8; rand_args.bytes];
238245
getrandom(&mut data).context("Failed to generate random data")?;

ra-tls/src/cert.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,7 @@ pub fn generate_ra_cert_with_app_id(
542542

543543
let report_data = QuoteContentType::RaTlsCert.to_report_data(&pubkey);
544544

545-
let attestation = Attestation::quote_with_app_id(&report_data, app_id)
545+
let attestation = Attestation::quote_with_app_id(&report_data, app_id, Default::default())
546546
.context("Failed to get quote for cert pubkey")?
547547
.into_versioned();
548548

0 commit comments

Comments
 (0)