Skip to main content

arcp_core/messages/
credentials.rs

1//! Wire types for provisioned credentials (ARCP v1.1 §9.8).
2//!
3//! Issuance / revocation / ledger machinery is the runtime's job; what lives
4//! here are only the types that travel on the wire (`job.accepted`'s
5//! `credentials` array, `credential.revoke`, etc.).
6
7use serde::{Deserialize, Serialize};
8
9use crate::messages::permissions::LeaseRequest;
10
11/// Stable id for a runtime-issued provisioned credential.
12#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
13#[serde(transparent)]
14pub struct CredentialId(
15    /// Wire string.
16    pub String,
17);
18
19impl CredentialId {
20    /// Mint a credential id with the canonical `cred_` prefix.
21    #[must_use]
22    pub fn new(sequence: u64) -> Self {
23        Self(format!("cred_{sequence:016x}"))
24    }
25
26    /// Borrow the wire string.
27    #[must_use]
28    pub fn as_str(&self) -> &str {
29        &self.0
30    }
31}
32
33impl std::fmt::Display for CredentialId {
34    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35        f.write_str(&self.0)
36    }
37}
38
39/// Provisioned credential authentication scheme.
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
41#[serde(rename_all = "snake_case")]
42#[non_exhaustive]
43pub enum CredentialScheme {
44    /// HTTP bearer token.
45    Bearer,
46}
47
48/// Wire shape for a provisioned credential (ARCP v1.1 §9.8.1).
49#[derive(Clone, PartialEq, Serialize, Deserialize)]
50pub struct ProvisionedCredential {
51    /// Credential identifier.
52    pub id: CredentialId,
53    /// Authentication scheme.
54    pub scheme: CredentialScheme,
55    /// Secret value. This is intentionally redacted from [`Debug`].
56    pub value: String,
57    /// Upstream endpoint where the credential is valid.
58    pub endpoint: String,
59    /// Optional provider profile.
60    #[serde(default, skip_serializing_if = "Option::is_none")]
61    pub profile: Option<String>,
62    /// Lease constraints baked into the upstream credential.
63    #[serde(default, skip_serializing_if = "Option::is_none")]
64    pub constraints: Option<LeaseRequest>,
65}
66
67impl std::fmt::Debug for ProvisionedCredential {
68    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69        f.debug_struct("ProvisionedCredential")
70            .field("id", &self.id)
71            .field("scheme", &self.scheme)
72            .field("value", &"<redacted>")
73            .field("endpoint", &self.endpoint)
74            .field("profile", &self.profile)
75            .field("constraints", &self.constraints)
76            .finish()
77    }
78}