Skip to main content

systemprompt_models/profile/
governance.rs

1//! Governance configuration for the gateway + MCP authorization hook.
2//!
3//! Authz is **fail-closed** with an explicit-opt-in surface. Four modes:
4//!
5//! - `webhook` — production. Core POSTs every request to the configured URL;
6//!   any transport error, non-2xx, or decode failure denies the request.
7//! - `extension` — production. The hook is supplied at bootstrap by the binary
8//!   via `AppContextBuilder::with_authz_hook(...)`. Bootstrap errors if no hook
9//!   is supplied. See `internal/guides/authz.md`.
10//! - `disabled` — denies every request via `DenyAllHook`. Use when authz is
11//!   intentionally inactive but you want the surface installed.
12//! - `unrestricted` — TEST/DEV ONLY. Allows every request via `AllowAllHook`.
13//!   Requires `acknowledgement` to equal the literal sentence `"I understand
14//!   this disables all authorization"`. Bootstrap errors otherwise.
15//!
16//! Absent `governance` block, absent `authz`, or any unparseable config →
17//! bootstrap installs `DenyAllHook` (everything denied) so misconfiguration
18//! never silently grants access.
19//!
20//! Example:
21//!
22//! ```yaml
23//! governance:
24//!   authz:
25//!     hook:
26//!       mode: webhook
27//!       url: http://localhost:8080/api/public/govern/authz
28//!       timeout_ms: 500
29//! ```
30//!
31//! Copyright (c) systemprompt.io — Business Source License 1.1.
32//! See <https://systemprompt.io> for licensing details.
33
34use serde::{Deserialize, Serialize};
35
36pub const UNRESTRICTED_ACKNOWLEDGEMENT: &str = "I understand this disables all authorization";
37
38#[derive(Debug, Clone, Default, Serialize, Deserialize, schemars::JsonSchema)]
39#[serde(deny_unknown_fields)]
40pub struct GovernanceConfig {
41    #[serde(default)]
42    pub authz: Option<AuthzConfig>,
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
46#[serde(deny_unknown_fields)]
47pub struct AuthzConfig {
48    pub hook: AuthzHookConfig,
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
52#[serde(rename_all = "lowercase")]
53pub enum AuthzMode {
54    Webhook,
55    Extension,
56    Disabled,
57    Unrestricted,
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
61#[serde(deny_unknown_fields)]
62pub struct AuthzHookConfig {
63    pub mode: AuthzMode,
64    #[serde(default)]
65    pub url: Option<String>,
66    #[serde(default = "default_timeout_ms")]
67    pub timeout_ms: u64,
68    #[serde(default)]
69    pub acknowledgement: Option<String>,
70}
71
72const fn default_timeout_ms() -> u64 {
73    500
74}