Files
rbac/docs/adr/ADR-001-bitset-permissions.md
Rene Nochebuena 0864f031a1 feat(rbac): initial stable release v0.9.0
Foundational identity and permission types for role-based access control — bit-set PermissionMask, immutable Identity value type, and PermissionProvider interface.

What's included:
- `Identity` value type with NewIdentity / WithTenant constructors and SetInContext / FromContext context helpers
- `Permission` (int64 bit position) and `PermissionMask` (int64 bit-set) with O(1) Has and non-mutating Grant
- `PermissionProvider` interface for DB-backed ResolveMask(ctx, uid, resource) resolution

Tested-via: todo-api POC integration
Reviewed-against: docs/adr/
2026-03-18 13:25:43 -06:00

52 lines
2.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR-001: Bit-Set Permissions
**Status:** Accepted
**Date:** 2026-03-18
## Context
Applications need to represent and check whether a user holds a specific capability
on a resource. Common approaches include: role strings (e.g. `"admin"`, `"editor"`),
permission string lists, or bit-set integers. Role strings require the application to
know which capabilities each role implies, making capability checks indirect and
requiring either a lookup table or a case statement everywhere. Permission string
lists are flexible but expensive to check (linear scan) and verbose to store.
## Decision
`Permission` is typed as `int64` and represents a named bit position (062).
Applications define their own constants using this type:
```go
const (
Read rbac.Permission = 0
Write rbac.Permission = 1
Delete rbac.Permission = 2
)
```
`PermissionMask` is also typed as `int64` and holds the resolved OR-combination of
granted permission bits. It is returned by `PermissionProvider.ResolveMask` and
checked with `PermissionMask.Has(p Permission) bool`.
The upper bound is 62 (not 63) to keep the value within the positive range of a
signed 64-bit integer, avoiding sign-bit ambiguity. `Has` and `Grant` both return
false/no-op for out-of-range values (`p < 0 || p >= 63`).
`Grant(p Permission) PermissionMask` is provided for constructing masks in tests and
in-memory provider implementations, returning a new mask with the bit set without
mutating the receiver.
## Consequences
- Permission checks are O(1) bitwise operations — no map lookup, no string comparison.
- A single `int64` column stores up to 62 independent permission bits per user-resource
pair in the database.
- Applications must define their own named constants; this package does not enumerate
domain permissions. This keeps `rbac` domain-agnostic.
- The 62-bit limit is sufficient for all foreseeable use cases; if an application
needs more than 62 orthogonal permissions on a single resource, a structural
refactor (multiple resources or resource hierarchies) is the appropriate response.
- `PermissionProvider` is the extension point for DB-backed resolution; the bit-set
design does not constrain the storage schema.