Skip to main content

chio_api_protect/proxy/
config.rs

1use super::*;
2use std::time::Duration;
3
4/// Default wall-clock ceiling on a single upstream proxy hop, including reading
5/// the full response body. Kept below the serve site's drain window so an
6/// in-flight hop is resolved and receipted before a shutdown force-closes the
7/// connection.
8pub const DEFAULT_UPSTREAM_REQUEST_TIMEOUT: Duration = Duration::from_secs(20);
9
10/// Configuration for the protect proxy.
11pub struct ProtectConfig {
12    /// Upstream URL to proxy to.
13    pub upstream: String,
14    /// Optional in-memory OpenAPI spec content (YAML or JSON).
15    pub spec_content: Option<String>,
16    /// Optional OpenAPI spec path. When omitted, the proxy auto-discovers the spec.
17    pub spec_path: Option<String>,
18    /// Address to listen on (e.g., "127.0.0.1:9090").
19    pub listen_addr: String,
20    /// Optional SQLite path for receipt persistence.
21    pub receipt_db: Option<String>,
22    /// Explicit opt-in to run without a durable receipt store. A durable audit
23    /// log is the product's core promise, so a `None` `receipt_db` is refused at
24    /// startup unless this is set, mirroring the CLI boot gate. When set, the
25    /// proxy runs with in-memory receipts and revocations that are lost on every
26    /// restart. Leave it `false` for durable-by-default embedding.
27    pub allow_ephemeral_receipts: bool,
28    /// Optional bearer token that authorizes remote sidecar control requests.
29    pub sidecar_control_token: Option<String>,
30    /// Optional seed used to keep the sidecar signer stable across restarts.
31    pub signer_seed_hex: Option<String>,
32    /// Explicit capability issuers trusted by the HTTP authority.
33    pub trusted_capability_issuers: Vec<PublicKey>,
34    /// Control-plane URL. When set, budget holds go through a `RemoteBudgetStore`.
35    pub control_url: Option<String>,
36    /// Bearer token for the control-plane budget endpoints.
37    pub control_token: Option<String>,
38    /// Local SQLite budget-store path used when no `control_url` is configured.
39    pub budget_db: Option<String>,
40    /// Optional durable SQLite revocation-store path. When set, the sidecar
41    /// loads its revoked capability ids at startup so operator revocations
42    /// recorded through `chio trust revoke --revocation-db <path>` are enforced
43    /// on `/v1/evaluate` and every other path that consults the revoked set.
44    /// Opening or reading a configured store that fails is fatal (fail-closed):
45    /// the sidecar refuses to start rather than run without the revocations it
46    /// was told to enforce.
47    pub revocation_db: Option<String>,
48    /// Retained for API compatibility. The kernel-mediated `/v1/evaluate`
49    /// route is a pre-execution authorization gate and always runs the
50    /// mediation kernel in execution-nonce strict mode, so this flag no
51    /// longer changes mediation behavior.
52    pub require_nonce: bool,
53    /// When true, the `/v1/evaluate/advisory` route is active.
54    /// Defaults to false; production deployments should leave this off to
55    /// prevent agents from receiving advisory receipts and bypassing the
56    /// kernel-mediated route.
57    pub allow_advisory: bool,
58    /// Wall-clock ceiling on a single upstream proxy hop, including reading the
59    /// full response body. Raise it for upstreams with legitimately slow calls or
60    /// large bounded responses; the serve site widens its drain window to match so
61    /// an in-flight hop is still receipted before shutdown force-closes it.
62    /// Defaults to [`DEFAULT_UPSTREAM_REQUEST_TIMEOUT`].
63    pub upstream_request_timeout: Duration,
64}
65
66impl std::fmt::Debug for ProtectConfig {
67    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68        f.debug_struct("ProtectConfig")
69            .field("upstream", &self.upstream)
70            .field(
71                "spec_content",
72                &self.spec_content.as_ref().map(|_| "<inline>"),
73            )
74            .field("spec_path", &self.spec_path)
75            .field("listen_addr", &self.listen_addr)
76            .field("receipt_db", &self.receipt_db)
77            .field("allow_ephemeral_receipts", &self.allow_ephemeral_receipts)
78            .field(
79                "sidecar_control_token",
80                &self.sidecar_control_token.as_ref().map(|_| "<redacted>"),
81            )
82            .field(
83                "signer_seed_hex",
84                &self.signer_seed_hex.as_ref().map(|_| "<redacted>"),
85            )
86            .field(
87                "trusted_capability_issuers",
88                &self.trusted_capability_issuers,
89            )
90            .field("control_url", &self.control_url)
91            .field("budget_db", &self.budget_db)
92            .field("revocation_db", &self.revocation_db)
93            .field("require_nonce", &self.require_nonce)
94            .field("allow_advisory", &self.allow_advisory)
95            .field("upstream_request_timeout", &self.upstream_request_timeout)
96            .finish()
97    }
98}