Skip to main content

ppoppo_sdk_core/
lib.rs

1//! Ppoppo SDK shared primitives — internal mechanism for the
2//! Ppoppo SDK family (`pas-external`, future `pas-plims`, `pcs-external`).
3//!
4//! ## Stability — not a stable public API
5//!
6//! This crate is published to crates.io as a transitive dependency of
7//! the SDK family above (cargo enforces "all transitive deps of a
8//! published crate must themselves be published"). It is **not** a
9//! stable public API; it carries no SemVer guarantees beyond the
10//! current minor and may rearrange shapes between minors. Consume
11//! the SDK crates that re-export from it (`pas-external::*`,
12//! eventually `pas-plims::*` / `pcs-external::*`); do not depend on
13//! `ppoppo-sdk-core` directly from a 3rd-party application.
14//!
15//! Phase A foundation (RFC `RFC_2026-05-08_app-credential-collapse.md`)
16//! — collapses the verifier port + audit trait + session-liveness port +
17//! discovery primitive + perimeter Bearer-auth Layer kit + identity
18//! types out of `pas-external` so multiple SDK crates and 1st-party
19//! services (chat-auth, chat-api) all consume the same primitives.
20//!
21//! ## Surface (Slice 1a)
22//!
23//! - `error::SdkCoreError` — narrow error type for sdk-core primitives.
24//! - `types::{Ppnum, PpnumId, SessionId, UserId, KeyId}` — SDK-shared
25//!   identity types. `Ppnum::TryFrom<String>` is the validated boundary.
26//! - `audit::*` — `AuditSink` trait + `AuditEvent` + `VerifyErrorKind` +
27//!   `IdTokenFailureKind` + `RateLimiter` trait + `RateLimitKey` +
28//!   `compose_source_id` + `compose_id_token_source_id`. Plus the
29//!   in-tree utility impls (`NoopAuditSink`, `MemoryAuditSink`,
30//!   `MemoryRateLimiter`, `RateLimitedAuditSink`) — utility impls live
31//!   here too because the audit module is one cohesive unit.
32//! - `session_liveness::{SessionLiveness, SessionLivenessError}` —
33//!   per-request L2 row liveness port. Wired into the verifier slot.
34//!   Trait-only (no `cipher`/`liveness` AES wrapper code — that stays
35//!   in pas-external as a feature-gated submodule).
36//!
37//! ## Surface (Slice 1b — populated when verifier cohesive group lands)
38//!
39//! - `verifier::*` — `BearerVerifier` trait + `JwtVerifier` impl +
40//!   `MemoryBearerVerifier` + `VerifiedClaims` + `VerifyConfig` +
41//!   `VerifyError` + `JwksCache`. Audit decision E (cohesive group —
42//!   no trait/impl split across crates).
43//!
44//! ## Surface (Slice 2 — populated)
45//!
46//! - `discovery::{Discovery, DiscoveryError, fetch_discovery}` — OIDC
47//!   discovery document fetch (`<issuer>/.well-known/openid-configuration`).
48//!   RFC 8414 §3.3 issuer-mismatch defense lives here. Gated on
49//!   `well-known-fetch` (HTTP fetch + URL types).
50//!
51//! ## Surface (Slice 4 — populated)
52//!
53//! - `bearer::*` — perimeter Bearer-auth Layer kit. `AuthProvider<S>`
54//!   port + `BearerAuthLayer<Sess, P>` tower::Layer + `BearerAuthConfig`
55//!   + `VerifyError` + `MemoryAuthProvider<S>` (test-support). Gated on
56//!   `axum` feature. 1st-party services (chat-auth) import direct from
57//!   `ppoppo_sdk_core::bearer::*` (audit decision B); 3rd-party
58//!   consumers (RCW/CTW) reach the same kit through
59//!   `pas_external::bearer::*` re-export (audit decision D).
60//!
61//! ## Surface (Phase E — populated)
62//!
63//! - `token_cache::{TokenCache, TokenCacheConfig, TokenSource, TokenCacheError,
64//!   ClientCredentialsSource}` — JWT retention layer with single-flight
65//!   refresh. `TokenCache` owns a `Box<dyn TokenSource>`; the built-in
66//!   `ClientCredentialsSource` covers the OAuth2 `client_credentials` grant.
67//!   Gated on `token-cache` (cache+trait) and `client-credentials` (HTTP source).
68//! - `interceptor::{AuthInterceptor, BearerCredential}` — tonic sync
69//!   `Interceptor` that attaches `Authorization: Bearer <token>` per outgoing
70//!   gRPC call. Constructed from a pre-fetched `BearerCredential` (one instance
71//!   per call). Gated on `tonic-interceptor`.
72//!
73//! ## Out of scope (later phases)
74//!
75//! - `scopes::*` — sealed-trait family parent for SDK-specific scope marker types.
76
77#![deny(rust_2018_idioms)]
78
79pub mod audit;
80#[cfg(feature = "axum")]
81pub mod bearer;
82#[cfg(feature = "well-known-fetch")]
83pub mod discovery;
84pub mod error;
85#[cfg(feature = "tonic-interceptor")]
86pub mod interceptor;
87pub mod session_liveness;
88#[cfg(feature = "token-cache")]
89pub mod token_cache;
90pub mod types;
91pub mod verifier;
92
93// Top-level re-exports — keep narrow (≤ 25 public names budget for Phase A).
94pub use error::SdkCoreError;
95pub use types::{KeyId, Ppnum, PpnumId, SessionId, UserId};
96pub use session_liveness::{SessionLiveness, SessionLivenessError};
97pub use audit::{
98    AuditEvent, AuditSink, IdTokenFailureKind, MemoryRateLimiter, NoopAuditSink, RateLimitKey,
99    RateLimitedAuditSink, RateLimiter, VerifyErrorKind, compose_id_token_source_id,
100    compose_source_id,
101};
102#[cfg(any(test, feature = "test-support"))]
103pub use audit::MemoryAuditSink;
104
105// Verifier cohesive group (audit decision E + G).
106pub use verifier::{BearerVerifier, VerifiedClaims, VerifyConfig, VerifyError};
107#[cfg(feature = "well-known-fetch")]
108pub use verifier::{JwksCache, JwtVerifier};
109#[cfg(any(test, feature = "test-support"))]
110pub use verifier::MemoryBearerVerifier;
111
112// Discovery primitive (Slice 2).
113#[cfg(feature = "well-known-fetch")]
114pub use discovery::{Discovery, DiscoveryError, fetch_discovery};
115
116// NOTE: bearer kit (`AuthProvider`, `BearerAuthLayer`, `BearerAuthConfig`,
117// `VerifyError`, `MemoryAuthProvider`) is intentionally NOT flat-re-exported
118// at the crate root. The bearer-side `VerifyError` would collide with the
119// verifier-side `VerifyError`; rather than rename one, consumers import
120// through the explicit `ppoppo_sdk_core::bearer::*` module path so the
121// "this is the perimeter Layer kit, not the token verifier" semantic is
122// visible at the import site (audit decision F — flat module under bearer
123// itself; keep parent namespaces clean).