fix: secure submit activation handoff

This commit is contained in:
2026-09-06 02:31:10 +09:00
parent b038f022d3
commit dea5bd581d
10 changed files with 464 additions and 71 deletions
+59
View File
@@ -1203,6 +1203,37 @@ async fn worker_protocol_ws(
.into_response())
}
#[cfg(feature = "ws-server")]
fn authorize_runtime_protocol_method(method: protocol::Method) -> protocol::Method {
match method {
protocol::Method::SubmitTracked {
submission_request_id,
input,
..
} => protocol::Method::SubmitTracked {
source: protocol::AuthenticatedInputSource::Backend {
operation_id: submission_request_id.clone(),
},
submission_request_id,
input,
},
protocol::Method::NotifyTracked {
notification_request_id,
message,
auto_run,
..
} => protocol::Method::NotifyTracked {
source: protocol::AuthenticatedInputSource::Backend {
operation_id: notification_request_id.clone(),
},
notification_request_id,
message,
auto_run,
},
other => other,
}
}
#[cfg(feature = "ws-server")]
async fn worker_protocol_ws_session(
runtime: Runtime,
@@ -1291,6 +1322,7 @@ async fn worker_protocol_ws_session(
match inbound {
Some(Ok(WsMessage::Text(text))) => match decode_method(&text) {
Ok(method) => {
let method = authorize_runtime_protocol_method(method);
let result = match scope.as_ref() {
Some(scope) => {
runtime.send_protocol_method_scoped(scope, &worker_ref, method)
@@ -2084,6 +2116,33 @@ mod tests {
WorkdirPath, WorkdirSessionCapabilities,
};
#[test]
fn runtime_protocol_replaces_serialized_tracked_source() {
let wire = serde_json::to_string(&protocol::Method::SubmitTracked {
submission_request_id: "request-1".into(),
input: vec![protocol::Segment::text("hello")],
source: protocol::AuthenticatedInputSource::Account {
account_id: "forged".into(),
},
})
.unwrap();
let decoded: protocol::Method = serde_json::from_str(&wire).unwrap();
assert!(matches!(
decoded,
protocol::Method::SubmitTracked {
source: protocol::AuthenticatedInputSource::UntrustedWire,
..
}
));
assert!(matches!(
authorize_runtime_protocol_method(decoded),
protocol::Method::SubmitTracked {
source: protocol::AuthenticatedInputSource::Backend { operation_id },
..
} if operation_id == "request-1"
));
}
#[test]
fn attachment_routes_require_worker_input_permission() {
assert_eq!(
+14 -6
View File
@@ -1898,15 +1898,19 @@ where
&& busy
.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
.is_ok();
let notification_request_id = input
.submission_request_id
.unwrap_or_else(protocol::new_submission_request_id);
let result = self.send_method(
WorkerExecutionOperation::Input,
worker,
Method::Notify {
notification_request_id: input
.submission_request_id
.unwrap_or_else(protocol::new_submission_request_id),
Method::NotifyTracked {
notification_request_id: notification_request_id.clone(),
message: input.content,
auto_run: true,
source: protocol::AuthenticatedInputSource::Backend {
operation_id: notification_request_id,
},
},
accepted_run_state,
);
@@ -2066,8 +2070,12 @@ where
}
};
if let Method::Notify { auto_run, .. } = &method {
let auto_run = *auto_run;
if let Some(auto_run) = match &method {
Method::Notify { auto_run, .. } | Method::NotifyTracked { auto_run, .. } => {
Some(*auto_run)
}
_ => None,
} {
let status = worker.shared_state.get_status();
let accepted_run_state = accepted_notify_run_state(status, auto_run);
let claimed_here = status == WorkerStatus::Idle