zeph_subagent/manager/
secrets.rs1use std::collections::HashMap;
5use std::time::Duration;
6
7use super::SubAgentManager;
8use crate::error::SubAgentError;
9use crate::grants::SecretRequest;
10
11pub(crate) fn make_hook_env(
13 task_id: &str,
14 agent_name: &str,
15 tool_name: &str,
16) -> HashMap<String, String> {
17 let mut env = HashMap::new();
18 env.insert("ZEPH_AGENT_ID".to_owned(), task_id.to_owned());
19 env.insert("ZEPH_AGENT_NAME".to_owned(), agent_name.to_owned());
20 env.insert("ZEPH_AGENT_TYPE".to_owned(), "subagent".to_owned());
21 env.insert("ZEPH_TOOL_NAME".to_owned(), tool_name.to_owned());
22 env
23}
24
25impl SubAgentManager {
26 pub fn approve_secret(
37 &mut self,
38 task_id: &str,
39 secret_key: &str,
40 ttl: Duration,
41 ) -> Result<(), SubAgentError> {
42 let handle = self
43 .agents
44 .get_mut(task_id)
45 .ok_or_else(|| SubAgentError::NotFound(task_id.to_owned()))?;
46
47 handle.grants.sweep_expired();
48
49 if !handle
50 .def
51 .permissions
52 .secrets
53 .iter()
54 .any(|k| k == secret_key)
55 {
56 tracing::warn!(task_id, "secret request denied: key not in allowed list");
57 return Err(SubAgentError::Invalid(format!(
58 "secret is not in the allowed secrets list for '{}'",
59 handle.def.name
60 )));
61 }
62
63 handle.grants.grant_secret(secret_key, ttl);
64 Ok(())
65 }
66
67 pub fn deliver_secret(&mut self, task_id: &str, key: String) -> Result<(), SubAgentError> {
76 let handle = self
77 .agents
78 .get_mut(task_id)
79 .ok_or_else(|| SubAgentError::NotFound(task_id.to_owned()))?;
80 handle
81 .secret_tx
82 .try_send(Some(key))
83 .map_err(|e| SubAgentError::Channel(e.to_string()))
84 }
85
86 pub fn deny_secret(&mut self, task_id: &str) -> Result<(), SubAgentError> {
93 let handle = self
94 .agents
95 .get_mut(task_id)
96 .ok_or_else(|| SubAgentError::NotFound(task_id.to_owned()))?;
97 handle
98 .secret_tx
99 .try_send(None)
100 .map_err(|e| SubAgentError::Channel(e.to_string()))
101 }
102
103 pub fn try_recv_secret_request(&mut self) -> Option<(String, SecretRequest)> {
109 for handle in self.agents.values_mut() {
110 if let Ok(req) = handle.pending_secret_rx.try_recv() {
111 return Some((handle.task_id.clone(), req));
112 }
113 }
114 None
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::make_hook_env;
121
122 #[test]
123 fn make_hook_env_sets_agent_type_subagent() {
124 let env = make_hook_env("task-42", "my-agent", "Shell");
125 assert_eq!(
126 env.get("ZEPH_AGENT_TYPE").map(String::as_str),
127 Some("subagent")
128 );
129 assert_eq!(
130 env.get("ZEPH_AGENT_ID").map(String::as_str),
131 Some("task-42")
132 );
133 assert_eq!(
134 env.get("ZEPH_AGENT_NAME").map(String::as_str),
135 Some("my-agent")
136 );
137 assert_eq!(env.get("ZEPH_TOOL_NAME").map(String::as_str), Some("Shell"));
138 }
139}