Frame arithmetic is daemon-gated with its only consumers; boundary tests are finite

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-10-28 05:40:05 +01:00
commit bf07b2cd38
2 changed files with 15 additions and 9 deletions

View file

@ -29,6 +29,7 @@ pub struct TransportEnvelope {
/// The longest caller id, request id or model name a service admits. The
/// frame arithmetic below depends on it, so a longer one is refused up front.
#[cfg(feature = "daemon")]
pub(crate) const MAX_IDENTITY_BYTES: usize = 256;
/// The most bytes a serialized envelope holding `ciphertext_len` ciphertext
@ -36,6 +37,7 @@ pub(crate) const MAX_IDENTITY_BYTES: usize = 256;
/// array of integers: a byte of 128 or more takes two bytes, so the worst case
/// is twice the ciphertext, plus the array header and the envelope's other
/// fields at their longest. Measured from the real encoding, not assumed.
#[cfg(feature = "daemon")]
pub(crate) fn worst_frame_bytes(ciphertext_len: usize) -> usize {
let shell = rmp_serde::to_vec(&TransportEnvelope {
schema_id: ENVELOPE_SCHEMA_ID.to_string(),
@ -429,6 +431,7 @@ mod tests {
assert!(matches!(write(&[], 1_000), Err(TransportFrameError::Size)));
}
#[cfg(feature = "daemon")]
#[test]
fn the_worst_frame_is_the_real_encoding_of_an_all_high_ciphertext() {
let long = "x".repeat(MAX_IDENTITY_BYTES);
@ -449,6 +452,7 @@ mod tests {
}
}
#[cfg(feature = "daemon")]
#[test]
fn a_sealed_envelope_never_exceeds_the_worst_frame_for_its_ciphertext() {
let key = security("epiphany-distinct-test-key");

View file

@ -917,16 +917,21 @@ mod tests {
assert_eq!(executions, 1);
}
/// The largest result plaintext whose sealed frame fits at the worst encoding.
fn widest_guaranteed_plaintext(base: usize) -> usize {
(base..=FRAME)
.take_while(|plaintext| worst_frame_bytes(plaintext + GCM_TAG) <= FRAME)
.last()
.unwrap_or(base)
}
#[test]
fn a_result_within_what_the_worst_encoding_leaves_is_delivered_intact() {
// The largest plaintext whose sealed frame fits at the worst encoding is
// always carried, whatever the ciphertext bytes turn out to be.
for request_id in id_cases() {
let base = empty_result_len(&request_id);
let mut plaintext = base;
while worst_frame_bytes(plaintext + 1 + GCM_TAG) <= FRAME {
plaintext += 1;
}
let plaintext = widest_guaranteed_plaintext(base);
let (first, second, _) = call_twice(SizedBackend::new(plaintext - base), &request_id);
let TransportDisposition::Transported { events, receipt } = &first.disposition else {
panic!("expected a transported result");
@ -946,11 +951,8 @@ mod tests {
// way the caller gets an answer, and the retry gets the same one.
for request_id in id_cases() {
let base = empty_result_len(&request_id);
let mut plaintext = base;
while worst_frame_bytes(plaintext + GCM_TAG) <= FRAME {
plaintext += 1;
}
for extra in [0, 1, 2] {
let plaintext = widest_guaranteed_plaintext(base);
for extra in [1, 2, 3] {
let backend = SizedBackend::new(plaintext + extra - base);
let (first, second, executions) = call_twice(backend, &request_id);
assert_eq!(first, second);