Skip to main content

secrets_core/
signing_keys.rs

1//! Helpers for storing and retrieving signing key references (no signing logic).
2//!
3//! URIs follow the shared scheme:
4//! `secrets://<env>/<tenant>/<team|_>/signing/{purpose}__key-ref`
5//! where `purpose` is one of build/attestation/sbom/generic.
6
7use crate::embedded::{SecretsCore, SecretsError};
8use crate::spec_compat::SecretUri;
9use crate::types::Scope;
10use greentic_types::{SigningKeyRef, TeamId, TenantCtx};
11use tracing::info;
12
13/// Supported signing purposes for key references.
14#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
15pub enum SigningPurpose {
16    Build,
17    Attestation,
18    Sbom,
19    Generic,
20}
21
22impl SigningPurpose {
23    fn as_name(self) -> &'static str {
24        match self {
25            SigningPurpose::Build => "build",
26            SigningPurpose::Attestation => "attestation",
27            SigningPurpose::Sbom => "sbom",
28            SigningPurpose::Generic => "generic",
29        }
30    }
31}
32
33/// Build the canonical URI for the given purpose.
34pub fn signing_key_ref_uri(
35    tenant: &TenantCtx,
36    purpose: SigningPurpose,
37) -> Result<SecretUri, SecretsError> {
38    let scope = scope_from_tenant(tenant)?;
39    let name = format!("{}__key-ref", purpose.as_name());
40    SecretUri::new(scope, "signing", name).map_err(SecretsError::from)
41}
42
43/// Fetch a signing key reference for the given tenant and purpose.
44pub async fn get_signing_key_ref(
45    core: &SecretsCore,
46    tenant: &TenantCtx,
47    purpose: SigningPurpose,
48) -> Result<SigningKeyRef, SecretsError> {
49    let uri = signing_key_ref_uri(tenant, purpose)?;
50    let res = core.get_json::<SigningKeyRef>(&uri.to_string()).await;
51    match &res {
52        Ok(value) => info!(
53            tenant = %tenant.tenant_id,
54            team = ?tenant.team,
55            purpose = %purpose.as_name(),
56            signing_key_ref = %value,
57            "retrieved signing key reference",
58        ),
59        Err(err) => info!(
60            tenant = %tenant.tenant_id,
61            team = ?tenant.team,
62            purpose = %purpose.as_name(),
63            error = %err,
64            "failed to retrieve signing key reference",
65        ),
66    }
67    res
68}
69
70fn scope_from_tenant(ctx: &TenantCtx) -> Result<Scope, SecretsError> {
71    let env = ctx.env.as_ref();
72    let tenant = ctx.tenant_id.as_ref();
73    let team = ctx.team.as_ref().or(ctx.team_id.as_ref()).map(|team| {
74        let t: &TeamId = team;
75        t.as_ref().to_string()
76    });
77    Scope::new(env, tenant, team).map_err(SecretsError::from)
78}