Module: Magik::Policy

Defined in:
lib/magik/policy.rb

Overview

Authorization: one rule per resource verb, evaluated identically in every surface that projects from a declaration — screens, actions, API resources, channels, jobs and the admin panel.

Implements: Phase 2 — Rendering & Actions of docs/idea/00-build-spec.md (architecture decision 13, added by amendment on 2026-08-26).

Planned DSL surface, copied from the spec:

  • policy :Name do default :deny; can :verb do |actor, record| ... end end
  • screen/action/channel/job/api ..., policy: %i[Name verb]
  • roles/staff_roles on the app composition root

Two decisions carried from the audit that found this gap (docs/idea/10-saas-coverage.md), both load-bearing:

  1. Phase 2, not Phase 7. Adding a policy: argument to six constructs after those constructs exist is the retrofit the spec itself calls unsurvivable when it says it about tenant_id.
  2. Tier 1, not tier 3 beside Auth. Render and Realtime sit at tier 2 and must evaluate policies, and imports go strictly down a tier. So the evaluator takes the actor as an opaque value — exactly as Router takes a path without knowing what a screen is — and auth at tier 3 supplies it.

Authorization is deliberately not a swap point: a second backend is a second authorization system, which is how frameworks of this shape die.

Status: Not implemented — spec only. Every entry point below raises NotImplementedError.

See Also:

Constant Summary collapse

SPEC_PHASE =

The build-spec phase this subsystem implements.

Returns:

  • (String)
"Phase 2 — Rendering & Actions"
DSL_SURFACE =

The DSL this subsystem will expose, verbatim from the spec.

Returns:

  • (Array<String>)
[
  "policy :Name do default :deny; can :verb do |actor, record| ... end end",
  "screen/action/channel/job/api ..., policy: %i[Name verb]",
  "roles :owner, :admin, :member, :viewer, default: :member",
  "staff_roles :support, :support_lead — a separate axis from tenant membership"
].freeze
STATUS =

Implementation status of this subsystem.

Returns:

  • (String)
"Not implemented — spec only"

Class Method Summary collapse

Class Method Details

.define(*_args, **_options) ⇒ void

This method returns an undefined value.

Entry point for the Policy DSL.

Parameters:

  • _args (Array) —

    ignored

  • _options (Hash) —

    ignored

Raises:

  • (NotImplementedError) —

    always, until Phase 2 lands



61
62
63
# File 'lib/magik/policy.rb', line 61

def self.define(*_args, **_options)
  raise NotImplementedError, "Magik::Policy is spec-only; see docs/idea/00-build-spec.md"
end