From 2c1f5dfafeb8803d8478231dfe0d314f257b05e1 Mon Sep 17 00:00:00 2001 From: Hare Date: Sat, 31 Oct 2026 04:58:19 +0900 Subject: [PATCH] fix: bound Subject database retention to synchronous plugin checks --- .../src/server/subject_authorization.rs | 4 +- .../src/server_plugin_host.rs | 57 ++++++++++++------- .../src/server_plugin_service.rs | 48 ++++++++-------- 3 files changed, 65 insertions(+), 44 deletions(-) diff --git a/crates/workspace-server/src/server/subject_authorization.rs b/crates/workspace-server/src/server/subject_authorization.rs index aeb084fc1..3d533ab9b 100644 --- a/crates/workspace-server/src/server/subject_authorization.rs +++ b/crates/workspace-server/src/server/subject_authorization.rs @@ -955,7 +955,9 @@ impl WorkspaceApi { "foreign Plugin Worker".into(), )); } - plugin_execution_identity(&api, &worker).map_err(|error| error.error) + super::plugin_host::with_authority_database(&api, || { + plugin_execution_identity(&api, &worker).map_err(|error| error.error) + }) }) .await } diff --git a/crates/workspace-server/src/server_plugin_host.rs b/crates/workspace-server/src/server_plugin_host.rs index 473fe3965..c8b918b05 100644 --- a/crates/workspace-server/src/server_plugin_host.rs +++ b/crates/workspace-server/src/server_plugin_host.rs @@ -134,6 +134,20 @@ fn operation_name(op: &PluginHostOperation) -> &'static str { } } +/// Retain the physical Subject database only for this synchronous check. Each +/// policy/lineage query still reads its owner; no authorization result or lock +/// survives the closure, and FeatureStorage continues to enforce lifecycle fences. +pub(super) fn with_authority_database( + api: &WorkspaceApi, + check: impl FnOnce() -> crate::Result, +) -> crate::Result { + let _database = api + .feature_storage + .open(&api.subjektiv_registration) + .map_err(|error| Error::Store(error.to_string()))?; + check() +} + async fn check( api: Arc, context: ServerRequestContext, @@ -220,28 +234,31 @@ async fn check_tools( let executor = api.config_store.db_executor(); executor .run(move || { - subject_authorization::authorize_scope( - &api, - &worker, - &server_api::authorization::OperationAuthorizationRequest { - operation: operation_name(&operation).into(), - resource: server_api::authorization::PermissionResource::PluginInstallation { - workspace_id: workspace.clone(), - installation_id: installation.clone(), + with_authority_database(&api, || { + subject_authorization::authorize_scope( + &api, + &worker, + &server_api::authorization::OperationAuthorizationRequest { + operation: operation_name(&operation).into(), + resource: + server_api::authorization::PermissionResource::PluginInstallation { + workspace_id: workspace.clone(), + installation_id: installation.clone(), + }, }, - }, - ) - .map_err(|e| e.error)?; - api.config_store.with_immediate_transaction(|tx| { - policy::authorize( - tx, - &workspace, - &execution, - &plan_id, - &installation, - &tools, - &operation, ) + .map_err(|e| e.error)?; + api.config_store.with_immediate_transaction(|tx| { + policy::authorize( + tx, + &workspace, + &execution, + &plan_id, + &installation, + &tools, + &operation, + ) + }) }) }) .await diff --git a/crates/workspace-server/src/server_plugin_service.rs b/crates/workspace-server/src/server_plugin_service.rs index ac1255ce7..1393eff89 100644 --- a/crates/workspace-server/src/server_plugin_service.rs +++ b/crates/workspace-server/src/server_plugin_service.rs @@ -31,30 +31,32 @@ async fn check_service( let executor = api.config_store.db_executor(); executor .run(move || { - for op in ["plugin.service.consume", operation_name(&operation)] { - subject_authorization::authorize_scope( - &api, - &worker, - &OperationAuthorizationRequest { - operation: op.into(), - resource: PermissionResource::PluginInstallation { - workspace_id: workspace.clone(), - installation_id: installation.clone(), + with_authority_database(&api, || { + for op in ["plugin.service.consume", operation_name(&operation)] { + subject_authorization::authorize_scope( + &api, + &worker, + &OperationAuthorizationRequest { + operation: op.into(), + resource: PermissionResource::PluginInstallation { + workspace_id: workspace.clone(), + installation_id: installation.clone(), + }, }, - }, - ) - .map_err(|e| e.error)?; - } - api.config_store.with_immediate_transaction(|tx| { - policy::authorize_service( - tx, - &workspace, - &execution, - &plan_id, - &installation, - &name, - &operation, - ) + ) + .map_err(|e| e.error)?; + } + api.config_store.with_immediate_transaction(|tx| { + policy::authorize_service( + tx, + &workspace, + &execution, + &plan_id, + &installation, + &name, + &operation, + ) + }) }) }) .await