Skip to main content

static_idp_plugin/
lib.rs

1//! Static `IdP` Plugin
2//!
3//! Permissive, in-memory echo implementation of
4//! [`account_management_sdk::IdpPluginClient`] for development and E2E
5//! environments. Every operation succeeds with a deterministic payload
6//! so Account Management's bootstrap saga and tenant lifecycle flows
7//! can run end-to-end without a real `IdP`.
8//!
9//! Do NOT enable this plugin in production. The production fallback is
10//! `account_management::infra::idp::NoopIdpProvider`, whose
11//! `UnsupportedOperation` defaults force operators to wire a real
12//! provider.
13//!
14//! ## Behaviour
15//!
16//! | Method | Behaviour |
17//! |---|---|
18//! | `provision_tenant` | Returns `Ok(IdpProvisionResult::new(Some(echo_metadata)))` — a deterministic JSON projection of the request (`tenant_id`, `tenant_name`, `tenant_type`, `root`/`child` target, optional `parent_id`, echoed `provisioning_metadata`). Pure function of the input so E2E suites can pin byte-for-byte equality; surfaces AM's `Some(metadata)` activation branch end-to-end. |
19//! | `deprovision_tenant` | Returns `Ok(())`. |
20//! | `provision_user` | Echoes the request as an `IdpUser` whose `id` is a deterministic `UUIDv5` derived from `(tenant_id, username)`, then records it in the per-tenant in-memory cache. |
21//! | `deprovision_user` | Removes the matching row from the per-tenant cache; collapses removed-and-already-absent to `Ok(())` per the SDK contract. |
22//! | `list_users` | Paginates the per-tenant cache, honouring the typed `OData` filter (`FilterNode<IdpUserFilterField>`) and order (`ODataOrderBy`) on the SPI request. Filtered point lookup (`$filter = id eq <uuid>`) returns either an empty page or a single-element page (the authoritative existence signal). Default order is `username ASC, id ASC` (with `id ASC` tiebreaker injected on caller-supplied orders too). Cursors are `toolkit_odata::CursorV1` key-tuple boundaries; mismatch between the cursor's encoded order and the request's effective order surfaces as `IdpUserOperationFailure::Rejected`, so a hostile / buggy client cannot smuggle state into the plugin. |
23//!
24//! ## State
25//!
26//! The plugin keeps a per-tenant `HashMap<user_id, IdpUser>` behind a
27//! `parking_lot::Mutex`. State lives in-process and is dropped on
28//! restart — matching the dev-only contract of every other
29//! `static-*-plugin`. A real `IdP` provider would persist this state
30//! upstream; AM consumes the same trait surface either way.
31//!
32//! ## Configuration
33//!
34//! ```yaml
35//! gears:
36//!   static-idp-plugin:
37//!     config:
38//!       vendor: "constructorfabric"
39//!       priority: 100
40//! ```
41#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
42
43pub mod config;
44pub mod domain;
45pub mod gear;
46
47pub use gear::StaticIdpPlugin;