core: type workspace and secret timestamps

This commit is contained in:
a.tolmachev
2026-04-13 05:59:11 +00:00
parent 03cb109b40
commit c736b4f5a8
17 changed files with 243 additions and 139 deletions
+17 -18
View File
@@ -870,14 +870,14 @@ impl AdminService {
user_id: &crank_core::UserId,
payload: WorkspacePayload,
) -> Result<WorkspaceRecord, ApiError> {
let now = now_string()?;
let now = OffsetDateTime::now_utc();
let workspace = Workspace {
id: WorkspaceId::new(new_prefixed_id("ws")),
slug: payload.slug,
display_name: payload.display_name,
status: WorkspaceStatus::Active,
settings: payload.settings,
created_at: now.clone(),
created_at: now,
updated_at: now,
};
@@ -1034,7 +1034,7 @@ impl AdminService {
status: payload.status.unwrap_or(existing.status),
settings: payload.settings.unwrap_or(existing.settings),
created_at: existing.created_at,
updated_at: now_string()?,
updated_at: OffsetDateTime::now_utc(),
};
self.registry
@@ -1183,10 +1183,10 @@ impl AdminService {
status: InvitationStatus::Pending,
token_hash: hash_access_secret(&invite_token),
expires_at: match payload.expires_at {
Some(expires_at) => expires_at,
Some(expires_at) => parse_timestamp(&expires_at)?,
None => default_invitation_expiry()?,
},
created_at: now_string()?,
created_at: OffsetDateTime::now_utc(),
},
};
@@ -2362,9 +2362,7 @@ impl AdminService {
auth_profile: &AuthProfile,
) -> Result<ResolvedAuth, RuntimeError> {
let mut secrets = BTreeMap::new();
let used_at = now_string().map_err(|error| RuntimeError::SecretCrypto {
details: error.to_string(),
})?;
let used_at = OffsetDateTime::now_utc();
for secret_id in auth_profile.config.secret_ids() {
let secret = self
@@ -2451,7 +2449,7 @@ impl AdminService {
self.ensure_workspace_exists(workspace_id).await?;
validate_secret_payload(&payload)?;
let now = now_string()?;
let now = OffsetDateTime::now_utc();
let secret = Secret {
id: SecretId::new(new_prefixed_id("secret")),
workspace_id: workspace_id.clone(),
@@ -2459,7 +2457,7 @@ impl AdminService {
kind: payload.kind,
status: SecretStatus::Active,
current_version: 1,
created_at: now.clone(),
created_at: now,
updated_at: now,
last_used_at: None,
};
@@ -2494,7 +2492,7 @@ impl AdminService {
return Err(ApiError::validation("secret value must not be null"));
}
let now = now_string()?;
let now = OffsetDateTime::now_utc();
let ciphertext = self
.secret_crypto
.encrypt(&payload.value)
@@ -4615,6 +4613,11 @@ fn now_string() -> Result<String, ApiError> {
.map_err(|error| ApiError::internal(error.to_string()))
}
fn parse_timestamp(value: &str) -> Result<OffsetDateTime, ApiError> {
OffsetDateTime::parse(value, &Rfc3339)
.map_err(|_| ApiError::validation("timestamp must be RFC 3339"))
}
fn format_timestamp(timestamp: OffsetDateTime) -> String {
timestamp
.format(&Rfc3339)
@@ -4642,9 +4645,7 @@ async fn resolve_runtime_auth_for_task(
})?;
let mut secrets = BTreeMap::new();
let used_at = now_string().map_err(|error| RuntimeError::SecretCrypto {
details: error.to_string(),
})?;
let used_at = OffsetDateTime::now_utc();
for secret_id in auth_profile.config.secret_ids() {
let secret = registry
@@ -4682,12 +4683,10 @@ async fn resolve_runtime_auth_for_task(
ResolvedAuth::from_profile(&auth_profile, &secrets).map(Some)
}
fn default_invitation_expiry() -> Result<String, ApiError> {
fn default_invitation_expiry() -> Result<OffsetDateTime, ApiError> {
OffsetDateTime::now_utc()
.checked_add(time::Duration::days(7))
.ok_or_else(|| ApiError::internal("failed to compute invitation expiry"))?
.format(&Rfc3339)
.map_err(|error| ApiError::internal(error.to_string()))
.ok_or_else(|| ApiError::internal("failed to compute invitation expiry"))
}
fn runtime_error_code(error: &RuntimeError) -> &'static str {