Skip to main content

systemprompt_security/credential/
error.rs

1//! Everything that can go wrong between a stored secret and an auth header.
2//!
3//! The variants are typed so that callers can branch, but their `Display`
4//! text is load-bearing too: the gateway relays it into a `PreAudit` dispatch
5//! error and an operator reads it in a log line. So each message names the
6//! thing an operator can change — the secret, the key inside it, the token
7//! endpoint — and never the value of any of them.
8//!
9//! Copyright (c) systemprompt.io — Business Source License 1.1.
10//! See <https://systemprompt.io> for licensing details.
11
12use std::sync::Arc;
13
14use thiserror::Error;
15
16/// A credential could not be parsed, scoped, or exchanged for a header.
17#[derive(Debug, Error)]
18pub enum CredentialError {
19    #[error("service-account key is malformed: {0}")]
20    Malformed(#[source] serde_json::Error),
21
22    #[error(
23        "endpoint '{endpoint}' needs a {field} to fill `{placeholder}`, but the secret is not a \
24         service-account key (no project_id or region to fill it from)"
25    )]
26    MissingScope {
27        endpoint: String,
28        field: &'static str,
29        placeholder: &'static str,
30    },
31
32    #[error("service-account private_key is not a valid RSA PEM: {0}")]
33    SigningKey(#[source] jsonwebtoken::errors::Error),
34
35    #[error("could not sign the assertion: {0}")]
36    Sign(#[source] jsonwebtoken::errors::Error),
37
38    #[error("system clock is before the unix epoch: {0}")]
39    Clock(#[source] std::time::SystemTimeError),
40
41    #[error("could not build the token-exchange client: {0}")]
42    Client(#[source] Arc<reqwest::Error>),
43
44    #[error("token endpoint {uri} unreachable: {source}")]
45    Unreachable {
46        uri: String,
47        #[source]
48        source: reqwest::Error,
49    },
50
51    #[error("token endpoint returned {status}: {body}")]
52    Rejected { status: String, body: String },
53
54    #[error("token endpoint returned an unreadable body: {0}")]
55    UnreadableBody(#[source] serde_json::Error),
56}