# RBAC Policy Configuration
#
# Defines access rules for the website. Identity (who the user is)
# comes from JWT claims or session; this file defines what each group
# is allowed to access.
#
# Group names must match the role strings derived from JWT:
#   Role::Admin     → "admin"
#   Role::Moderator → "moderator"
#   Role::User      → "user"
#   Role::Guest     → "guest"
#   Role::Custom(s) → s
#
# Validate: nickel export rbac.ncl

let C = import "./nickel/rbac/contracts.ncl" in

# Reusable effect sets — compose with array concatenation (@)
let E = {
  redirect_login = [{ type = "redirect", to = "/login?return={request.path}" }],
  audit_deny     = [{ type = "audit_log", event = "access_denied",  level = "warn" }],
  audit_allow    = [{ type = "audit_log", event = "access_granted", level = "info" }],
  api_forbidden  = [{ type = "response", status = 403, body.error = "Forbidden" }],
  log_warn       = [{ type = "log", level = "warn", message = "Denied: {request.path}" }],
  security_alert = [{
    type = "notify",
    channel = "security",
    message = "Admin access: {request.path} by {user.email}",
  }],
} in

{
  groups = [
    {
      name = "admin",
      parent_groups = [],
      permissions = [
        {
          resource = "endpoint",
          pattern  = "/api/*",
          outcome  = "allow",
          methods  = [],
          effects  = E.audit_allow,
        },
        {
          resource = "page",
          pattern  = "/*",
          outcome  = "allow",
          methods  = [],
          effects  = [],
        },
      ],
    },
    {
      name = "moderator",
      parent_groups = ["user"],
      permissions = [
        {
          resource = "endpoint",
          pattern  = "/api/content/*",
          outcome  = "allow",
          methods  = ["GET", "POST", "PUT"],
          effects  = E.audit_allow,
        },
        {
          resource = "endpoint",
          pattern  = "/api/admin/*",
          outcome  = "deny",
          methods  = [],
          effects  = E.audit_deny @ E.api_forbidden,
        },
        {
          resource = "page",
          pattern  = "/admin/content/*",
          outcome  = "allow",
          methods  = [],
          effects  = [],
        },
      ],
    },
    {
      name = "user",
      parent_groups = [],
      permissions = [
        {
          resource = "page",
          pattern  = "/*",
          outcome  = "allow",
          methods  = [],
          effects  = [],
        },
        {
          resource = "endpoint",
          pattern  = "/api/*",
          outcome  = "deny",
          methods  = [],
          effects  = E.audit_deny @ E.api_forbidden,
        },
      ],
    },
  ],

  user_overrides = [
    # Example: block a specific user and redirect to login
    # {
    #   id = "blocked@example.com",
    #   permissions = [{
    #     resource = "page",
    #     pattern  = "/*",
    #     outcome  = "deny",
    #     methods  = [],
    #     effects  = E.audit_deny @ E.security_alert @ E.redirect_login,
    #   }],
    # },
  ],

  defaults = {
    unauthenticated_allow = [
      # Protected paths evaluated first — first match wins
      { resource = "page",     pattern = "/admin/*",    outcome = "deny",  methods = [], effects = E.audit_deny @ E.redirect_login },
      # Public pages
      { resource = "page",     pattern = "/login",      outcome = "allow", methods = [], effects = [] },
      { resource = "page",     pattern = "/register",   outcome = "allow", methods = [], effects = [] },
      { resource = "page",     pattern = "/*",          outcome = "allow", methods = [], effects = [] },
      # Public endpoints and assets
      { resource = "endpoint", pattern = "/api/health",               outcome = "allow", methods = [],       effects = [] },
      { resource = "endpoint", pattern = "/api/ws",                   outcome = "allow", methods = ["GET"],  effects = [] },
      { resource = "endpoint", pattern = "/api/auth/*",               outcome = "allow", methods = [],       effects = [] },
      { resource = "endpoint", pattern = "/api/server_request_otp*", outcome = "allow", methods = ["POST"], effects = [] },
      { resource = "endpoint", pattern = "/api/server_verify_otp*",  outcome = "allow", methods = ["POST"], effects = [] },
      { resource = "endpoint", pattern = "/api/content-render/*",     outcome = "allow", methods = ["GET"],  effects = [] },
      { resource = "endpoint", pattern = "/api/content-index/*",      outcome = "allow", methods = ["GET"],  effects = [] },
      { resource = "asset",    pattern = "/*",                        outcome = "allow", methods = [],       effects = [] },
    ],
    unauthenticated_deny = [],
    authenticated_fallback    = "deny",
    unauthenticated_fallback  = "deny",
    fallback_effects          = E.log_warn,
  },
} | C.FileRbacConfig
