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 | 4b8e7ce594c068621867f9c9deed0ec64ae6c553 |
| Branch | ws3-clearance |
| Path or archive member | internal/platform/security/rbac.go |
| Original SHA-256 | 8b6c35f1b52a2784549f3baca73d520cd64b590069610826e59b8309bcfb2503 |
| Git blob SHA | 9268ebb4127491c5a0602f2e98f2ea95ed645dfb |
| Reading-copy SHA-256 | 8b6c35f1b52a2784549f3baca73d520cd64b590069610826e59b8309bcfb2503 |
Every recorded occurrence
These 17 records contain identical original source bytes. Their paths and revisions remain part of the archive.
| Original record | Branch or archive | Revision / identifier | Original location |
|---|---|---|---|
| Janady13/missionmatch / internal/platform/security/rbac.go | ws3-clearance | 4b8e7ce594c068621867f9c9deed0ec64ae6c553 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | ws7-federal-signal | 6a9f6ce9cfb13345ffb47770d4960e7c2d9c17c2 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | ws6-retrieval | 6c56e29231ec05735927fa265c97d517499dfeaf | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | per-tenant-routing | 9bde0f9a74b89d01980fa658e5253acda7528d0c | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | ai-brain-live | aac32fc49c878cc5bca099459307611562d0bac1 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | ws1-ontology-sync | b596f449a32a1016fbd403c36505cc00a1ac9ee6 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | deploy-and-ops | bdacd9d0b4d5998d25fc74bf4007f4c3ec538c7a | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | phase2-eval-fairness | d361af254701975fe239927656ababb56374655e | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | ws2-alias-relationship | e4dada4601c6eb101830f9d223a9655dfa120616 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | per-tenant-routing | 9bde0f9a74b89d01980fa658e5253acda7528d0c | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | ws6-retrieval | 6c56e29231ec05735927fa265c97d517499dfeaf | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | ws1-ontology-sync | b596f449a32a1016fbd403c36505cc00a1ac9ee6 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | ws3-clearance | 4b8e7ce594c068621867f9c9deed0ec64ae6c553 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | phase2-eval-fairness | d361af254701975fe239927656ababb56374655e | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | deploy-and-ops | bdacd9d0b4d5998d25fc74bf4007f4c3ec538c7a | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | ws7-federal-signal | 6a9f6ce9cfb13345ffb47770d4960e7c2d9c17c2 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | ai-brain-live | aac32fc49c878cc5bca099459307611562d0bac1 | Open original |
Recovered source transcript
Download complete source text ↓139 lines · 5.8 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
CapBrainQuery Capability = "brain.query" // ask the AI brain a natural language question (read only augmented generation over the tenant's own data)
)
// 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},
CapBrainQuery: {RoleOwner, RoleAdmin, RoleRecruiter, RoleMember, RoleViewer}, // same tier as search.run: a read only question over the tenant's own data
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) }