ThatAIguyA world of ideas

THE CONSCIOUSNESS ATLAS
Read. Experiment. Follow the evidence.

ConsciousnessLearn · Explore · Joseph Anady

Janady13/missionmatch / internal/platform/security/tools.go

Source identity, revision, and recovered contents.

GitHub sourceSource text recovered

Source identity

FieldRecorded value
Source typeGitHub source
Original recordJanady13/missionmatch / internal/platform/security/tools.go
DateNot specified in source
RepositoryJanady13/missionmatch
Revision2178e7298d0e5d9af83afa12402fd587f0ba6ed8
Branchfeature/aioe-upgrade
Path or archive memberinternal/platform/security/tools.go
Original SHA-2562468fc5a98225b0d13976ce65968cd9331a955fff468546e6e44eb6c5843b6e8
Git blob SHA0458ac71a3634b34c9841e05d87c1b345f6b8be1
Reading-copy SHA-2562468fc5a98225b0d13976ce65968cd9331a955fff468546e6e44eb6c5843b6e8

Original source ↗

Recovered source transcript

package security import ( "net/http" "sort" "github.com/missionworkforce/missionmatch/internal/platform/tenant" ) // Tool entitlement: what a person may SEE, kept separate from what they may DO. // // Role answers authority: may this person edit a requirement, run an export, disable an account. Tool // answers surface: does recruitMATCH appear for them at all. The two are genuinely independent, and // collapsing them would be wrong in both directions. One client's recruiter works only recruitMATCH and // slateMATCH while another's sees every product, and that is not a difference in authority, so it must // not be expressed by giving one of them a different role. Equally, hiding a tool must never be mistaken // for removing authority: a user with recruitMATCH hidden but CapCandidateWrite still held is refused by // the tool gate, not by the capability check, and the refusal has to be the tool's. // // Entitlement is per user and explicit. Absence of a grant is absence of access, in the API and in the // interface, so an account created without grants sees nothing rather than everything. The opposite // default fails toward silent over exposure of a whole product to someone who was never meant to have it. // Tool is one of the four products. The vocabulary is closed and matches the CHECK constraint on // user_tool_access, so a value that would be refused by the database is refused here first. type Tool string const ( ToolMissionMatch Tool = "missionmatch" ToolScreenMatch Tool = "screenmatch" ToolSlateMatch Tool = "slatematch" ToolRecruitMatch Tool = "recruitmatch" ) // AllTools is the full vocabulary, in the order the navigation presents them. var AllTools = []Tool{ToolMissionMatch, ToolScreenMatch, ToolSlateMatch, ToolRecruitMatch} // ValidTool reports whether a string names a real tool. Used before any write, so an unknown value is a // 400 from the service rather than a constraint violation surfacing as a 500. func ValidTool(s string) bool { for _, t := range AllTools { if Tool(s) == t { return true } } return false } // ToolsOf normalizes a raw list into a sorted, deduplicated, valid set. Unknown values are DROPPED // rather than causing a failure, because this runs on the read path when turning stored rows into a // principal: a tool retired from the vocabulary while still present in old rows must degrade to that // tool being invisible, not to the user being unable to log in. func ToolsOf(raw []string) []string { seen := make(map[string]bool, len(raw)) out := make([]string, 0, len(raw)) for _, s := range raw { if !ValidTool(s) || seen[s] { continue } seen[s] = true out = append(out, s) } sort.Strings(out) return out } // HasTool reports whether a principal's granted set includes a tool. Superuser is NOT special cased // here, deliberately: entitlement is data, and a superuser whose grants were narrowed should see the // narrowing rather than silently override it. The service grants a superuser every tool at creation, so // the common case is covered by the data being right rather than by an exception in the check. func HasTool(granted []string, want Tool) bool { for _, g := range granted { if Tool(g) == want { return true } } return false } // CanGrantTools reports whether an actor may change another user's tool entitlement, and is the tool // analogue of CanGrantRole. Two conditions, both required: // // 1. The actor must outrank the target. Same separation of duties as roles: nobody edits a peer's or a // superior's access, and nobody edits their own. // 2. The actor may only grant tools they themselves hold. Without this an admin entitled to two tools // could grant themselves a third by way of an account they control, so the ceiling on what an actor // can spread is what they already have. // // Revocation is bounded by the first condition only: an actor may remove any tool from someone they // outrank, including one the actor does not hold, because taking access away is the safe direction. func CanGrantTools(actorRole, targetRole Role, actorTools, wantTools []string) bool { if !OutRanks(actorRole, targetRole) { return false } return CanConferTools(actorTools, wantTools) } // CanConferTools is the POSSESSION half on its own: may this actor hand out these tools at all, setting // aside who the recipient is. // // It exists because the two halves answer to different authorities and one caller only needs the second. // On an INVITE, whether the actor may create an account at that role has already been decided by // CanGrantRole, which permits the one case OutRanks does not: a superuser creating another superuser. // Routing an invite through CanGrantTools would re impose strict outranking on top of that decision and // refuse the tools for an account the actor was just authorized to create, so the invitation fails as a // 403 with the role permitted and the entitlement denied. That is not a stricter policy, it is two rules // disagreeing. // // Editing an EXISTING user still goes through CanGrantTools, because there the outranking condition is // doing real work: it is what stops an actor rewriting a peer's or a superior's access. func CanConferTools(actorTools, wantTools []string) bool { for _, w := range wantTools { if !ValidTool(w) { return false } if !HasTool(actorTools, Tool(w)) { return false } } return true } // RequireTool is the API side gate for a product surface. It is the enforcement that matters: hiding a // route in the navigation is a presentation choice, and a user who keeps a bookmark, or who reads the // bundle, reaches the same handler. Mounting this on the tool's route group means the entitlement is // enforced once, at the boundary, for every endpoint the tool owns including ones added later. // // It refuses with 404 rather than 403. A tool the caller is not entitled to should not be distinguishable // from a tool that does not exist: a 403 confirms the surface is real and tells an unentitled account // exactly which products the organization has bought. func RequireTool(tool Tool) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { p, ok := tenant.UserFromContext(r.Context()) if !ok || !HasTool(p.Tools, tool) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusNotFound) _, _ = w.Write([]byte(`{"error":{"code":"not_found","message":"not found"}}`)) return } next.ServeHTTP(w, r) }) } } // RequireAnyTool gates a surface on holding AT LEAST ONE of the given tools. It exists for the shared // readers (the candidate and requirement pickers) that every product needs: gating them to a single tool // would break the other three, and leaving them ungated would expose the candidate list to an account // entitled to nothing at all. Same 404 posture as RequireTool, for the same reason. func RequireAnyTool(tools ...Tool) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { p, ok := tenant.UserFromContext(r.Context()) if ok { for _, t := range tools { if HasTool(p.Tools, t) { next.ServeHTTP(w, r) return } } } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusNotFound) _, _ = w.Write([]byte(`{"error":{"code":"not_found","message":"not found"}}`)) }) } }

Search equations, builds, manuscript text, and recovered sources.