Skip to content

Commit 7db4c4a

Browse files
committed
fix: batch merge of bug fixes (PR #287) - issues #2743, #2744, #2745, #2746, #2749, #2750, #2751, #2752, #2754, #2755
Fixes: - #2743: Use tokio::select! for ordered stdout/stderr interleaving - #2744: Add CWD validation before command execution - #2745: Implement Retry-After header parsing and respect in retry logic - #2746: Add read_timeout to HTTP client to prevent hangs on truncated responses - #2749: Enable cookie_store for cookie persistence across redirects - #2750: Add --method flag for HEAD/GET method selection in scrape command - #2751: Add comprehensive base64 validation for import command - #2752: Add EmptyResponse event type for malformed API responses - #2754: Add atomic_write functions using write-temp-then-rename pattern - #2755: Add poll_with_backoff method to prevent CPU spin on non-blocking stdin
1 parent 1a96672 commit 7db4c4a

9 files changed

Lines changed: 555 additions & 519 deletions

File tree

cortex-cli/src/import_cmd.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ impl ImportCommand {
107107
);
108108
}
109109

110+
// Validate all messages, including base64 content
111+
validate_export_messages(&export.messages)?;
112+
110113
// Validate agent references in the imported session
111114
let missing_agents = validate_agent_references(&export)?;
112115
if !missing_agents.is_empty() {
@@ -365,6 +368,82 @@ fn validate_no_circular_references(messages: &[ExportMessage]) -> Result<()> {
365368
Ok(())
366369
}
367370

371+
/// Validate all messages in an export, including base64-encoded content.
372+
/// Returns a clear error message if invalid data is found.
373+
fn validate_export_messages(messages: &[ExportMessage]) -> Result<()> {
374+
use base64::Engine;
375+
376+
for (idx, message) in messages.iter().enumerate() {
377+
// Check for base64-encoded image data in content
378+
// Common pattern: "data:image/png;base64,..." or "data:image/jpeg;base64,..."
379+
if let Some(data_uri_start) = message.content.find("data:image/") {
380+
if let Some(base64_marker) = message.content[data_uri_start..].find(";base64,") {
381+
let base64_start = data_uri_start + base64_marker + 8; // 8 = len(";base64,")
382+
let remaining = &message.content[base64_start..];
383+
384+
// Find end of base64 data (could end with quote, whitespace, or end of string)
385+
let base64_end = remaining
386+
.find(|c: char| c == '"' || c == '\'' || c == ' ' || c == '\n' || c == ')')
387+
.unwrap_or(remaining.len());
388+
let base64_data = &remaining[..base64_end];
389+
390+
// Validate the base64 data
391+
if !base64_data.is_empty() {
392+
let engine = base64::engine::general_purpose::STANDARD;
393+
if let Err(e) = engine.decode(base64_data) {
394+
bail!(
395+
"Invalid base64 encoding in message {} (role: '{}'): {}\n\
396+
The image data starting at position {} has invalid base64 encoding.\n\
397+
Please ensure all embedded images use valid base64 encoding.",
398+
idx + 1,
399+
message.role,
400+
e,
401+
data_uri_start
402+
);
403+
}
404+
}
405+
}
406+
}
407+
408+
// Validate tool call arguments if present
409+
if let Some(ref tool_calls) = message.tool_calls {
410+
for (tc_idx, tool_call) in tool_calls.iter().enumerate() {
411+
// Check for base64 in tool call arguments
412+
let args_str = tool_call.arguments.to_string();
413+
if args_str.contains(";base64,") {
414+
// Try to find and validate any base64 in the arguments
415+
for (pos, _) in args_str.match_indices(";base64,") {
416+
let base64_start = pos + 8;
417+
let remaining = &args_str[base64_start..];
418+
let base64_end = remaining
419+
.find(|c: char| {
420+
c == '"' || c == '\'' || c == ' ' || c == '\n' || c == ')'
421+
})
422+
.unwrap_or(remaining.len());
423+
let base64_data = &remaining[..base64_end];
424+
425+
if !base64_data.is_empty() {
426+
let engine = base64::engine::general_purpose::STANDARD;
427+
if let Err(e) = engine.decode(base64_data) {
428+
bail!(
429+
"Invalid base64 encoding in message {} tool call {} ('{}' arguments): {}\n\
430+
Please ensure all embedded data uses valid base64 encoding.",
431+
idx + 1,
432+
tc_idx + 1,
433+
tool_call.name,
434+
e
435+
);
436+
}
437+
}
438+
}
439+
}
440+
}
441+
}
442+
}
443+
444+
Ok(())
445+
}
446+
368447
/// Convert an export message to a protocol event.
369448
fn message_to_event(message: &ExportMessage, turn_id: &mut u64, cwd: &PathBuf) -> Result<Event> {
370449
let event_msg = match message.role.as_str() {

0 commit comments

Comments
 (0)