feat: expose current Plugin execution identity to trusted Hosts

This commit is contained in:
2026-10-30 02:52:25 +09:00
parent e7506c5eb8
commit 4f096f26b5
@@ -709,6 +709,50 @@ pub(super) async fn interrupt_subject_workers(
results results
} }
impl WorkspaceApi {
/// Trusted Host plan creation uses the same identity as live Plugin operations.
/// Principal and delegation are derived here, never accepted from public JSON.
pub async fn plugin_execution_identity(
&self,
worker: &RuntimeWorkerRef,
) -> crate::Result<crate::plugin_plan::HostExecutionIdentity> {
self.store
.get_workspace_runtime_binding(self.workspace_id(), &worker.runtime_id)
.await?
.filter(|binding| binding.revoked_at.is_none())
.ok_or_else(|| {
Error::WorkspacePermissionDenied("Plugin Runtime trust revoked".into())
})?;
let api = self.clone();
let worker = worker.clone();
self.host_executors
.host()?
.run(move || {
let member = api.store.get_worker_registry(api.workspace_id(), &worker)?;
let reserved = api
.store
.has_active_worker_create_reservation(api.workspace_id(), &worker)?;
if member.is_none() && !reserved {
return Err(Error::WorkspacePermissionDenied(
"Plugin Worker is not registered".into(),
));
}
api.store
.require_current_worker_singleton_owner(api.workspace_id(), &worker)?;
let summary = api.runtime.worker(&worker).map_err(|_| {
Error::WorkspacePermissionDenied("Plugin Worker unavailable".into())
})?;
if summary.workspace.workspace_id.as_deref() != Some(api.workspace_id()) {
return Err(Error::WorkspacePermissionDenied(
"foreign Plugin Worker".into(),
));
}
plugin_execution_identity(&api, &worker).map_err(|error| error.error)
})
.await
}
}
pub(super) fn administration_actor( pub(super) fn administration_actor(
context: &server_api::ServerRequestContext, context: &server_api::ServerRequestContext,
) -> ApiResult<&RequestActor> { ) -> ApiResult<&RequestActor> {