mkit_server/hooks/mod.rs
1//! Remote hooks: the `mkit.server.hooks.v1` adapter (SPEC-SERVER §§6-8),
2//! behind the `remote-hooks` feature.
3//!
4//! A deployment can run authorization, admission and outcome delivery in a
5//! separate service, such as a payment layer. This module holds the whole
6//! protocol except the transport:
7//!
8//! - [`HookChannel`] moves one Connect unary call (`POST <base>/<procedure>`,
9//! `application/json`, `Connect-Protocol-Version: 1`). The native HTTPS
10//! channel (WP-3.8) and the Workers binding (WP-3.9) will implement it.
11//! - [`HookSigner`] signs every request over its exact body bytes with the
12//! `mkit-hook:v1` domain, a fresh 32-byte nonce and a validity of at most
13//! 300 s. Only a channel that reports [`HookChannel::isolated`] (a service
14//! binding, §7.3) may go unsigned, and [`HookClient::new`] refuses anything
15//! else.
16//! - [`HookVerifier`] is the receiving side of that signature (a hook service's
17//! §7.1 checks), free of server-runtime dependencies.
18//! - [`RemoteAuthorizer`], [`RemoteAdmission`] and [`RemoteOutcomes`] share
19//! one [`HookClient`] and implement the stage traits, so any subset plugs
20//! into [`Hooks`](crate::pipeline::Hooks).
21//! - [`RemoteInspector`] implements synchronous inspection at stage 5. The
22//! pipeline owns complete inspected-set enumeration, batching and stable
23//! inspection ids.
24//!
25//! # Failure semantics
26//!
27//! Authorize, Admit and Inspect fail closed (§8): a transport error, timeout, non-2xx
28//! status, Connect error body, non-JSON content type, body over 64 KiB,
29//! malformed JSON, absent decision/verdict or a failed §6.6 check all answer
30//! retryable `unavailable` and write nothing. There is no retry inside a call.
31//! A deliberate `deny` in a 2xx answer is a decision, sanitised per §6.2. An
32//! Outcome is acknowledged by any 2xx; every other result is a
33//! [`DeliveryError`](crate::pipeline::DeliveryError) that kind 8 retries with
34//! backoff, signing each attempt afresh.
35//!
36//! # Credential safety
37//!
38//! Admit bodies carry admission credentials. Requests and responses are never
39//! logged or `Debug`-printed (the generated messages would print values), the
40//! request body is serialised once into an exactly sized `Zeroizing` buffer,
41//! the credential values of the message are wiped after the call, and every
42//! failure reason is a fixed string.
43//!
44//! # Not here
45//!
46//! The launch profile accepts synchronous fail-closed inspection only (§18).
47//! Async inspection belongs to WP-5.5c. Event belongs to WP-5.2.
48//! `AuthorizeAllow.writer_view` becomes `AuthzFacts::caller_view`, which the
49//! pipeline honours only under the `authority` role (§10.1). Reservation-id
50//! uniqueness is enforced per partition by the pipeline, while §6.6 asks for
51//! it per audience: uniqueness across partitions is the hook's obligation.
52
53mod channel;
54mod client;
55mod inspection;
56mod map;
57mod roles;
58mod sign;
59
60mod proto {
61 pub(super) use mkit_rpc::hooks as v1;
62}
63
64pub use channel::{ChannelError, HookChannel, HookRequest, HookResponse};
65pub use client::{DEFAULT_TIMEOUT, HookClient, HookConfigError, MAX_RESPONSE_BYTES};
66pub use inspection::{InspectVerdict, RemoteInspector};
67pub use mkit_rpc::hooks::{DEFAULT_VALIDITY, DOMAIN, HookSigner, MAX_VALIDITY, SignerError};
68pub use mkit_rpc::hooks::{
69 HookVerifier, KeyListError, MAX_CLOCK_LEAD_MS, Verified, VerifierKey, VerifyError,
70};
71pub use roles::{RemoteAdmission, RemoteAuthorizer, RemoteOutcomes, RemotePurge};
72pub use sign::{NonceSource, OsNonces};
73
74#[cfg(test)]
75pub(crate) mod tests;