v0.3.0
Highlights
The record-less (collection) gate grew a type: this release closes the #19 scoped-index trap and the #50 cross-type escalation together.
- Type-bound collection gates (#50). A controller opts scoped grants into collection actions by declaring both hooks:
def current_scope_record = nilplusdef current_scope_model = TheType. A scoped grant now only opens record-less gates of its own type (STI-normalized viabase_class); with no declared type the gate fails closed with a diagnosablemodel_undeclared(ormodel_invalid) reason. - Listed reads derive from the scoped list (#65). For actions in
config.collection_read_actions(default["index"]), the gate asksscope_for(...).exists?— the same id-narrowed query the list renders from — so "Owner of Report #7" finally opens the reports index and sees exactly their record. Gate and list agree by construction;full_accessscoped roles are honored here and only here. - Report mode (#37):
config.enforcement = :reportobserves would-deny requests (access.would_denyledger rows +X-Current-Scope-Reason: would_deny) instead of 403ing — the retrofit story for legacy apps. Note: only:no_grantis downgraded;model_undeclared/model_invalidstill 403. - Strict
permission_keys=(#20): unknown keys now raise instead of silently dropping (assign_permission_keys(..., scrub: true)is the deliberate opt-in to dropping). - Ungated-surface detection (#62): grid badges for provably ungated controllers, a rake task, and a production tripwire posture.
- Console 403 says why (#23):
not_full_accessreason + a short explanatory page instead of a barehead :forbidden. - Dev diagnostics (#41), error-isolated
subject_label(#22), and a stack of hardening/review fixes — including the 0.3.0 release-gate fixes (#93).
Upgrade-breaking route rename (#85, errata): org-wide role assignment is now resources :role_assignments (plural). Hosts POSTing /current_scope/role_assignment directly get a 404 — use /current_scope/role_assignments; helpers role_assignment_path (create) → role_assignments_path, remove_role_assignment_path → role_assignment_path(id).
Full details, including the who-this-changes upgrade notes: CHANGELOG.
Verified by a three-part release gate (deep multi-lens review, test audit with hand-mutation probes, security review — records in docs/reviews/) and a six-host post-release shakedown (current_scope_test_scenarios + the showcase, all green against the published gem).