pub fn check_task_scope(
task: &serde_json::Value,
worker_id: &str,
agent_name: &str,
workspace_ids: &[String],
) -> Result<(), String> {
let metadata = task_metadata(task);
let target_agent = metadata
.get("target_agent_name")
.and_then(|v| v.as_str())
.or_else(|| task.get("target_agent_name").and_then(|v| v.as_str()))
.or_else(|| {
task.get("task")
.and_then(|t| t.get("target_agent_name"))
.and_then(|v| v.as_str())
});
if let Some(target) = target_agent {
if !target.is_empty() && target != agent_name {
return Err(format!("target_agent_name={target} ≠ agent={agent_name}"));
}
}
let target_worker = metadata
.get("target_worker_id")
.and_then(|v| v.as_str())
.or_else(|| task.get("target_worker_id").and_then(|v| v.as_str()));
if let Some(target) = target_worker {
if !target.is_empty() && target != worker_id {
return Err(format!("target_worker_id={target} ≠ worker={worker_id}"));
}
}
let ws_id = task
.get("workspace_id")
.and_then(|v| v.as_str())
.or_else(|| metadata.get("workspace_id").and_then(|v| v.as_str()))
.unwrap_or("");
if !ws_id.is_empty() && ws_id != "global" && !workspace_ids.is_empty() {
if !workspace_ids.iter().any(|id| id == ws_id) {
return Err(format!("workspace_id={ws_id} not in worker scope"));
}
}
Ok(())
}
fn task_metadata(task: &serde_json::Value) -> serde_json::Map<String, serde_json::Value> {
task.get("task")
.and_then(|t| t.get("metadata"))
.or_else(|| task.get("metadata"))
.and_then(|m| m.as_object())
.cloned()
.unwrap_or_default()
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn accepts_unscoped_task() {
let task = json!({"id": "t1", "prompt": "hello"});
assert!(check_task_scope(&task, "w1", "builder", &[]).is_ok());
}
#[test]
fn rejects_wrong_agent() {
let task = json!({"id": "t1", "metadata": {"target_agent_name": "planner"}});
assert!(check_task_scope(&task, "w1", "builder", &[]).is_err());
}
#[test]
fn accepts_matching_agent() {
let task = json!({"id": "t1", "metadata": {"target_agent_name": "builder"}});
assert!(check_task_scope(&task, "w1", "builder", &[]).is_ok());
}
#[test]
fn rejects_wrong_worker() {
let task = json!({"id": "t1", "metadata": {"target_worker_id": "other-worker"}});
assert!(check_task_scope(&task, "w1", "builder", &[]).is_err());
}
#[test]
fn accepts_matching_worker() {
let task = json!({"id": "t1", "metadata": {"target_worker_id": "w1"}});
assert!(check_task_scope(&task, "w1", "builder", &[]).is_ok());
}
#[test]
fn rejects_unknown_workspace() {
let task = json!({"id": "t1", "workspace_id": "ws-999"});
let workspaces = vec!["ws-1".into(), "ws-2".into()];
assert!(check_task_scope(&task, "w1", "builder", &workspaces).is_err());
}
#[test]
fn accepts_known_workspace() {
let task = json!({"id": "t1", "workspace_id": "ws-1"});
let workspaces = vec!["ws-1".into(), "ws-2".into()];
assert!(check_task_scope(&task, "w1", "builder", &workspaces).is_ok());
}
#[test]
fn accepts_global_workspace() {
let task = json!({"id": "t1", "workspace_id": "global"});
let workspaces = vec!["ws-1".into()];
assert!(check_task_scope(&task, "w1", "builder", &workspaces).is_ok());
}
#[test]
fn accepts_empty_workspace_when_worker_has_none() {
let task = json!({"id": "t1"});
assert!(check_task_scope(&task, "w1", "builder", &[]).is_ok());
}
#[test]
fn nested_task_metadata_agent() {
let task = json!({"task": {"id": "t1", "metadata": {"target_agent_name": "builder"}}});
assert!(check_task_scope(&task, "w1", "builder", &[]).is_ok());
}
#[test]
fn nested_task_metadata_wrong_agent() {
let task = json!({"task": {"id": "t1", "metadata": {"target_agent_name": "planner"}}});
assert!(check_task_scope(&task, "w1", "builder", &[]).is_err());
}
}