Skip to content

TIGER-410: enforce the ACL §1a role-scope standard in code (Service primitive + Media + blog taxonomy) - #381

Merged
WebTigers merged 2 commits into
mainfrom
feat/tiger-410-org-scope-conformance
Oct 31, 2026
Merged

WebTigers merged 2 commits into
mainfrom
feat/tiger-410-org-scope-conformance

Conversation

@WebTigers

Copy link
Copy Markdown
Owner

Implements the ACL §1a "role scope as the standard" doc (merged in PR #373) — the standard shipped, the enforcing code did not. [TIGER-410]

What

A single org-scope authority on Tiger_Service:

  • RESOURCE_ALL_ORGS + _orgId() / _orgScope() / _inOrgScope().
  • _orgScope() returns null (no predicate = app-wide) or [ownOrg, ''] (own org + global rows).
  • The ACL resource Tiger_Tenancy_AllOrgs (read granted to role admin, so superadmin/developer inherit; manager/supermanager don't) decides which — role configuration, not an if-on-role.

Callers moved onto the primitive:

  • Media — Tiger_Model_Media::datatable() takes org_scope (array | null) instead of a hard org_id; modules/media row/manage guards use _inOrgScope(). Generalizes the narrower TIGER-64 single-org scoping.
  • Blog taxonomy — modules/blog vocabulary listing treats null as app-wide, array as explicit scope.

New: tests/Unit/Service/OrgScopeTest.php.

Why

Multi-tenant isolation must hold for normal users (own org only), but the prior hard org_id scoping also walled app-wide admins out of the orgs they administer. One authority both callers use, per the no-$db-predicates-in-services convention.

Scope

Covers the shared Service primitive + Media + blog taxonomy. Sibling TIGER-391 (CMS surface still hard-scoped) is NOT in this PR.

Provenance

Recovered from uncommitted work that was sitting on an unrelated (already-merged) branch; lifted cleanly onto origin/main via a fresh branch. php -l clean; full suite runs in CI.

🤖 Generated with Claude Code

https://claude.ai/code/session_01ASauLLscjqdsNqBNsx2Typ

WebTigers and others added 2 commits October 31, 2026 01:41
The §1a "role scope as the standard" doc shipped (PR #373); this is the code
that enforces it.

- Tiger_Service gains the one org-scope authority: RESOURCE_ALL_ORGS +
  _orgId()/_orgScope()/_inOrgScope(). _orgScope() returns null (no predicate =
  app-wide) or [ownOrg, ''] (own org + global rows); the ACL resource
  Tiger_Tenancy_AllOrgs (read -> role admin) decides which, so it is role
  configuration, not an if-on-role.
- Media (Tiger_Model_Media + modules/media) and blog taxonomy (modules/blog)
  move off hard single-org scoping onto the shared primitive, so an app-wide
  admin is no longer walled out of orgs it administers while tenants stay
  isolated from each other. Generalizes the narrower TIGER-64 media scoping.
- tests/Unit/Service/OrgScopeTest.php.

Sibling TIGER-391 (CMS surface still hard-scoped) is not covered here.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ASauLLscjqdsNqBNsx2Typ
…dia)

The two media cross-tenant cases asserted the PRE-§1a rule (an admin is refused
on another org's row). §1a makes "reach every org" a CAPABILITY granted at
`admin` in core, and media is an admin-gated feature, so an app-wide admin
legitimately manages every org's media — the cases now assert that (crosses +
mutates/removes B's row). The tenant WALL (a role without the capability is
scoped to its own org) is pinned at the primitive in Unit/Service/OrgScopeTest,
where that decision lives. The cms-menu cases still assert denial: Cms_Service_Menu
is out of scope for TIGER-410 and not yet converted, so they pin its current
behaviour. Class docblock rewritten to say all of this.

Fixes the integration + coverage CI failures (the only two reds on this PR).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ASauLLscjqdsNqBNsx2Typ
@WebTigers
WebTigers merged commit 7a29013 into main Oct 31, 2026
14 checks passed
@WebTigers
WebTigers deleted the feat/tiger-410-org-scope-conformance branch October 31, 2026 13:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant