core: add tenancy extension seam
This commit is contained in:
@@ -165,4 +165,5 @@ Progress:
|
||||
- Phase 1 / task `1.7`: workspace version bumped to `0.2.0`; release gate пройден (`just verify`, `npm run build`, `npm run e2e`), release commit и tag `v0.2.0` подготовлены в `crank-community`
|
||||
- Phase 2 dependency slice: `IdentityProvider` seam widened to cover `SSO/TOTP` with default `NotSupportedForProvider` methods and shared public DTOs for authorize/callback/two-factor flows; workspace version bumped to `0.3.0` for downstream enterprise consumption
|
||||
- Phase 2 dependency slice: `apps/admin-api` now exposes a reusable lib target (`src/lib.rs`), so downstream private repos can depend on `build_app`, `AppState`, `AdminServiceBuilder`, and auth/state modules without copying the Community admin app
|
||||
- Phase 3 dependency slice: added public tenancy seam in `crank-core` — `TenantId`, `TenantResolutionContext`, `TenantController`, `TenancyError`, and `SingleTenantController` — so `cloud` can build hosted tenant routing without bypassing the shared extension model
|
||||
- backward-compatible alias `CommunityMachineCredentialVerifier` сохранен, поведение Community не изменено
|
||||
|
||||
@@ -3,3 +3,4 @@ pub mod audit;
|
||||
pub mod auth;
|
||||
pub mod capability;
|
||||
pub mod protocol;
|
||||
pub mod tenancy;
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
||||
use crate::{TenantId, WorkspaceId};
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||
pub struct TenantResolutionContext {
|
||||
pub workspace_id: Option<WorkspaceId>,
|
||||
pub workspace_slug: Option<String>,
|
||||
pub host: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error, PartialEq, Eq)]
|
||||
pub enum TenancyError {
|
||||
#[error("tenant lookup is not supported in this edition")]
|
||||
UnsupportedLookup,
|
||||
#[error("internal tenancy failure: {0}")]
|
||||
Internal(String),
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait TenantController: Send + Sync {
|
||||
fn resolve_tenant(&self, request: &TenantResolutionContext) -> Result<TenantId, TenancyError>;
|
||||
|
||||
async fn list_workspaces_for_tenant(
|
||||
&self,
|
||||
tenant: &TenantId,
|
||||
) -> Result<Vec<WorkspaceId>, TenancyError>;
|
||||
}
|
||||
|
||||
pub type SharedTenantController = Arc<dyn TenantController>;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SingleTenantController {
|
||||
tenant_id: TenantId,
|
||||
}
|
||||
|
||||
impl Default for SingleTenantController {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
tenant_id: TenantId::new("default"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl TenantController for SingleTenantController {
|
||||
fn resolve_tenant(
|
||||
&self,
|
||||
_request: &TenantResolutionContext,
|
||||
) -> Result<TenantId, TenancyError> {
|
||||
Ok(self.tenant_id.clone())
|
||||
}
|
||||
|
||||
async fn list_workspaces_for_tenant(
|
||||
&self,
|
||||
_tenant: &TenantId,
|
||||
) -> Result<Vec<WorkspaceId>, TenancyError> {
|
||||
Ok(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{SingleTenantController, TenantController, TenantResolutionContext};
|
||||
use crate::TenantId;
|
||||
|
||||
#[tokio::test]
|
||||
async fn single_tenant_controller_returns_default_tenant() {
|
||||
let controller = SingleTenantController::default();
|
||||
|
||||
let tenant = controller
|
||||
.resolve_tenant(&TenantResolutionContext::default())
|
||||
.unwrap();
|
||||
let workspaces = controller.list_workspaces_for_tenant(&tenant).await.unwrap();
|
||||
|
||||
assert_eq!(tenant, TenantId::new("default"));
|
||||
assert!(workspaces.is_empty());
|
||||
}
|
||||
}
|
||||
@@ -48,6 +48,7 @@ define_id!(ToolId);
|
||||
define_id!(SampleId);
|
||||
define_id!(AuthProfileId);
|
||||
define_id!(WorkspaceId);
|
||||
define_id!(TenantId);
|
||||
define_id!(UserId);
|
||||
define_id!(UserSessionId);
|
||||
define_id!(AgentId);
|
||||
|
||||
@@ -52,9 +52,13 @@ pub use ext::protocol::{
|
||||
AdapterRegistry, AdapterResponse, PreparedRequest, ProtocolAdapter, ProtocolAdapterError,
|
||||
ResponseCacheScope, RuntimeRequestContext, SharedProtocolAdapter, WindowExecutionResult,
|
||||
};
|
||||
pub use ext::tenancy::{
|
||||
SharedTenantController, SingleTenantController, TenantController, TenantResolutionContext,
|
||||
TenancyError,
|
||||
};
|
||||
pub use ids::{
|
||||
AgentId, AsyncJobId, AuditEventId, AuthProfileId, DescriptorId, InvitationId, InvocationLogId,
|
||||
OperationId, PlatformApiKeyId, SampleId, SecretId, StreamSessionId, ToolId, UserId,
|
||||
OperationId, PlatformApiKeyId, SampleId, SecretId, StreamSessionId, TenantId, ToolId, UserId,
|
||||
UserSessionId, WorkspaceId,
|
||||
};
|
||||
pub use observability::{
|
||||
|
||||
Reference in New Issue
Block a user