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 | 1e9249840a4302ec82e123b9c9cb6f75badea3e4 |
| Branch | master |
| Path or archive member | internal/platform/security/rbac.go |
| Original SHA-256 | 04939c207c51629c3c99c00e480aba5957d01a95d593d85e86579b7b4a72495c |
| Git blob SHA | 2efda05402a2f030c413e423e7068f283d4a3e1f |
| Reading-copy SHA-256 | 04939c207c51629c3c99c00e480aba5957d01a95d593d85e86579b7b4a72495c |
Every recorded occurrence
These 23 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 | master | 1e9249840a4302ec82e123b9c9cb6f75badea3e4 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | m5-price-to-win | 41000ad30fff4129fdaf5ec84e15ba14c27d4890 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | collision-deconfliction | 4ee5a09972608ed89f8377c6665542d5f450f0a6 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | graphrag-foundation | b0ddeb9f633fd138d09309d1a17b7d13bc3a67f7 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | time-to-fill-survival | b66e1e505863d4f17741a4b9ede73509e45bd6c6 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | mag-substrate | b82c7100a492dec67dfd1eda6b3f53def859be35 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | capture-readiness | bae6af7cb2997e819174a9e9cfff5e16067a1975 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | ws8-teaching-loop | c823f0fb6bb2aba0f39001eb6de96f4000d9321f | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | phase2-connectors | e038d4c687aec16f8bd9bc4d907eea14d91f8704 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | presentation-readiness | eb574acaa29d71ce4d0f852572e87c275c79fdb7 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | ws9-bench-ingestion | f585a9ef32fa554663ce1fba9a414a54b6e49cf0 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | vendor-intelligence | fe9796a19c261951d3f2565206c0c1b5ac294465 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | collision-deconfliction | 4ee5a09972608ed89f8377c6665542d5f450f0a6 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | m5-price-to-win | 41000ad30fff4129fdaf5ec84e15ba14c27d4890 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | master | 1e9249840a4302ec82e123b9c9cb6f75badea3e4 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | ws8-teaching-loop | c823f0fb6bb2aba0f39001eb6de96f4000d9321f | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | mag-substrate | b82c7100a492dec67dfd1eda6b3f53def859be35 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | time-to-fill-survival | b66e1e505863d4f17741a4b9ede73509e45bd6c6 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | graphrag-foundation | b0ddeb9f633fd138d09309d1a17b7d13bc3a67f7 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | ws9-bench-ingestion | f585a9ef32fa554663ce1fba9a414a54b6e49cf0 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | presentation-readiness | eb574acaa29d71ce4d0f852572e87c275c79fdb7 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | phase2-connectors | e038d4c687aec16f8bd9bc4d907eea14d91f8704 | Open original |
| Janady13/missionmatch / internal/platform/security/rbac.go | capture-readiness | bae6af7cb2997e819174a9e9cfff5e16067a1975 | Open original |
Recovered source transcript
Download complete source text ↓141 lines · 6.1 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)
CapCurationCurate Capability = "curation.curate" // approve a teaching curation proposal and verify the staged ontology edge, the two step WS8 human in the loop gate; a governance write held at the compliance tier
)
// 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},
CapCurationCurate: {RoleOwner, RoleAdmin}, // the compliance and operator tier, the same roles that hold the compliance governance writes
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) }