///|
/// Purpose-bound access decisions for privacy-sensitive de-identification
/// services. The core engine never grants access by itself; callers provide a
/// principal, purpose, and resource scope which are evaluated together.
pub(all) enum AccessPermission {
AccessReadRaw
AccessReadMasked
AccessWriteMasked
AccessRunPipeline
AccessReviewFinding
AccessExportAudit
AccessManagePolicy
AccessManageKeys
} derive(Debug, Eq)
///|
pub(all) enum AccessDecision {
AccessAllowed
AccessDenied
AccessRequiresApproval
AccessExpired
AccessScopeMismatch
} derive(Debug, Eq)
///|
pub(all) enum AccessPurpose {
AccessTreatment
AccessOperations
AccessResearch
AccessQuality
AccessSupport
AccessSecurity
} derive(Debug, Eq)
///|
pub(all) struct AccessPrincipal {
principal_id : String
display_name : String
roles : Array[String]
department : String
active : Bool
mfa_verified : Bool
} derive(Debug, Eq)
///|
pub(all) struct AccessGrant {
grant_id : String
principal_id : String
permission : AccessPermission
purpose : AccessPurpose
resource_prefix : String
expires_at : String
requires_mfa : Bool
requires_approval : Bool
approved_by : String
approved_at : String
reason : String
} derive(Debug, Eq)
///|
pub(all) struct AccessRequest {
request_id : String
principal : AccessPrincipal
permission : AccessPermission
purpose : AccessPurpose
resource_id : String
requested_at : String
reason : String
emergency : Bool
} derive(Debug)
///|
pub(all) struct AccessEvaluation {
request_id : String
decision : AccessDecision
matched_grant : String
reasons : Array[String]
evaluated_at : String
audit_checksum : String
} derive(Debug)
///|
pub fn access_permission_name(permission : AccessPermission) -> String {
match permission {
AccessReadRaw => "read_raw"
AccessReadMasked => "read_masked"
AccessWriteMasked => "write_masked"
AccessRunPipeline => "run_pipeline"
AccessReviewFinding => "review_finding"
AccessExportAudit => "export_audit"
AccessManagePolicy => "manage_policy"
AccessManageKeys => "manage_keys"
}
}
///|
pub fn access_decision_name(decision : AccessDecision) -> String {
match decision {
AccessAllowed => "allowed"
AccessDenied => "denied"
AccessRequiresApproval => "requires_approval"
AccessExpired => "expired"
AccessScopeMismatch => "scope_mismatch"
}
}
///|
pub fn access_purpose_name(purpose : AccessPurpose) -> String {
match purpose {
AccessTreatment => "treatment"
AccessOperations => "operations"
AccessResearch => "research"
AccessQuality => "quality"
AccessSupport => "support"
AccessSecurity => "security"
}
}
///|
pub fn access_principal(
principal_id : String,
display_name : String,
roles : Array[String],
department : String,
) -> AccessPrincipal {
{
principal_id,
display_name,
roles,
department,
active: true,
mfa_verified: false,
}
}
///|
pub fn AccessPrincipal::deactivate(self : AccessPrincipal) -> AccessPrincipal {
{ ..self, active: false }
}
///|
pub fn AccessPrincipal::verify_mfa(self : AccessPrincipal) -> AccessPrincipal {
{ ..self, mfa_verified: true }
}
///|
pub fn AccessPrincipal::has_role(self : AccessPrincipal, role : String) -> Bool {
self.roles.contains(role)
}
///|
pub fn AccessPrincipal::is_valid(self : AccessPrincipal) -> Bool {
self.principal_id.length() > 0 &&
self.display_name.length() > 0 &&
self.department.length() > 0 &&
self.active &&
!self.roles.is_empty()
}
///|
pub fn access_grant(
principal_id : String,
permission : AccessPermission,
purpose : AccessPurpose,
resource_prefix : String,
expires_at : String,
reason : String,
) -> AccessGrant {
{
grant_id: stable_hash(
principal_id +
":" +
access_permission_name(permission) +
":" +
resource_prefix,
),
principal_id,
permission,
purpose,
resource_prefix,
expires_at,
requires_mfa: permission == AccessReadRaw || permission == AccessManageKeys,
requires_approval: permission == AccessExportAudit ||
permission == AccessManageKeys,
approved_by: "",
approved_at: "",
reason,
}
}
///|
pub fn AccessGrant::approve(
grant : AccessGrant,
approver : String,
approved_at : String,
) -> AccessGrant {
{ ..grant, approved_by: approver, approved_at }
}
///|
pub fn AccessGrant::is_approved(self : AccessGrant) -> Bool {
!self.requires_approval ||
(self.approved_by.length() > 0 && self.approved_at.length() > 0)
}
///|
pub fn AccessGrant::is_expired(self : AccessGrant, now : String) -> Bool {
self.expires_at.length() > 0 && self.expires_at < now
}
///|
pub fn AccessGrant::covers(self : AccessGrant, request : AccessRequest) -> Bool {
self.principal_id == request.principal.principal_id &&
self.permission == request.permission &&
self.purpose == request.purpose &&
(
self.resource_prefix.is_empty() ||
request.resource_id.has_prefix(self.resource_prefix)
)
}
///|
pub fn access_request(
request_id : String,
principal : AccessPrincipal,
permission : AccessPermission,
purpose : AccessPurpose,
resource_id : String,
requested_at : String,
reason : String,
) -> AccessRequest {
{
request_id,
principal,
permission,
purpose,
resource_id,
requested_at,
reason,
emergency: false,
}
}
///|
pub fn AccessRequest::as_emergency(self : AccessRequest) -> AccessRequest {
{ ..self, emergency: true }
}
///|
pub fn AccessRequest::is_valid(self : AccessRequest) -> Bool {
self.request_id.length() > 0 &&
self.principal.is_valid() &&
self.resource_id.length() > 0 &&
self.requested_at.length() > 0 &&
self.reason.length() > 0
}
///|
pub fn evaluate_access(
request : AccessRequest,
grants : Array[AccessGrant],
now : String,
) -> AccessEvaluation {
let mut matched = ""
let mut decision = AccessDenied
let reasons : Array[String] = []
if !request.is_valid() {
reasons.push("invalid request")
} else if !request.principal.active {
reasons.push("principal is inactive")
} else {
let mut scope_found = false
for grant in grants {
if grant.principal_id == request.principal.principal_id &&
grant.permission == request.permission &&
grant.purpose == request.purpose {
if grant.covers(request) {
scope_found = true
matched = grant.grant_id
if grant.is_expired(now) {
decision = AccessExpired
reasons.push("grant expired")
} else if grant.requires_mfa && !request.principal.mfa_verified {
decision = AccessDenied
reasons.push("multi-factor verification required")
} else if !grant.is_approved() {
decision = AccessRequiresApproval
reasons.push("independent approval required")
} else {
decision = AccessAllowed
reasons.push("matching active grant")
}
}
}
}
if !scope_found && decision == AccessDenied {
let same_permission = grants.any(fn(grant) {
grant.principal_id == request.principal.principal_id &&
grant.permission == request.permission &&
grant.purpose == request.purpose
})
if same_permission {
decision = AccessScopeMismatch
reasons.push("resource is outside the granted scope")
} else {
reasons.push("no matching grant")
}
}
if request.emergency &&
decision == AccessDenied &&
request.principal.has_role("incident-response") {
decision = AccessRequiresApproval
reasons.push("emergency access requires post-event approval")
}
}
{
request_id: request.request_id,
decision,
matched_grant: matched,
reasons,
evaluated_at: now,
audit_checksum: stable_hash(
request.request_id +
":" +
access_decision_name(decision) +
":" +
reasons.join("|"),
),
}
}
///|
pub fn AccessEvaluation::is_allowed(self : AccessEvaluation) -> Bool {
self.decision == AccessAllowed
}
///|
pub fn AccessEvaluation::summary(self : AccessEvaluation) -> String {
[
"request_id=" + self.request_id,
"decision=" + access_decision_name(self.decision),
"matched_grant=" + self.matched_grant,
"reasons=" + self.reasons.join("; "),
"evaluated_at=" + self.evaluated_at,
"audit_checksum=" + self.audit_checksum,
].join("\n")
}
///|
pub fn AccessEvaluation::to_json(self : AccessEvaluation) -> String {
"{" +
"\"request_id\":\"" +
json_escape(self.request_id) +
"\"," +
"\"decision\":\"" +
access_decision_name(self.decision) +
"\"," +
"\"matched_grant\":\"" +
json_escape(self.matched_grant) +
"\"," +
"\"reasons\":[" +
self.reasons.map(json_escape).join(",") +
"]," +
"\"audit_checksum\":\"" +
json_escape(self.audit_checksum) +
"\"}"
}
///|
pub fn access_requires_raw_protection(permission : AccessPermission) -> Bool {
permission == AccessReadRaw || permission == AccessManageKeys
}
///|
pub fn access_purpose_allows_raw(purpose : AccessPurpose) -> Bool {
purpose == AccessTreatment || purpose == AccessSecurity
}
///|
pub fn access_policy_is_safe(
permission : AccessPermission,
purpose : AccessPurpose,
) -> Bool {
!access_requires_raw_protection(permission) ||
access_purpose_allows_raw(purpose)
}
///|
pub fn filter_accessible_grants(
grants : Array[AccessGrant],
principal_id : String,
purpose : AccessPurpose,
) -> Array[AccessGrant] {
grants.filter(fn(grant) {
grant.principal_id == principal_id && grant.purpose == purpose
})
}
///|
pub fn access_grant_checksum(grants : Array[AccessGrant]) -> String {
stable_hash(
grants
.map(fn(grant) {
grant.grant_id +
":" +
grant.principal_id +
":" +
access_permission_name(grant.permission) +
":" +
access_purpose_name(grant.purpose)
})
.join("\n"),
)
}
///|
pub fn access_evaluation_is_auditable(evaluation : AccessEvaluation) -> Bool {
evaluation.request_id.length() > 0 &&
evaluation.evaluated_at.length() > 0 &&
evaluation.audit_checksum.length() > 0 &&
!evaluation.reasons.is_empty()
}