huskies: merge 1103 bug Rate-limit warning at session start sticks the rate_limit_exit flag, causing 1053's fast-path bypass to skip completion on clean session exits
This commit is contained in:
@@ -445,4 +445,62 @@ mod tests {
|
||||
the respawn's lookup_session returns it (warm), not None (cold)"
|
||||
);
|
||||
}
|
||||
|
||||
// ── bug 1103: soft rate-limit warning (status=allowed) must NOT set rate_limit_exit ──
|
||||
|
||||
/// Regression: a `rate_limit_event` with `status="allowed"` is a soft
|
||||
/// warning — the request was permitted. The session that follows should
|
||||
/// complete normally and report `rate_limit_exit == false`, not trigger the
|
||||
/// rate-limit respawn path in the spawn handler.
|
||||
#[tokio::test]
|
||||
async fn rate_limit_allowed_status_does_not_set_rate_limit_exit() {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let script = tmp.path().join("emit_allowed_then_exit.sh");
|
||||
// Emit status="allowed" (soft warning), then exit cleanly.
|
||||
std::fs::write(
|
||||
&script,
|
||||
"#!/bin/sh\nprintf '%s\\n' '{\"type\":\"rate_limit_event\",\"rate_limit_info\":{\"status\":\"allowed\",\"reset_at\":\"2099-01-01T12:00:00Z\"}}'\n",
|
||||
)
|
||||
.unwrap();
|
||||
std::fs::set_permissions(&script, std::fs::Permissions::from_mode(0o755)).unwrap();
|
||||
|
||||
let (tx, _rx) = broadcast::channel::<AgentEvent>(64);
|
||||
let (watcher_tx, mut watcher_rx) = broadcast::channel::<WatcherEvent>(16);
|
||||
let event_log = Arc::new(Mutex::new(Vec::new()));
|
||||
|
||||
let result = run_agent_pty_streaming(
|
||||
"1103_soft_warning_no_exit_flag",
|
||||
"coder-1",
|
||||
"sh",
|
||||
&[script.to_string_lossy().to_string()],
|
||||
"--",
|
||||
"/tmp",
|
||||
&tx,
|
||||
&event_log,
|
||||
None,
|
||||
0,
|
||||
watcher_tx,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
|
||||
let pty = result.expect("PTY run should succeed");
|
||||
assert!(
|
||||
!pty.rate_limit_exit,
|
||||
"rate_limit_exit must be false for a soft 'allowed' warning; \
|
||||
only genuine hard blocks (rejected) should set it"
|
||||
);
|
||||
|
||||
// Watcher must have received RateLimitWarning, not RateLimitHardBlock.
|
||||
let evt = watcher_rx
|
||||
.try_recv()
|
||||
.expect("Expected a RateLimitWarning watcher event");
|
||||
assert!(
|
||||
matches!(evt, WatcherEvent::RateLimitWarning { .. }),
|
||||
"Expected RateLimitWarning for status=allowed, got: {evt:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,7 +347,11 @@ fn run_agent_pty_blocking(
|
||||
.and_then(|i| i.get("status"))
|
||||
.and_then(|s| s.as_str())
|
||||
.unwrap_or("");
|
||||
let is_hard_block = !status.is_empty() && status != "allowed_warning";
|
||||
// "allowed" and "allowed_warning" are soft warnings — the request was
|
||||
// permitted; only statuses that actually block the request (e.g. "rejected")
|
||||
// are genuine hard blocks that warrant a rate-limit exit respawn.
|
||||
let is_hard_block =
|
||||
!status.is_empty() && status != "allowed" && status != "allowed_warning";
|
||||
let reset_at = rate_limit_info
|
||||
.and_then(|i| i.get("reset_at"))
|
||||
.and_then(|r| r.as_str())
|
||||
|
||||
Reference in New Issue
Block a user