Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions core/ir/src/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,29 @@ impl ResourceId {
pub fn tool(name: impl Into<String>) -> Self {
Self(format!("tool:{}", name.into()))
}

/// Create a cloud resource ID.
///
/// Format: `cloud:{provider}:{scope}:{kind}/{name}`
///
/// Used for tracking access to cloud resources (buckets, IAM roles, etc.).
pub fn cloud(provider: &str, scope: &str, kind: &str, name: &str) -> Self {
Self(format!("cloud:{provider}:{scope}:{kind}/{name}"))
}

/// Create a cloud resource ID from a [`CloudResource`](crate::transport::cloud::CloudResource).
pub fn from_cloud_resource(resource: &crate::transport::cloud::CloudResource) -> Self {
Self(resource.resource_id())
}

/// Create a secret resource ID.
///
/// Format: `secret:{name}`
///
/// Used for tracking access to secrets (read/write).
pub fn secret(name: impl Into<String>) -> Self {
Self(format!("secret:{}", name.into()))
}
}

impl From<&str> for ResourceId {
Expand Down Expand Up @@ -362,6 +385,18 @@ mod tests {
assert!(conn.0.starts_with("conn:"));
}

#[test]
fn test_cloud_resource_id() {
let cloud = ResourceId::cloud("gcp", "my-project", "storage_bucket", "my-bucket");
assert_eq!(cloud.0, "cloud:gcp:my-project:storage_bucket/my-bucket");
}

#[test]
fn test_secret_resource_id() {
let secret = ResourceId::secret("db-password");
assert_eq!(secret.0, "secret:db-password");
}

#[test]
fn test_access_mode_conflicts() {
assert!(!AccessMode::Read.conflicts_with(&AccessMode::Read));
Expand Down
Loading
Loading