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)"
|
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(|i| i.get("status"))
|
||||||
.and_then(|s| s.as_str())
|
.and_then(|s| s.as_str())
|
||||||
.unwrap_or("");
|
.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
|
let reset_at = rate_limit_info
|
||||||
.and_then(|i| i.get("reset_at"))
|
.and_then(|i| i.get("reset_at"))
|
||||||
.and_then(|r| r.as_str())
|
.and_then(|r| r.as_str())
|
||||||
|
|||||||
Reference in New Issue
Block a user