- store: SQLite (WAL, foreign keys ON, CGO-free driver) + the embedded migration runner; each module's migrations are name-prefixed (D-012) - audit: the append-only audit log; the actor threads via context (R-1) - users: the user_id/GUID/email anchors (D-013) - config: the YAML settings file (D-035) + validation - httpx: cookies · loopback detection · trusted-proxy XFF · CSRF · security headers · redaction - middleware: correlation id · audit · rate limiting - mail: the invite/recovery mailer seam - server: the core DOOR — the resolution switch, the dispatch registry (RegisterModule), the role gates, /setup · enroll/login · recovery flows, the reserved `static` workflow, and the loopback-only bootstrap (D-025)
49 lines
1.6 KiB
Go
49 lines
1.6 KiB
Go
package server
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"git.lohmar.co.uk/cclohmar/NextMyDay/internal/core/users"
|
|
)
|
|
|
|
// TestTiersRippleDown proves the D-034 role gate: simple tiers, one role per
|
|
// user, and a role implies every role below it.
|
|
func TestTiersRippleDown(t *testing.T) {
|
|
g := NewTiers()
|
|
|
|
// No explicit requirement -> the floor (team): every authenticated role is
|
|
// admitted.
|
|
for _, r := range []users.Role{users.RoleTeam, users.RoleManager, users.RoleDirector, users.RoleAdmin} {
|
|
if !g.Allowed(r, "home", "dashboard") {
|
|
t.Errorf("%s was denied an unlisted function (floor = team)", r)
|
|
}
|
|
}
|
|
// An invalid/empty role fails closed.
|
|
if g.Allowed(users.Role("boss"), "home", "dashboard") {
|
|
t.Error("an invalid role was admitted by the tier gate")
|
|
}
|
|
if g.Allowed(users.Role(""), "home", "dashboard") {
|
|
t.Error("an empty role was admitted by the tier gate")
|
|
}
|
|
|
|
// A function requiring manager: team is denied, manager and above pass
|
|
// (ripple-down).
|
|
g.Require("users", "create", users.RoleManager)
|
|
if g.Allowed(users.RoleTeam, "users", "create") {
|
|
t.Error("team was admitted to a manager function")
|
|
}
|
|
for _, r := range []users.Role{users.RoleManager, users.RoleDirector, users.RoleAdmin} {
|
|
if !g.Allowed(r, "users", "create") {
|
|
t.Errorf("%s was denied a manager function (ripple-down)", r)
|
|
}
|
|
}
|
|
|
|
// A director function: only director and admin pass.
|
|
g.Require("users", "promote", users.RoleDirector)
|
|
if g.Allowed(users.RoleManager, "users", "promote") {
|
|
t.Error("manager was admitted to a director function")
|
|
}
|
|
if !g.Allowed(users.RoleAdmin, "users", "promote") {
|
|
t.Error("admin was denied a director function")
|
|
}
|
|
}
|