Add durable credential registry and secret lifecycle

This commit is contained in:
ms2k 2026-07-17 00:18:02 +09:00
commit ac2289bd0a

View file

@ -0,0 +1,62 @@
use remora_domain::ports::{ActiveCredentialGrant, CredentialResolver};
use crate::error::CredentialError;
use crate::registry::CredentialRegistry;
use crate::types::SecretMaterial;
use crate::vault::VaultClient;
/// Grant-bound credential resolver.
///
/// Every resolve reloads durable execution-grant pin state. Unknown, revoked,
/// or destroyed pins fail closed. Callers cannot resolve by forging bare
/// credential/version IDs.
#[derive(Clone, Debug)]
pub struct GrantBoundResolver {
registry: CredentialRegistry,
vault: VaultClient,
}
impl GrantBoundResolver {
#[must_use]
pub fn new(registry: CredentialRegistry, vault: VaultClient) -> Self {
Self { registry, vault }
}
pub async fn resolve_access(
&self,
access: &ActiveCredentialGrant,
) -> Result<SecretMaterial, CredentialError> {
let pin = self
.registry
.load_active_grant_pin(access.grant_id())
.await?
.ok_or(CredentialError::GrantInactive)?;
let coord = self
.registry
.load_version_coord(&pin.credential_id, &pin.version_id)
.await?
.ok_or(CredentialError::Unresolvable)?;
if coord.destroyed {
return Err(CredentialError::Unresolvable);
}
self.vault
.get_version(
&coord.secret_mount,
&coord.secret_path,
coord.vault_kv_version,
)
.await
}
}
impl CredentialResolver for GrantBoundResolver {
type Error = CredentialError;
type Secret = SecretMaterial;
fn resolve(
&self,
access: &ActiveCredentialGrant,
) -> impl std::future::Future<Output = Result<Self::Secret, Self::Error>> + Send {
self.resolve_access(access)
}
}