///|
pub(all) enum GateVerdict {
Pass
Fail
Indeterminate
} derive(Eq, Debug)
///|
pub(all) struct GateConfig {
max_new_grants : Int
max_revocations : Int
forbid_cross_tenant_grants : Bool
permitted_principals : Array[String]
permitted_actions : Array[String]
} derive(Debug)
///|
pub(all) struct GateFinding {
code : String
request : AccessRequest
message : String
} derive(Debug)
///|
pub(all) struct GateResult {
verdict : GateVerdict
findings : Array[GateFinding]
} derive(Debug)
///|
pub fn strict_gate() -> GateConfig {
{
max_new_grants: 0,
max_revocations: 0,
forbid_cross_tenant_grants: true,
permitted_principals: [],
permitted_actions: [],
}
}
///|
fn request_is_exception(request : AccessRequest, config : GateConfig) -> Bool {
config.permitted_principals.contains(request.principal_id) &&
config.permitted_actions.contains(request.action)
}
///|
fn is_cross_tenant(universe : RequestUniverse, request : AccessRequest) -> Bool {
let mut principal_tenant : String? = None
let mut resource_tenant : String? = None
for principal in universe.principals {
if principal.id == request.principal_id {
principal_tenant = Some(principal.tenant)
break
}
}
for resource in universe.resources {
if resource.id == request.resource_id {
resource_tenant = Some(resource.tenant)
break
}
}
match (principal_tenant, resource_tenant) {
(Some(a), Some(b)) => a != b
_ => false
}
}
///|
/// Exceptions require both the principal and action to be explicitly listed.
/// They affect only the general grant count, never cross-tenant violations.
pub fn check_gate(
report : AuditReport,
universe : RequestUniverse,
config : GateConfig,
) -> GateResult {
let findings : Array[GateFinding] = []
if !report.complete || config.max_new_grants < 0 || config.max_revocations < 0 {
return { verdict: Indeterminate, findings, }
}
let mut new_grants = 0
let mut revocations = 0
for change in report.changes {
match change.kind {
NewGrant => {
if !request_is_exception(change.request, config) {
new_grants += 1
}
if config.forbid_cross_tenant_grants &&
is_cross_tenant(universe, change.request) {
findings.push({
code: "CROSS_TENANT",
request: change.request,
message: "New cross-tenant access",
})
}
}
RevokedGrant => revocations += 1
_ => ()
}
}
if new_grants > config.max_new_grants {
for change in report.changes {
if change.kind is NewGrant &&
!request_is_exception(change.request, config) {
findings.push({
code: "NEW_GRANT",
request: change.request,
message: "New grant exceeds configured budget",
})
}
}
}
if revocations > config.max_revocations {
for change in report.changes {
if change.kind is RevokedGrant {
findings.push({
code: "REVOCATION",
request: change.request,
message: "Revocation exceeds configured budget",
})
}
}
}
{ verdict: if findings.length() == 0 { Pass } else { Fail }, findings, }
}