refactor(#1834): derive cancel-loose-end privilege from the socket, not the MANAGER_AGENT name
The cancel-loose-end guards (cancel approval / question / reminder)
inferred manager-level privilege by string-matching the canceller
against the hardcoded `hive_sh4re::MANAGER_AGENT` ("ruth"). That laundered
privilege through a name: a request arrives on the privileged manager
socket, gets stamped with the bootstrap agent's name, and the guards
re-derive privilege from that name. Renaming or replacing the bootstrap
agent would then silently move privilege.
Privilege is a property of the SOCKET the request arrived on (the manager
socket is the trust boundary), so thread an explicit `privileged: bool`
through `dispatch_shared` → `handle_cancel_loose_end` → the three guards:
- `Broker::cancel_reminder_as` and `OperatorQuestions::cancel`: the
`== MANAGER_AGENT` leg becomes `privileged` (owner/asker + operator name
legs unchanged).
- `check_approval_canceller_is_manager(canceller)` →
`check_can_cancel_approval(privileged)` (manager-socket-only); unit tests
updated to assert on the flag.
The manager socket passes `privileged = true`; the agent socket passes
`false`. `MANAGER_AGENT` is still passed as the actor NAME for legitimate
attribution/routing (notifications, schedule ownership, bootstrap
destroy-protection) — those are not privilege checks and are left intact.
Scope is the privilege guards only.
This commit is contained in:
parent
e797b75ca9
commit
53f49615fa
5 changed files with 65 additions and 49 deletions
|
|
@ -124,6 +124,7 @@ pub(crate) fn recv_timeout(wait_seconds: Option<u64>) -> std::time::Duration {
|
|||
pub(crate) async fn dispatch_shared(
|
||||
req: &hive_sh4re::Request,
|
||||
agent: &str,
|
||||
privileged: bool,
|
||||
coord: &Arc<Coordinator>,
|
||||
) -> Option<hive_sh4re::Response> {
|
||||
Some(match req {
|
||||
|
|
@ -178,10 +179,11 @@ pub(crate) async fn dispatch_shared(
|
|||
handle_get_agent_meta(coord, agent, name.as_deref()).await
|
||||
}
|
||||
hive_sh4re::Request::CancelLooseEnd { kind, id } => {
|
||||
crate::questions::handle_cancel_loose_end(coord, agent, *kind, *id).map_or_else(
|
||||
|message| hive_sh4re::Response::Err { message },
|
||||
|()| hive_sh4re::Response::Ok,
|
||||
)
|
||||
crate::questions::handle_cancel_loose_end(coord, agent, privileged, *kind, *id)
|
||||
.map_or_else(
|
||||
|message| hive_sh4re::Response::Err { message },
|
||||
|()| hive_sh4re::Response::Ok,
|
||||
)
|
||||
}
|
||||
hive_sh4re::Request::CreateRepo { repo } => handle_create_repo(agent, repo).await,
|
||||
hive_sh4re::Request::AckTurn => handle_ack_turn(coord, agent),
|
||||
|
|
@ -433,7 +435,9 @@ fn handle_requeue_inflight(coord: &Arc<Coordinator>, agent: &str) -> hive_sh4re:
|
|||
}
|
||||
|
||||
async fn dispatch(req: &AgentRequest, agent: &str, coord: &Arc<Coordinator>) -> AgentResponse {
|
||||
if let Some(resp) = dispatch_shared(req, agent, coord).await {
|
||||
// Regular agent socket: never privileged. Privilege is reserved for
|
||||
// requests arriving on the manager socket (see `manager_server`).
|
||||
if let Some(resp) = dispatch_shared(req, agent, false, coord).await {
|
||||
return resp;
|
||||
}
|
||||
match req {
|
||||
|
|
|
|||
Loading…
Reference in a new issue