Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/missionmatch / internal/platform/security/rbac.go |
| Date | Not specified in source |
| Repository | Janady13/missionmatch |
| Revision | 43d56387270ef4da4cabd794d97ca6a49909bc7d |
| Branch | w3-ai-staffing-recommendations |
| Path or archive member | internal/platform/security/rbac.go |
| Original SHA-256 | a455f50fd869e6546b9aa19c2f1ffcfc4ddbafae12df08e21a655af542d2d1b7 |
| Git blob SHA | 46f354f64867b44e63a513ca71d21ef9cbb68036 |
| Reading-copy SHA-256 | a455f50fd869e6546b9aa19c2f1ffcfc4ddbafae12df08e21a655af542d2d1b7 |
Recovered source transcript
Download complete source text ↓137 lines · 5.4 KB
package security
// Role is the tenant role enum already enforced by the users table CHECK constraint. The five roles
// form an ordered hierarchy for the RequireRole comparison, but capabilities are assigned explicitly
// per role below, not implied by rank alone.
type Role string
const (
RoleOwner Role = "owner"
RoleAdmin Role = "admin"
RoleRecruiter Role = "recruiter"
RoleMember Role = "member"
RoleViewer Role = "viewer"
)
// Capability is a fine grained permission checked at the API. Handlers gate on a Capability rather
// than a role so the policy lives in one table and the UI never has to hide a control to enforce
// access.
type Capability string
const (
CapCandidateRead Capability = "candidate.read"
CapCandidateWrite Capability = "candidate.write"
CapRequirementEdit Capability = "requirement.write"
CapSlateEdit Capability = "slate.write"
CapSearchRun Capability = "search.run"
CapExportRun Capability = "export.run"
CapSourcingRead Capability = "sourcing.read" // see sourced candidate contact fields and the sourcing log
CapPrivacyErase Capability = "privacy.erase" // hard delete a sourced candidate and their PII
CapUserInvite Capability = "user.invite"
CapUserRoleChange Capability = "user.role.change"
CapUserDisable Capability = "user.disable"
CapOrgSettings Capability = "org.settings.write"
CapAuditRead Capability = "audit.read"
CapComplianceRead Capability = "compliance.read" // adverse impact report, AEDT inventory and model registry, retention reads
CapComplianceWrite Capability = "compliance.write" // register an AEDT tool, run retention: governance writes
CapStaffingRecommend Capability = "staffing.recommend" // generate an AI staffing recommendation run; this WRITES recommendation rows, so it is a write capability, not a read
)
// roleRank orders the hierarchy for AtLeast and for bounding invited roles. Higher is more
// privileged.
var roleRank = map[Role]int{
RoleViewer: 0,
RoleMember: 1,
RoleRecruiter: 2,
RoleAdmin: 3,
RoleOwner: 4,
}
// capabilityRoles is the authoritative permission matrix. owner holds every capability. admin manages
// recruiter, member, and viewer accounts and runs the recruiting workflow, but cannot change org
// settings or manage other admins and owners (those are owner only and are further guarded by the
// separation of duties checks in the auth service). The two privacy capabilities gate the sourced
// candidate contact fields, the sourcing log, and erasure: sourcing.read goes to the roles that
// actually source (owner, admin, recruiter) and the destructive privacy.erase is held tighter
// (owner, admin).
var capabilityRoles = map[Capability][]Role{
CapCandidateRead: {RoleOwner, RoleAdmin, RoleRecruiter, RoleMember, RoleViewer},
CapSearchRun: {RoleOwner, RoleAdmin, RoleRecruiter, RoleMember, RoleViewer},
CapCandidateWrite: {RoleOwner, RoleAdmin, RoleRecruiter},
CapRequirementEdit: {RoleOwner, RoleAdmin, RoleRecruiter},
CapSlateEdit: {RoleOwner, RoleAdmin, RoleRecruiter},
CapStaffingRecommend: {RoleOwner, RoleAdmin, RoleRecruiter}, // same roles that hold slate.write: generating staffing recommendations is the same authority tier
CapExportRun: {RoleOwner, RoleAdmin, RoleRecruiter},
CapSourcingRead: {RoleOwner, RoleAdmin, RoleRecruiter},
CapPrivacyErase: {RoleOwner, RoleAdmin},
CapUserInvite: {RoleOwner, RoleAdmin},
CapUserRoleChange: {RoleOwner, RoleAdmin},
CapUserDisable: {RoleOwner, RoleAdmin},
CapAuditRead: {RoleOwner, RoleAdmin},
CapComplianceRead: {RoleOwner, RoleAdmin},
CapComplianceWrite: {RoleOwner, RoleAdmin},
CapOrgSettings: {RoleOwner},
}
// capabilitySet is the matrix indexed for O(1) lookup, built once at init.
var capabilitySet = func() map[Role]map[Capability]bool {
set := map[Role]map[Capability]bool{
RoleOwner: {}, RoleAdmin: {}, RoleRecruiter: {}, RoleMember: {}, RoleViewer: {},
}
for cap, roles := range capabilityRoles {
for _, role := range roles {
set[role][cap] = true
}
}
return set
}()
// ValidRole reports whether role is one of the five known roles.
func ValidRole(role Role) bool {
_, ok := roleRank[role]
return ok
}
// Has reports whether role holds the capability.
func Has(role Role, cap Capability) bool {
caps, ok := capabilitySet[role]
if !ok {
return false
}
return caps[cap]
}
// AtLeast reports whether role is at or above min in the hierarchy. Unknown roles are never at least
// anything.
func AtLeast(role, min Role) bool {
r, ok := roleRank[role]
if !ok {
return false
}
m, ok := roleRank[min]
if !ok {
return false
}
return r >= m
}
// OutRanks reports whether actor is strictly more privileged than other. It is the core separation of
// duties predicate: a user may only invite, role change, disable, or reset the MFA of someone they
// outrank, never a peer or a superior, and never themselves.
func OutRanks(actor, other Role) bool {
a, ok := roleRank[actor]
if !ok {
return false
}
o, ok := roleRank[other]
if !ok {
return false
}
return a > o
}
// CanInvite reports whether an actor may invite a user with the given role. The invited role must be
// strictly below the actor's own role, so an admin can invite recruiter, member, and viewer but
// never another admin or an owner, and owners are created only through provisioning, never an invite.
func CanInvite(actor, invited Role) bool { return OutRanks(actor, invited) }