From f9830fe7ddf73aedf0dd5deb66feef3ad8e3a96b Mon Sep 17 00:00:00 2001 From: Hare Date: Tue, 20 Oct 2026 03:40:36 +0900 Subject: [PATCH] test: reject Bash search pages that would skip an unread long line --- crates/worker/src/wip/bash_output_tests.rs | 40 ++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/crates/worker/src/wip/bash_output_tests.rs b/crates/worker/src/wip/bash_output_tests.rs index 39eac727e..21f2b88bc 100644 --- a/crates/worker/src/wip/bash_output_tests.rs +++ b/crates/worker/src/wip/bash_output_tests.rs @@ -468,3 +468,43 @@ async fn common_read_and_search_permissions_are_independent_from_bash_execution( ); assert!(!f._dir.path().join("denied").exists()); } + +#[tokio::test] +async fn multibyte_long_line_search_refuses_instead_of_skipping_an_unread_suffix() { + let f = Fixture::new(); + let result = f + .run("printf '雪%.0s' {1..22000}; printf 'needle\nnext\n'") + .await; + let path = result["stdout_entry"].as_str().unwrap(); + let error = invoke( + &f.runtime, + path, + Contract::SearchText, + "search", + json!({"pattern":"needle","offset":0,"limit":1}), + ) + .await + .unwrap_err(); + assert!( + error.to_string().contains("ResourceLimitExceeded"), + "{error}" + ); + // No successful page claims to advance past a partial line. Raw bytes can still + // retrieve its unread suffix using the same common file contract. + let suffix = invoke( + &f.runtime, + path, + Contract::ReadBytes, + "read", + json!({"offset":66000,"limit":7}), + ) + .await + .unwrap(); + assert_eq!( + base64::engine::general_purpose::STANDARD + .decode(suffix["data"].as_str().unwrap()) + .unwrap(), + b"needle\n" + ); + assert_eq!(suffix["next_offset"], 66007); +}