Feat v0.9.9 surface access via roles

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-03 19:52:47 +00:00
parent b0e9dd7f80
commit 75dfdb3dcd
9 changed files with 359 additions and 6 deletions

View File

@@ -2,6 +2,36 @@
All notable changes to Armature are documented here.
## v0.9.9 — Surface Access via Roles
Surfaces can now gate access by team role. A manifest declaring
`"access": "role:approver"` restricts the surface to users who hold the
`approver` role in any team — consistent with how `group:NAME` works.
**New surface access level: `role:ROLENAME`**
- Added to both `evaluateAccess()` and `validAccessLevels()` validation
- User must hold the specified role in at least one team (any-team
semantics — no team context needed in the URL)
- System admins bypass role checks, consistent with `RequireRole`
middleware
- Unauthenticated users get redirected to login
- Graceful fallback: if Teams store is nil, access is denied (fail closed)
**New store method: `HasRoleInAnyTeam(ctx, userID, role)`**
- Checks both primary role (`team_members`) and additional roles
(`team_user_roles`) across all teams in a single query
- Implemented for both SQLite and PostgreSQL
**Refactor:** `evaluateAccess` promoted from package-level function to
`Engine` method to enable store access for role lookups.
**Tests:** 10 new tests — 5 handler integration tests (granted, denied,
unauthenticated, admin bypass, nil store), 3 store tests
(primary role, additional role, no match), 2 validation tests
(valid role, empty role name)
## v0.9.8 — Conditional Routing → SDK Primitive
Promotes the workflow branch-rule engine to a generic Starlark SDK