summaryrefslogtreecommitdiff
path: root/src/authorization/entities.rs
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-07-15 16:37:08 -0600
committermo khan <mo@mokhan.ca>2025-07-17 16:30:22 -0600
commit45df4d0d9b577fecee798d672695fe24ff57fb1b (patch)
tree1b99bf645035b58e0d6db08c7a83521f41f7a75b /src/authorization/entities.rs
parentf94f79608393d4ab127db63cc41668445ef6b243 (diff)
feat: migrate from Cedar to SpiceDB authorization system
This is a major architectural change that replaces the Cedar policy-based authorization system with SpiceDB's relation-based authorization. Key changes: - Migrate from Rust to Go implementation - Replace Cedar policies with SpiceDB schema and relationships - Switch from envoy `ext_authz` with Cedar to SpiceDB permission checks - Update build system and dependencies for Go ecosystem - Maintain Envoy integration for external authorization This change enables more flexible permission modeling through SpiceDB's Google Zanzibar inspired relation-based system, supporting complex hierarchical permissions that were difficult to express in Cedar. Breaking change: Existing Cedar policies and Rust-based configuration will no longer work and need to be migrated to SpiceDB schema.
Diffstat (limited to 'src/authorization/entities.rs')
-rw-r--r--src/authorization/entities.rs145
1 files changed, 0 insertions, 145 deletions
diff --git a/src/authorization/entities.rs b/src/authorization/entities.rs
deleted file mode 100644
index 050f6f26..00000000
--- a/src/authorization/entities.rs
+++ /dev/null
@@ -1,145 +0,0 @@
-use crate::gitlab::Api;
-use serde::Serialize;
-use std::collections::HashSet;
-use std::future::Future;
-use std::pin::Pin;
-
-type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
-
-// Cedar entity structures
-// Note: We define custom types instead of using cedar_policy::Entity directly because:
-// 1. Cedar's Entity type is for runtime use, not JSON serialization
-// 2. These types ensure our JSON output matches Cedar's expected format exactly
-// 3. The #[serde(rename)] attributes handle Cedar's specific field naming requirements
-#[derive(Debug, Serialize)]
-pub struct CedarEntity {
- pub uid: CedarUid,
- pub attrs: serde_json::Value,
- pub parents: Vec<CedarParent>,
-}
-
-#[derive(Debug, Serialize)]
-pub struct CedarUid {
- #[serde(rename = "type")]
- pub entity_type: String,
- pub id: String,
-}
-
-#[derive(Debug, Serialize)]
-pub struct CedarParent {
- #[serde(rename = "type")]
- pub parent_type: String,
- pub id: String,
-}
-
-pub struct EntitiesRepository {
- api: Api,
-}
-
-impl EntitiesRepository {
- pub fn new(api: Api) -> EntitiesRepository {
- EntitiesRepository { api }
- }
-
- pub async fn all(
- &self,
- project_path: String,
- ) -> Result<Vec<CedarEntity>, Box<dyn std::error::Error>> {
- let mut entities = Vec::new();
- let mut groups = HashSet::new();
-
- let project = self.api.get_project(&project_path).await?;
-
- entities.push(CedarEntity {
- uid: CedarUid {
- entity_type: "Project".to_string(),
- id: project.id.to_string(),
- },
- attrs: serde_json::json!({
- "name": project.name,
- "path": project.path,
- "full_path": format!("{}/{}", project.namespace.full_path, project.path),
- }),
- parents: if project.namespace.kind == "group" {
- vec![CedarParent {
- parent_type: "Group".to_string(),
- id: project.namespace.id.to_string(),
- }]
- } else {
- vec![]
- },
- });
-
- for member in self.api.get_project_members(project.id).await? {
- if member.state == "active" {
- entities.push(CedarEntity {
- uid: CedarUid {
- entity_type: "User".to_string(),
- id: member.id.to_string(),
- },
- attrs: serde_json::json!({
- "username": member.username,
- "access_level": member.access_level,
- }),
- parents: vec![],
- });
- }
- }
-
- if project.namespace.kind == "group" {
- self.fetch_hierarchy(project.namespace.id, &mut entities, &mut groups)
- .await?;
- }
-
- Ok(entities)
- }
-
- /// Validates that the entities can be parsed by Cedar
- pub fn is_valid(entities: &[CedarEntity]) -> Result<(), Box<dyn std::error::Error>> {
- let json = serde_json::to_string(entities)?;
- cedar_policy::Entities::from_json_str(&json, None)?;
- Ok(())
- }
-
- fn fetch_hierarchy<'a>(
- &'a self,
- group_id: u64,
- entities: &'a mut Vec<CedarEntity>,
- groups: &'a mut HashSet<u64>,
- ) -> BoxFuture<'a, Result<(), Box<dyn std::error::Error>>> {
- Box::pin(async move {
- if groups.contains(&group_id) {
- return Ok(());
- }
-
- groups.insert(group_id);
-
- let group = self.api.get_group(group_id).await?;
-
- let parents = if let Some(parent_id) = group.parent_id {
- self.fetch_hierarchy(parent_id, entities, groups).await?;
- vec![CedarParent {
- parent_type: "Group".to_string(),
- id: parent_id.to_string(),
- }]
- } else {
- vec![]
- };
-
- entities.push(CedarEntity {
- uid: CedarUid {
- entity_type: "Group".to_string(),
- id: group.id.to_string(),
- },
- attrs: serde_json::json!({
- "name": group.name,
- "path": group.path,
- "full_path": group.full_path,
- }),
- parents,
- });
-
- Ok(())
- })
- }
-}