first pass at access control setup

This commit is contained in:
2026-03-24 14:45:07 -05:00
parent af5175b96a
commit 2ebb03b868
105 changed files with 6163 additions and 1416 deletions

View File

@@ -21,10 +21,6 @@ pub enum Resource {
Inquiries,
Keys,
Artifacts,
Workflows,
Webhooks,
Analytics,
History,
Identities,
Permissions,
}
@@ -40,6 +36,7 @@ pub enum Action {
Cancel,
Respond,
Manage,
Decrypt,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
@@ -69,6 +66,8 @@ pub struct GrantConstraints {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub owner_types: Option<Vec<OwnerType>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub owner_refs: Option<Vec<String>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub visibility: Option<Vec<ArtifactVisibility>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub execution_scope: Option<ExecutionScopeConstraint>,
@@ -99,6 +98,7 @@ pub struct AuthorizationContext {
pub pack_ref: Option<String>,
pub owner_identity_id: Option<Id>,
pub owner_type: Option<OwnerType>,
pub owner_ref: Option<String>,
pub visibility: Option<ArtifactVisibility>,
pub encrypted: Option<bool>,
pub execution_owner_identity_id: Option<Id>,
@@ -115,6 +115,7 @@ impl AuthorizationContext {
pack_ref: None,
owner_identity_id: None,
owner_type: None,
owner_ref: None,
visibility: None,
encrypted: None,
execution_owner_identity_id: None,
@@ -162,6 +163,15 @@ impl Grant {
}
}
if let Some(owner_refs) = &constraints.owner_refs {
let Some(owner_ref) = &ctx.owner_ref else {
return false;
};
if !owner_refs.contains(owner_ref) {
return false;
}
}
if let Some(visibility) = &constraints.visibility {
let Some(target_visibility) = ctx.visibility else {
return false;
@@ -289,4 +299,28 @@ mod tests {
.insert("team".to_string(), json!("infra"));
assert!(!grant.allows(Resource::Packs, Action::Read, &ctx));
}
#[test]
fn owner_ref_constraint_requires_exact_value_match() {
let grant = Grant {
resource: Resource::Artifacts,
actions: vec![Action::Read],
constraints: Some(GrantConstraints {
owner_types: Some(vec![OwnerType::Pack]),
owner_refs: Some(vec!["python_example".to_string()]),
..Default::default()
}),
};
let mut ctx = AuthorizationContext::new(1);
ctx.owner_type = Some(OwnerType::Pack);
ctx.owner_ref = Some("python_example".to_string());
assert!(grant.allows(Resource::Artifacts, Action::Read, &ctx));
ctx.owner_ref = Some("other_pack".to_string());
assert!(!grant.allows(Resource::Artifacts, Action::Read, &ctx));
ctx.owner_ref = None;
assert!(!grant.allows(Resource::Artifacts, Action::Read, &ctx));
}
}