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 thiserror::Error;
13
14/// A credential could not be parsed, scoped, or exchanged for a header.
15#[derive(Debug, Error)]
16pub enum CredentialError {
17    #[error("service-account key is malformed: {0}")]
18    Malformed(String),
19
20    #[error(
21        "endpoint '{endpoint}' needs a {field} to fill `{placeholder}`, but the secret is not a \
22         service-account key (no project_id or region to fill it from)"
23    )]
24    MissingScope {
25        endpoint: String,
26        field: &'static str,
27        placeholder: &'static str,
28    },
29
30    #[error("service-account private_key is not a valid RSA PEM: {0}")]
31    SigningKey(String),
32
33    #[error("could not sign the assertion: {0}")]
34    Sign(String),
35
36    #[error("system clock is before the unix epoch: {0}")]
37    Clock(String),
38
39    #[error("could not build the token-exchange client: {0}")]
40    Client(String),
41
42    #[error("token endpoint {uri} unreachable: {reason}")]
43    Unreachable { uri: String, reason: String },
44
45    #[error("token endpoint returned {status}: {body}")]
46    Rejected { status: String, body: String },
47
48    #[error("token endpoint returned an unreadable body: {0}")]
49    UnreadableBody(String),
50}