pub struct BrokerState { /* private fields */ }Expand description
The shared broker state: the loaded policy surface plus the backend manager.
Construct once with BrokerState::new and wrap in an Arc; the accept loop
clones the Arc into every connection handler.
Implementations§
Source§impl BrokerState
impl BrokerState
Sourcepub fn new(
catalog: Catalog,
policy: ResolvedPolicy,
config: Config,
manager: BackendManager,
backend_label: impl Into<String>,
) -> Self
pub fn new( catalog: Catalog, policy: ResolvedPolicy, config: Config, manager: BackendManager, backend_label: impl Into<String>, ) -> Self
Bundle the loaded policy surface (the load() 4-tuple’s first three
elements) with an already-constructed BackendManager.
backend_label is the name a status response advertises (the backend
kind(); with one backend today this is unambiguous). The manager is built
separately because building backends from credentials is the binary’s job
(vault-vh1); this layer only routes + authorizes.
Sourcepub fn with_limits(
catalog: impl Into<Arc<Catalog>>,
policy: ResolvedPolicy,
config: Config,
manager: BackendManager,
backend_label: impl Into<String>,
limits: BrokerLimits,
) -> Self
pub fn with_limits( catalog: impl Into<Arc<Catalog>>, policy: ResolvedPolicy, config: Config, manager: BackendManager, backend_label: impl Into<String>, limits: BrokerLimits, ) -> Self
Like BrokerState::new but with explicit broker BrokerLimits (the
AEAD payload cap + rotation grace/retention policy the binary threads from
its args). BrokerState::new uses BrokerLimits::default.
Sourcepub fn with_audit_log(self, audit: Arc<AuditLog>) -> Self
pub fn with_audit_log(self, audit: Arc<AuditLog>) -> Self
Attach a JSONL audit sink (vault-vq5), consuming and returning self.
When set, BrokerState::audit appends one JSONL line per recorded
decision to the open append-only file; when this is never called, file
audit is disabled (tracing still logs every decision). The binary opens
the file once at startup and threads the AuditLog in here.
Sourcepub fn with_jwt_revocations(self, jwt_revocations: JwtRevocationStore) -> Self
pub fn with_jwt_revocations(self, jwt_revocations: JwtRevocationStore) -> Self
Attach the JWT-SVID revocation deny-list loaded at startup.
Sourcepub fn with_version(self, version: impl Into<String>) -> Self
pub fn with_version(self, version: impl Into<String>) -> Self
Set the broker software version reported by status/health.
The binary (basil-bin) passes its own env!("CARGO_PKG_VERSION") so the
served version follows the shipped basil binary rather than this
library crate. Without this, the version defaults to basil-core’s.
Sourcepub fn with_reload_inputs(self, inputs: ReloadInputs) -> Self
pub fn with_reload_inputs(self, inputs: ReloadInputs) -> Self
Record the configured on-disk catalog/policy paths so the SIGHUP reload
engine (basil-y3e.2) can re-read from the same paths startup used.
Without this, BrokerState::reload_inputs is None and a reload fails
closed with ReloadError::NoInputs (a SIGHUP then only reopens the audit
log). The broker never reads catalog/policy from an unconfigured source.
Sourcepub const fn reload_inputs(&self) -> Option<&ReloadInputs>
pub const fn reload_inputs(&self) -> Option<&ReloadInputs>
The configured catalog/policy paths the reload engine re-reads, if any.
Sourcepub const fn reload_lock(&self) -> &Mutex<()>
pub const fn reload_lock(&self) -> &Mutex<()>
The lock the reload engine holds across its whole validate→swap sequence, so concurrent triggers (SIGHUP + admin RPC) apply strictly one at a time and generation ids stay monotonic with no lost update.
Sourcepub fn active_generation_id(&self) -> u64
pub fn active_generation_id(&self) -> u64
The id of the currently serving generation (observable for the status
probe, basil-s7h, and the reload audit). A monotonic counter bumped on
each successful reload.
Sourcepub fn cached_readiness(&self) -> Option<ReadinessOutcome>
pub fn cached_readiness(&self) -> Option<ReadinessOutcome>
Return the cached readiness outcome if one was computed for the
currently-serving generation within READINESS_CACHE_TTL (basil-8nwy).
A cache hit lets the admin Readiness RPC answer without re-fanning-out
one backend read per catalog key: the amplification a hostile, ungated
socket peer could otherwise drive. The entry is bypassed (re-probe required)
when it has expired or when the serving generation has changed since it
was cached, so a hot reload that alters the key set can never be masked
longer than it takes to recompute, and a stale generation’s counts are never
served. Returns None to mean “no usable cache; probe the backend”.
The returned outcome is generation-independent; the caller stamps the current generation id onto the wire response.
Sourcepub fn cache_readiness(&self, generation: u64, outcome: ReadinessOutcome)
pub fn cache_readiness(&self, generation: u64, outcome: ReadinessOutcome)
Store a freshly-computed readiness outcome for generation, valid for
READINESS_CACHE_TTL from now (basil-8nwy). A subsequent
BrokerState::cached_readiness within that window (and on the same
generation) reuses it instead of re-probing the backend.
A poisoned lock is swallowed (the cache is a best-effort optimization, never a correctness or liveness dependency): the worst case is a missed cache and one extra probe, never a panic on the serving path.
Sourcepub fn cached_jwks(&self) -> Option<CachedJwks>
pub fn cached_jwks(&self) -> Option<CachedJwks>
Return the cached JWKS document for the currently-serving generation.
Sourcepub fn cache_jwks(&self, generation: u64, body: Vec<u8>, etag: String)
pub fn cache_jwks(&self, generation: u64, body: Vec<u8>, etag: String)
Store a freshly-built JWKS document for generation.
Sourcepub fn swap_generation(&self, generation: Arc<Generation>)
pub fn swap_generation(&self, generation: Arc<Generation>)
Atomically swap in a new Generation, replacing the currently serving
one. The only mutation point of the reloadable policy surface.
Callers (the reload engine, basil-y3e.2) must have already validated the
new generation; this is the unconditional store. In-flight operations that
pinned the previous generation via BrokerState::load_generation keep
seeing it until they drop their guard. The swap never disturbs an op
already in progress.
Sourcepub fn load_generation(&self) -> Guard<Arc<Generation>>
pub fn load_generation(&self) -> Guard<Arc<Generation>>
Snapshot the active Generation for the lifetime of one operation.
This is the one point an RPC pins its generation: call it once at
request entry, then drive the whole op off the returned guard
(Generation::pdp, Generation::config, Generation::id) so the
(catalog, policy, config) triple stays coherent even if a concurrent
reload swaps in a newer generation mid-op. Hold the guard only as long as
the op needs it (it pins the snapshot from being reclaimed); if the
snapshot must survive an .await, clone the inner Arc out of the guard
rather than holding the guard across the suspension point.
Sourcepub fn record_decision(&self, record: &DecisionRecord)
pub fn record_decision(&self, record: &DecisionRecord)
Record one authorization decision (vault-vq5): emit it to tracing
(allow=info, deny=warn) and, when a JSONL audit sink is configured,
append it as one line to the append-only audit file.
The file append is best-effort: an IO error is logged and swallowed by
the sink so an audit-disk problem can never block, deny, or panic the data
plane: the trustworthy decision already happened and is in tracing. This
is the single hook the handler calls for every gated op, allow or deny.
Sourcepub fn record_provider_event(&self, event: &ProviderAuditEvent<'_>)
pub fn record_provider_event(&self, event: &ProviderAuditEvent<'_>)
Record one software-custody provider operation (wuj.7): emit it to
tracing (failure/deny at warn, allow/success at info) and, when a
JSONL audit sink is configured, append the secret-free
ProviderAuditEvent JSON as one line. The event carries the selected
provider and algorithm and never any seed, signature, plaintext, or
ciphertext bytes. Best-effort like Self::record_decision: it can never
block, fail, or panic the data plane.
Sourcepub fn record_reload(
&self,
previous_generation: u64,
new_generation: u64,
outcome: &str,
reason: &str,
actor: ReloadActor,
)
pub fn record_reload( &self, previous_generation: u64, new_generation: u64, outcome: &str, reason: &str, actor: ReloadActor, )
Record a generation reload outcome (basil-y3e.2, basil-atq): emit it to
tracing and, when a JSONL audit sink is configured, append one
basil.audit.reload line.
outcome is one of "applied" (a real swap happened, logged at info),
"checked" (an admin --check dry-run validated, no swap, info), or
"rejected" (the candidate failed; previous generation keeps serving,
warn). reason is a short, stable, non-secret token (e.g. signal,
admin_rpc, or a ReloadError audit token).
actor attributes the trigger (ReloadActor::Sighup for the signal path
or ReloadActor::Caller with the attested uid for the admin RPC), the
only field that differs in the audit trail between an otherwise-identical
SIGHUP and RPC reload (basil-ftmc). Like BrokerState::record_decision,
the file append is best-effort and can never block, fail, or panic the broker.
Sourcepub const fn manager(&self) -> &BackendManager
pub const fn manager(&self) -> &BackendManager
The backend manager that routes an allowed op to its backend instance.
Sourcepub fn backend_label(&self) -> &str
pub fn backend_label(&self) -> &str
The backend label advertised in a status response.
Sourcepub fn agent_version(&self) -> &str
pub fn agent_version(&self) -> &str
The broker software version advertised in status/health responses.
Sourcepub const fn limits(&self) -> BrokerLimits
pub const fn limits(&self) -> BrokerLimits
The broker-wide payload caps + rotation grace/retention policy.
Sourcepub const fn events(&self) -> &EventSource
pub const fn events(&self) -> &EventSource
Shared broker event source.
Sourcepub const fn jwt_revocations(&self) -> &JwtRevocationStore
pub const fn jwt_revocations(&self) -> &JwtRevocationStore
JWT-SVID revocation deny-list shared by Workload API validation.
Sourcepub async fn refresh_jwt_revocations(&self) -> Result<(), ManagerError>
pub async fn refresh_jwt_revocations(&self) -> Result<(), ManagerError>
Re-read the catalog-backed JWT-SVID deny-list and merge it into memory.
This stays outside the hot-swapped Generation: the deny-list is mutable
serving state, and refresh uses union semantics so a live revocation cannot
be clobbered by a concurrent reload.
§Errors
Returns ManagerError if the configured store is malformed, unreadable,
or the live deny-list locks are poisoned. On error the previous in-memory
set remains serving.
Sourcepub async fn revoke_jwt_svid(
&self,
trust_domain: &str,
jti: &str,
expires_at_unix: u64,
) -> Result<(), ManagerError>
pub async fn revoke_jwt_svid( &self, trust_domain: &str, jti: &str, expires_at_unix: u64, ) -> Result<(), ManagerError>
Persist and publish a JWT-SVID revocation.
§Errors
Returns crate::manager::ManagerError if the optional catalog-backed
deny-list write fails.
Trait Implementations§
Auto Trait Implementations§
impl !Freeze for BrokerState
impl !RefUnwindSafe for BrokerState
impl !UnwindSafe for BrokerState
impl Send for BrokerState
impl Sync for BrokerState
impl Unpin for BrokerState
impl UnsafeUnpin for BrokerState
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request