systemprompt_security/authz/
error.rs1use systemprompt_models::domain_error;
7use thiserror::Error;
8
9domain_error! {
10 pub enum AuthzError {
11 common: [repository, validation],
12
13 #[error("invalid rule_type: {0}")]
14 InvalidRuleType(String),
15
16 #[error("invalid access value: {0}")]
17 InvalidAccess(String),
18
19 #[error("unknown entity_type: {0}")]
20 UnknownEntityKind(String),
21
22 #[error("unknown access scope: {0}")]
23 UnknownAccessScope(String),
24
25 #[error(
26 "refusing to reconcile the gateway_route catalog against an empty route set — this \
27 would delete every route entity and cascade away every route grant; check that the \
28 profile actually declares a gateway"
29 )]
30 EmptyGatewayRouteSet,
31
32 #[error("authz hook transport: {0}")]
33 Hook(#[from] reqwest::Error),
34
35 #[error("authz bootstrap: {0}")]
36 Bootstrap(#[from] AuthzBootstrapError),
37
38 #[error("failed to {action} {path}: {source}")]
39 File {
40 action: &'static str,
41 path: String,
42 #[source]
43 source: std::io::Error,
44 },
45
46 #[error("failed to parse {path} as AccessControlConfig: {source}")]
47 ConfigParse {
48 path: String,
49 #[source]
50 source: serde_yaml::Error,
51 },
52
53 #[error(
54 "marketplace '{marketplace}': access.rules rule_type '{rule_type}' is not a valid \
55 subject dimension: {source}"
56 )]
57 MarketplaceRuleType {
58 marketplace: String,
59 rule_type: String,
60 #[source]
61 source: Box<AuthzError>,
62 },
63
64 #[error("invalid entity id: {0}")]
65 InvalidEntityId(#[source] systemprompt_identifiers::error::IdValidationError),
66 }
67}
68
69impl From<sqlx::Error> for AuthzError {
70 fn from(err: sqlx::Error) -> Self {
71 Self::Repository(systemprompt_models::errors::RepositoryError::from(err))
72 }
73}
74
75pub type AuthzResult<T> = Result<T, AuthzError>;
76
77#[derive(Debug, Error)]
78pub enum AuthzBootstrapError {
79 #[error(
80 "governance.authz.hook.mode = webhook but `url` is missing or blank — refusing to start"
81 )]
82 MissingWebhookUrl,
83
84 #[error("governance.authz.hook.url is invalid or unsafe: {0} — refusing to start")]
85 InvalidWebhookUrl(#[source] systemprompt_models::net::OutboundUrlError),
86
87 #[error(
88 "governance.authz.hook.mode = unrestricted requires `acknowledgement` field equal to the \
89 literal: {expected:?}"
90 )]
91 MissingUnrestrictedAcknowledgement { expected: &'static str },
92
93 #[error(
94 "governance.authz.hook.mode = extension but no extension hook was supplied via \
95 AppContextBuilder::with_authz_hook(...) — refusing to start"
96 )]
97 ExtensionModeButNoHook,
98
99 #[error(
100 "an extension authz hook was supplied via AppContextBuilder::with_authz_hook(...) but \
101 governance.authz.hook.mode is `{mode}` (must be `extension`) — refusing to start"
102 )]
103 ExtensionHookButWrongMode { mode: &'static str },
104
105 #[error(
106 "an extension authz hook was supplied via AppContextBuilder::with_authz_hook(...) but the \
107 profile has no `governance.authz` block — set `governance.authz.hook.mode = extension` \
108 or drop the `with_authz_hook` call"
109 )]
110 NoGovernanceButExtensionHook,
111}