Synced from monorepo

Synced from monorepo

Changes:
- Report invalid MCP server config instead of failing startup
- Keep completed terminal output when the gateway connection is lost
- Show a duration-only detail view for single-task task output
- Don't let a stale registry turn counter hide local sessions
- Raise the file-descriptor soft limit on Linux and log effective limits at startup
- Stop aborting when HTTP client construction fails
- Make session thread and runtime spawn failures recoverable
- Fix main-prompt paste parity in the question freeform input
- Fire SessionEnd hooks on /exit and headless quit
- Embed the deployment-config signing public key
- Repaint paste-chip background on inline panel inputs
- Security: prevent acceptEdits from auto-approving agent writes into the always-trusted global hook root
- Fix stacked "Worked for" markers so parks render as status and turns close with exactly one marker
- Parse hooks from config files
- Add a remote kill-switch for managed-config signature verification
- Security: fix workspace file-reference resolution bypassing workspace filesystem confinement

Source-Revision: d02693a856a54f1030695b36b91d276e96b30b23
This commit is contained in:
grokkybara[bot] 2026-07-25 18:44:42 +00:00
commit 47348d13ec
138 changed files with 7283 additions and 5796 deletions

View file

@ -526,11 +526,28 @@ impl WorkspaceRpcHandler {
let cwd = self.workspace.root_cwd()?;
let mut results = Vec::new();
for ref_path in &refs {
let full_path = if std::path::Path::new(ref_path).is_absolute() {
let requested_path = if std::path::Path::new(ref_path).is_absolute() {
std::path::PathBuf::from(ref_path)
} else {
cwd.join(ref_path)
};
let full_path = match self
.workspace
.confine_to_workspace_root(&requested_path)
.await
{
Ok((confined, _)) => confined,
Err(e) => {
results.push(serde_json::json!({
"path": requested_path.to_string_lossy(),
"ref": ref_path,
"exists": false,
"content": Value::Null,
"error": e.to_string(),
}));
continue;
}
};
let exists = full_path.exists();
let content = if exists {
tokio::fs::read_to_string(&full_path).await.ok()
@ -601,6 +618,9 @@ impl WorkspaceRpcHandler {
);
Ok(Value::Array(plugins))
}
<ExportGithubReq as WorkspaceRpc>::METHOD => {
dispatch_op::<ExportGithubReq>(params, &self.workspace, None).await
}
<HookRegistryReq as WorkspaceRpc>::METHOD => {
dispatch_op::<HookRegistryReq>(params, &self.workspace, None).await
}
@ -1169,7 +1189,9 @@ impl ToolServerHandler for WorkspaceRpcHandler {
mod tests {
use super::*;
use crate::capability::CapabilityMode;
use crate::handle::tests::{background_capable_cfg, make_handle, start_background_sleep};
use crate::handle::tests::{
background_capable_cfg, make_confining_handle, make_handle, start_background_sleep,
};
use xai_grok_tools::implementations::grok_build::scheduler::types::{
ScheduledTask, SchedulerState,
};
@ -2498,6 +2520,34 @@ mod tests {
);
}
#[tokio::test]
async fn dispatch_resolve_file_references_rejects_outside_root_when_confined() {
let handle = make_confining_handle();
let handler = WorkspaceRpcHandler::new(handle);
let secret = std::env::temp_dir().join("h1_3885911_outside_secret.txt");
std::fs::write(&secret, "OUTSIDE_SECRET").unwrap();
let params = serde_json::json!({
"refs": [secret.to_string_lossy(), "../escape.txt"]
});
let result = handler
.dispatch("workspace.resolve_file_references", params, None)
.await
.expect("dispatch itself should succeed");
let arr = result.as_array().expect("results array");
assert_eq!(arr.len(), 2);
for entry in arr {
assert_eq!(entry["exists"], serde_json::Value::Bool(false));
assert_eq!(entry["content"], serde_json::Value::Null);
assert!(
entry["error"]
.as_str()
.unwrap_or_default()
.contains("escapes workspace root"),
"escape should be rejected, not read: {entry:?}"
);
}
std::fs::remove_file(&secret).ok();
}
#[tokio::test]
async fn handle_hook_pause_resume_are_noops() {
let handle = make_handle();
let handler = WorkspaceRpcHandler::new(handle);
@ -3057,6 +3107,7 @@ mod tests {
<InstallPluginReq as WorkspaceRpc>::METHOD,
<RefreshPluginsReq as WorkspaceRpc>::METHOD,
<DiscoverPluginsReq as WorkspaceRpc>::METHOD,
<ExportGithubReq as WorkspaceRpc>::METHOD,
];
let skipped_global_db_mutators = [
<WorktreeGcReq as WorkspaceRpc>::METHOD,