Skip to content

Commit a85217d

Browse files
issammanibendk
authored andcommitted
fix: handle out of range timestamps
1 parent 6367571 commit a85217d

File tree

1 file changed

+45
-6
lines changed
  • components/context_id/src

1 file changed

+45
-6
lines changed

components/context_id/src/lib.rs

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,13 @@ impl ContextIDComponentInner {
113113
match (generated_context_id, creation_timestamp_s) {
114114
// We generated a new context ID then we need a fresh timestamp and no rotation needed
115115
(true, _) => (now, true, false),
116-
// Pre-existing context ID with valid timestamp then use timestamp and no rotation needed
117-
(false, secs) if secs > 0 => (
118-
DateTime::<Utc>::from_timestamp(secs, 0).unwrap_or(now),
119-
false,
120-
false,
121-
),
116+
// Pre-existing context ID with a positive timestamp:
117+
// try parsing it (any real UNIX-epoch timestamp is orders of magnitude within chrono’s 262 000-year range),
118+
// and if it’s somehow out-of-range fall back to `now` and force rotation
119+
// See: https://docs.rs/chrono/latest/chrono/naive/struct.NaiveDateTime.html#panics
120+
(false, secs) if secs > 0 => DateTime::<Utc>::from_timestamp(secs, 0)
121+
.map(|ts| (ts, false, false))
122+
.unwrap_or((now, true, true)),
122123
// Pre-existing context ID with zero timestamp then use current time and no rotation needed
123124
(false, 0) => (now, true, false),
124125
// Pre-existing context ID but INVALID timestamp then use current time but FORCE rotation
@@ -453,6 +454,44 @@ mod tests {
453454
});
454455
}
455456

457+
#[test]
458+
fn test_context_id_with_out_of_range_creation_date() {
459+
with_test_mars(|mars, delete_called| {
460+
let spy = SpyCallback::new();
461+
// Way beyond chrono’s 262.000 syear range
462+
let huge_secs = i64::MAX;
463+
let component = ContextIDComponentInner::new(
464+
TEST_CONTEXT_ID,
465+
huge_secs,
466+
false,
467+
spy.callback,
468+
*FAKE_NOW,
469+
mars,
470+
);
471+
472+
// A new UUID should have been generated.
473+
assert!(Uuid::parse_str(&component.context_id).is_ok());
474+
assert_ne!(component.context_id, TEST_CONTEXT_ID);
475+
476+
// The creation timestamp must have been set to now.
477+
assert_eq!(component.creation_timestamp, FAKE_NOW.clone());
478+
479+
// Also expect a persist to have been called and a rotation.
480+
assert_eq!(
481+
*spy.persist_called.lock().unwrap(),
482+
1,
483+
"persist() should have been called once"
484+
);
485+
assert_eq!(
486+
*spy.rotated_called.lock().unwrap(),
487+
1,
488+
"rotated() should have been called once"
489+
);
490+
// Since we forced a rotation on out-of-range, the MARS delete should have been called.
491+
assert!(*delete_called.lock().unwrap());
492+
});
493+
}
494+
456495
#[test]
457496
fn test_request_no_rotation() {
458497
with_test_mars(|mars, delete_called| {

0 commit comments

Comments
 (0)