feat(v1): harden typed runtime boundaries

Elect one canonical EffectBatch codec, remove the parallel postcard API, and strengthen fail-closed host, form, sync, WASM, macro, generated-contract, and test-harness proofs with mutation-driven coverage.

req: wire/008

req: wire/009

req: wire/010

req: push/008

req: client_local/015

req: client_local/016

req: client_local/017

req: client_local/018

req: client_local/019

req: sync/024

req: sync/025

req: sync/026

req: sync/027

req: sync/028

req: sync/029

req: test/020

req: test/021
This commit is contained in:
slhx agent
2026-07-16 22:27:28 +02:00
parent e7211df4c5
commit e9ced4e0c1
19 changed files with 1529 additions and 198 deletions
+86 -30
View File
@@ -1485,23 +1485,20 @@ fn base64_url_no_pad(input: &[u8]) -> String {
let mut out = String::with_capacity((input.len() * 4).div_ceil(3));
let mut chunks = input.chunks_exact(3);
for chunk in &mut chunks {
let n = ((chunk[0] as u32) << 16) | ((chunk[1] as u32) << 8) | chunk[2] as u32;
out.push(ALPHABET[((n >> 18) & 0x3f) as usize] as char);
out.push(ALPHABET[((n >> 12) & 0x3f) as usize] as char);
out.push(ALPHABET[((n >> 6) & 0x3f) as usize] as char);
out.push(ALPHABET[(n & 0x3f) as usize] as char);
out.push(ALPHABET[(chunk[0] >> 2) as usize] as char);
out.push(ALPHABET[(((chunk[0] & 0x03) << 4) + (chunk[1] >> 4)) as usize] as char);
out.push(ALPHABET[(((chunk[1] & 0x0f) << 2) + (chunk[2] >> 6)) as usize] as char);
out.push(ALPHABET[(chunk[2] & 0x3f) as usize] as char);
}
match chunks.remainder() {
[a] => {
let n = (*a as u32) << 16;
out.push(ALPHABET[((n >> 18) & 0x3f) as usize] as char);
out.push(ALPHABET[((n >> 12) & 0x3f) as usize] as char);
out.push(ALPHABET[(a >> 2) as usize] as char);
out.push(ALPHABET[((a & 0x03) << 4) as usize] as char);
}
[a, b] => {
let n = ((*a as u32) << 16) | ((*b as u32) << 8);
out.push(ALPHABET[((n >> 18) & 0x3f) as usize] as char);
out.push(ALPHABET[((n >> 12) & 0x3f) as usize] as char);
out.push(ALPHABET[((n >> 6) & 0x3f) as usize] as char);
out.push(ALPHABET[(a >> 2) as usize] as char);
out.push(ALPHABET[(((a & 0x03) << 4) + (b >> 4)) as usize] as char);
out.push(ALPHABET[((b & 0x0f) << 2) as usize] as char);
}
[] => {}
_ => unreachable!(),
@@ -1528,24 +1525,22 @@ fn parse_urlencoded_pairs(body: &[u8]) -> Result<Vec<(String, String)>, Interact
fn percent_decode(input: &[u8]) -> Result<String, InteractionFormRejection> {
let mut out = Vec::with_capacity(input.len());
let mut i = 0;
while i < input.len() {
match input[i] {
b'+' => {
out.push(b' ');
i += 1;
}
b'%' if i + 2 < input.len() => {
let high = hex(input[i + 1]).ok_or(InteractionFormRejection::InvalidBody)?;
let low = hex(input[i + 2]).ok_or(InteractionFormRejection::InvalidBody)?;
out.push((high << 4) | low);
i += 3;
}
b'%' => return Err(InteractionFormRejection::InvalidBody),
byte => {
out.push(byte);
i += 1;
let mut bytes = input.iter().copied();
while let Some(byte) = bytes.next() {
match byte {
b'+' => out.push(b' '),
b'%' => {
let high = bytes
.next()
.and_then(hex)
.ok_or(InteractionFormRejection::InvalidBody)?;
let low = bytes
.next()
.and_then(hex)
.ok_or(InteractionFormRejection::InvalidBody)?;
out.push(high * 16 + low);
}
byte => out.push(byte),
}
}
String::from_utf8(out).map_err(|_| InteractionFormRejection::InvalidBody)
@@ -1563,7 +1558,8 @@ fn hex(byte: u8) -> Option<u8> {
#[cfg(test)]
mod tests {
use super::{
encode_sse_batch, html_with_root_fingerprint, sse, BuildFingerprint, InteractionForm,
base64_url_no_pad, encode_sse_batch, html_with_root_fingerprint, parse_urlencoded_pairs,
percent_decode, sse, BuildFingerprint, InteractionForm, InteractionFormRejection,
HEMX_SSE_EVENT,
};
use axum::{
@@ -1615,6 +1611,65 @@ mod tests {
assert_eq!(root.text().collect::<String>(), "Docs");
}
#[test]
fn base64url_transport_matches_rfc_4648_vectors_without_padding() {
for (input, expected) in [
(b"".as_slice(), ""),
(b"f".as_slice(), "Zg"),
(b"fo".as_slice(), "Zm8"),
(b"foo".as_slice(), "Zm9v"),
(b"foob".as_slice(), "Zm9vYg"),
(b"fooba".as_slice(), "Zm9vYmE"),
(b"foobar".as_slice(), "Zm9vYmFy"),
(&[0xfb, 0xff, 0xff], "-___"),
(&[0x00, 0x0f, 0x00], "AA8A"),
(&[0x00, 0xcf, 0x00], "AM8A"),
(&[0xff], "_w"),
(&[0xff, 0xff], "__8"),
] {
assert_eq!(base64_url_no_pad(input), expected);
}
// req: push/008 test
}
#[test]
fn urlencoded_decoder_handles_standard_escapes_and_rejects_malformed_input() {
assert_eq!(
parse_urlencoded_pairs(
b"empty=&space=+&slash=%2f&digit=%39&upper=%4A&lower=%4a&repeat=1&repeat=2"
),
Ok(vec![
("empty".into(), String::new()),
("space".into(), " ".into()),
("slash".into(), "/".into()),
("digit".into(), "9".into()),
("upper".into(), "J".into()),
("lower".into(), "J".into()),
("repeat".into(), "1".into()),
("repeat".into(), "2".into()),
])
);
assert_eq!(parse_urlencoded_pairs(b""), Ok(Vec::new()));
for malformed in [
b"bad=%".as_slice(),
b"bad=%0".as_slice(),
b"bad=%gg".as_slice(),
b"bad=%0g".as_slice(),
b"%gg=value".as_slice(),
] {
assert_eq!(
parse_urlencoded_pairs(malformed),
Err(InteractionFormRejection::InvalidBody)
);
}
assert_eq!(percent_decode(b"a+b%2Fc"), Ok("a b/c".into()));
assert_eq!(
InteractionForm::parse_urlencoded(b"__h=1&bad=%"),
Err(InteractionFormRejection::InvalidBody)
);
// test req: form/002 req: failure/003
}
#[tokio::test]
async fn sse_response_streams_base64_url_effect_batches() {
let batch = EffectBatch {
@@ -1623,6 +1678,7 @@ mod tests {
ops: Vec::new(),
};
let encoded = encode_sse_batch(&batch);
assert_eq!(encoded, "SEVNWAEAAAALAAAAAAAAAAAAAAA");
let response = sse(stream::iter([Ok::<_, Infallible>(batch)])).into_response();
assert_eq!(