Split orchestration by durable use case

This commit is contained in:
ms2k 2026-07-19 01:33:14 +09:00
commit fa81cb7f21
2 changed files with 609 additions and 513 deletions

View file

@ -16,6 +16,8 @@ use crate::types::{
};
use crate::vault::{EmptyPathFence, VaultClient};
mod query;
/// Durable source-credential registry with Vault-backed secret versions.
#[derive(Clone, Debug)]
pub struct CredentialRegistry {
@ -417,122 +419,6 @@ impl CredentialRegistry {
.ok_or_else(|| DurableError::Effect("revoked credential is missing".into()))
}
pub async fn get(
&self,
caller: &CredentialCaller,
credential_id: &OpaqueId,
) -> Result<Option<SourceCredential>, CredentialError> {
let record = self.get_internal(credential_id).await?;
match require_manage(caller, record.as_ref()) {
Ok(visible) => Ok(Some(visible)),
Err(CredentialError::NotFound) => Ok(None),
Err(error) => Err(error),
}
}
pub async fn list(
&self,
caller: &CredentialCaller,
limit: u32,
cursor: Option<&str>,
) -> Result<SourceCredentialPage, CredentialError> {
let limit = limit.clamp(1, 100) as i64;
let after = cursor.map(decode_cursor).transpose()?;
let owner_filter = if caller.administrator {
None
} else {
Some(caller.principal_id.as_str().to_owned())
};
let rows = if let Some(owner) = owner_filter.as_deref() {
if let Some((created_at, id)) = after {
sqlx::query_as::<_, CredentialRow>(
"SELECT c.credential_id, c.owner_id, c.label, c.kind, c.status,
c.created_at, c.updated_at,
v.version_id AS active_version_id, v.created_at AS active_version_created_at
FROM source_credentials c
LEFT JOIN source_credential_versions v
ON v.version_id = c.active_version_id
WHERE c.owner_id = $1
AND (c.created_at, c.credential_id) < ($2, $3)
ORDER BY c.created_at DESC, c.credential_id DESC
LIMIT $4",
)
.bind(owner)
.bind(created_at)
.bind(id)
.bind(limit + 1)
.fetch_all(&self.pool)
.await
.map_err(DurableError::from)?
} else {
sqlx::query_as::<_, CredentialRow>(
"SELECT c.credential_id, c.owner_id, c.label, c.kind, c.status,
c.created_at, c.updated_at,
v.version_id AS active_version_id, v.created_at AS active_version_created_at
FROM source_credentials c
LEFT JOIN source_credential_versions v
ON v.version_id = c.active_version_id
WHERE c.owner_id = $1
ORDER BY c.created_at DESC, c.credential_id DESC
LIMIT $2",
)
.bind(owner)
.bind(limit + 1)
.fetch_all(&self.pool)
.await
.map_err(DurableError::from)?
}
} else if let Some((created_at, id)) = after {
sqlx::query_as::<_, CredentialRow>(
"SELECT c.credential_id, c.owner_id, c.label, c.kind, c.status,
c.created_at, c.updated_at,
v.version_id AS active_version_id, v.created_at AS active_version_created_at
FROM source_credentials c
LEFT JOIN source_credential_versions v
ON v.version_id = c.active_version_id
WHERE (c.created_at, c.credential_id) < ($1, $2)
ORDER BY c.created_at DESC, c.credential_id DESC
LIMIT $3",
)
.bind(created_at)
.bind(id)
.bind(limit + 1)
.fetch_all(&self.pool)
.await
.map_err(DurableError::from)?
} else {
sqlx::query_as::<_, CredentialRow>(
"SELECT c.credential_id, c.owner_id, c.label, c.kind, c.status,
c.created_at, c.updated_at,
v.version_id AS active_version_id, v.created_at AS active_version_created_at
FROM source_credentials c
LEFT JOIN source_credential_versions v
ON v.version_id = c.active_version_id
ORDER BY c.created_at DESC, c.credential_id DESC
LIMIT $1",
)
.bind(limit + 1)
.fetch_all(&self.pool)
.await
.map_err(DurableError::from)?
};
let mut items: Vec<SourceCredential> = Vec::with_capacity(rows.len().min(limit as usize));
let mut next_cursor = None;
for (index, row) in rows.into_iter().enumerate() {
if index as i64 >= limit {
let last = items
.last()
.ok_or_else(|| CredentialError::Config("page overflow without items".into()))?;
next_cursor = Some(encode_cursor(last.created_at, last.id.as_str()));
break;
}
items.push(row.into_record()?);
}
Ok(SourceCredentialPage { items, next_cursor })
}
/// Pin the current authorized version for a new execution grant.
///
/// Serializes with revoke/rotate on the credential advisory lock so a

View file

@ -0,0 +1,119 @@
use super::*;
impl CredentialRegistry {
pub async fn get(
&self,
caller: &CredentialCaller,
credential_id: &OpaqueId,
) -> Result<Option<SourceCredential>, CredentialError> {
let record = self.get_internal(credential_id).await?;
match require_manage(caller, record.as_ref()) {
Ok(visible) => Ok(Some(visible)),
Err(CredentialError::NotFound) => Ok(None),
Err(error) => Err(error),
}
}
pub async fn list(
&self,
caller: &CredentialCaller,
limit: u32,
cursor: Option<&str>,
) -> Result<SourceCredentialPage, CredentialError> {
let limit = limit.clamp(1, 100) as i64;
let after = cursor.map(decode_cursor).transpose()?;
let owner_filter = if caller.administrator {
None
} else {
Some(caller.principal_id.as_str().to_owned())
};
let rows = if let Some(owner) = owner_filter.as_deref() {
if let Some((created_at, id)) = after {
sqlx::query_as::<_, CredentialRow>(
"SELECT c.credential_id, c.owner_id, c.label, c.kind, c.status,
c.created_at, c.updated_at,
v.version_id AS active_version_id, v.created_at AS active_version_created_at
FROM source_credentials c
LEFT JOIN source_credential_versions v
ON v.version_id = c.active_version_id
WHERE c.owner_id = $1
AND (c.created_at, c.credential_id) < ($2, $3)
ORDER BY c.created_at DESC, c.credential_id DESC
LIMIT $4",
)
.bind(owner)
.bind(created_at)
.bind(id)
.bind(limit + 1)
.fetch_all(&self.pool)
.await
.map_err(DurableError::from)?
} else {
sqlx::query_as::<_, CredentialRow>(
"SELECT c.credential_id, c.owner_id, c.label, c.kind, c.status,
c.created_at, c.updated_at,
v.version_id AS active_version_id, v.created_at AS active_version_created_at
FROM source_credentials c
LEFT JOIN source_credential_versions v
ON v.version_id = c.active_version_id
WHERE c.owner_id = $1
ORDER BY c.created_at DESC, c.credential_id DESC
LIMIT $2",
)
.bind(owner)
.bind(limit + 1)
.fetch_all(&self.pool)
.await
.map_err(DurableError::from)?
}
} else if let Some((created_at, id)) = after {
sqlx::query_as::<_, CredentialRow>(
"SELECT c.credential_id, c.owner_id, c.label, c.kind, c.status,
c.created_at, c.updated_at,
v.version_id AS active_version_id, v.created_at AS active_version_created_at
FROM source_credentials c
LEFT JOIN source_credential_versions v
ON v.version_id = c.active_version_id
WHERE (c.created_at, c.credential_id) < ($1, $2)
ORDER BY c.created_at DESC, c.credential_id DESC
LIMIT $3",
)
.bind(created_at)
.bind(id)
.bind(limit + 1)
.fetch_all(&self.pool)
.await
.map_err(DurableError::from)?
} else {
sqlx::query_as::<_, CredentialRow>(
"SELECT c.credential_id, c.owner_id, c.label, c.kind, c.status,
c.created_at, c.updated_at,
v.version_id AS active_version_id, v.created_at AS active_version_created_at
FROM source_credentials c
LEFT JOIN source_credential_versions v
ON v.version_id = c.active_version_id
ORDER BY c.created_at DESC, c.credential_id DESC
LIMIT $1",
)
.bind(limit + 1)
.fetch_all(&self.pool)
.await
.map_err(DurableError::from)?
};
let mut items: Vec<SourceCredential> = Vec::with_capacity(rows.len().min(limit as usize));
let mut next_cursor = None;
for (index, row) in rows.into_iter().enumerate() {
if index as i64 >= limit {
let last = items
.last()
.ok_or_else(|| CredentialError::Config("page overflow without items".into()))?;
next_cursor = Some(encode_cursor(last.created_at, last.id.as_str()));
break;
}
items.push(row.into_record()?);
}
Ok(SourceCredentialPage { items, next_cursor })
}
}