feat(security): add permission system #448

Merged
CoreRasurae merged 1 commit from feature/m7-post-permissions into master 2026-02-28 21:07:22 +00:00
Member

Description

Add a namespace/project/plan/skill permission system with role-based access control. Implements four role levels (owner, admin, editor, viewer) with default-deny semantics and configurable allow overrides. Enforcement hooks are applied at CLI/service boundaries and are server-only; local mode returns permissive defaults via CLEVERAGENTS_SERVER_MODE environment variable.

Domain model (permission.py): PermissionRole, PermissionScope, and PermissionAction enums; RoleBinding, PermissionCheck, and PermissionPolicy Pydantic models; ROLE_PERMISSIONS matrix mapping roles to allowed actions per scope; DEFAULT_LOCAL_ROLE_MAPPING for local-mode fallback.

Service (permission_service.py): PermissionService class with check_permission, get_role_bindings, add_binding, remove_binding, and is_local_mode methods; enforce_permission decorator for declarative enforcement at service boundaries; module-level default service pattern with get_default_permission_service().

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactoring (no functional changes)
  • Documentation update
  • Test improvements
  • CI/CD changes

Quality Checklist

  • Code follows the project's coding standards (see CONTRIBUTING.md)
  • All public/protected methods have argument validation
  • Static typing is complete (no Any unless justified)
  • nox -s typecheck passes with no errors
  • nox -s lint passes with no errors
  • Unit tests written/updated (Behave scenarios in features/)
  • Integration tests written/updated (Robot suites in robot/) if applicable
  • Coverage remains above 85% (nox -s coverage_report)
  • No security issues introduced (nox -s security_scan)
  • No dead code introduced (nox -s dead_code)
  • Documentation updated if behavior changed

Testing

43 BDD scenarios in features/permission_system.feature covering allow/deny decisions, missing roles, server-disabled local mode, role binding CRUD, scope/action matrix, and decorator enforcement. 18 Robot Framework integration tests in robot/permission_system.robot with stubbed server client. Reference documentation in docs/reference/permissions.md.

Test Commands Run

nox -s unit_tests        # Behave tests
nox -s typecheck         # Type checking
nox -s lint              # Linting
nox -s coverage_report   # Coverage

Closes #344

Implementation Notes

  • Server mode is toggled by the CLEVERAGENTS_SERVER_MODE environment variable. When unset or falsy, all permission checks return allow (local mode).
  • The enforce_permission decorator extracts scope and action from function arguments and raises PermissionError when access is denied in server mode.
  • Role hierarchy is flat (no inheritance); each role has an explicit set of allowed actions per scope defined in ROLE_PERMISSIONS.
  • DEFAULT_LOCAL_ROLE_MAPPING provides a sensible owner-level binding for local-mode operations so that code paths requiring a role binding still function without a server.
## Description Add a namespace/project/plan/skill permission system with role-based access control. Implements four role levels (owner, admin, editor, viewer) with default-deny semantics and configurable allow overrides. Enforcement hooks are applied at CLI/service boundaries and are server-only; local mode returns permissive defaults via `CLEVERAGENTS_SERVER_MODE` environment variable. **Domain model** (`permission.py`): `PermissionRole`, `PermissionScope`, and `PermissionAction` enums; `RoleBinding`, `PermissionCheck`, and `PermissionPolicy` Pydantic models; `ROLE_PERMISSIONS` matrix mapping roles to allowed actions per scope; `DEFAULT_LOCAL_ROLE_MAPPING` for local-mode fallback. **Service** (`permission_service.py`): `PermissionService` class with `check_permission`, `get_role_bindings`, `add_binding`, `remove_binding`, and `is_local_mode` methods; `enforce_permission` decorator for declarative enforcement at service boundaries; module-level default service pattern with `get_default_permission_service()`. ## Type of Change - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] Refactoring (no functional changes) - [ ] Documentation update - [ ] Test improvements - [ ] CI/CD changes ## Quality Checklist - [x] Code follows the project's coding standards (see CONTRIBUTING.md) - [x] All public/protected methods have argument validation - [x] Static typing is complete (no `Any` unless justified) - [x] `nox -s typecheck` passes with no errors - [x] `nox -s lint` passes with no errors - [x] Unit tests written/updated (Behave scenarios in `features/`) - [x] Integration tests written/updated (Robot suites in `robot/`) if applicable - [x] Coverage remains above 85% (`nox -s coverage_report`) - [x] No security issues introduced (`nox -s security_scan`) - [x] No dead code introduced (`nox -s dead_code`) - [x] Documentation updated if behavior changed ## Testing 43 BDD scenarios in `features/permission_system.feature` covering allow/deny decisions, missing roles, server-disabled local mode, role binding CRUD, scope/action matrix, and decorator enforcement. 18 Robot Framework integration tests in `robot/permission_system.robot` with stubbed server client. Reference documentation in `docs/reference/permissions.md`. ### Test Commands Run ```bash nox -s unit_tests # Behave tests nox -s typecheck # Type checking nox -s lint # Linting nox -s coverage_report # Coverage ``` ## Related Issues Closes #344 ## Implementation Notes - Server mode is toggled by the `CLEVERAGENTS_SERVER_MODE` environment variable. When unset or falsy, all permission checks return allow (local mode). - The `enforce_permission` decorator extracts scope and action from function arguments and raises `PermissionError` when access is denied in server mode. - Role hierarchy is flat (no inheritance); each role has an explicit set of allowed actions per scope defined in `ROLE_PERMISSIONS`. - `DEFAULT_LOCAL_ROLE_MAPPING` provides a sensible owner-level binding for local-mode operations so that code paths requiring a role binding still function without a server.
CoreRasurae added this to the v3.6.0 milestone 2026-02-25 23:47:10 +00:00
CoreRasurae force-pushed feature/m7-post-permissions from e907ffa473
All checks were successful
CI / lint (pull_request) Successful in 25s
CI / quality (pull_request) Successful in 29s
CI / security (pull_request) Successful in 52s
CI / typecheck (pull_request) Successful in 1m6s
CI / benchmark-publish (pull_request) Has been skipped
CI / build (pull_request) Successful in 22s
CI / integration_tests (pull_request) Successful in 4m41s
CI / benchmark-regression (pull_request) Successful in 23m1s
CI / unit_tests (pull_request) Successful in 32m19s
CI / docker (pull_request) Successful in 1m2s
CI / coverage (pull_request) Successful in 1h54m47s
to 44ed1208e4
All checks were successful
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 15s
CI / build (pull_request) Successful in 19s
CI / quality (pull_request) Successful in 27s
CI / security (pull_request) Successful in 48s
CI / typecheck (pull_request) Successful in 1m0s
CI / integration_tests (pull_request) Successful in 4m14s
CI / unit_tests (pull_request) Successful in 10m53s
CI / docker (pull_request) Successful in 52s
CI / benchmark-regression (pull_request) Successful in 22m14s
CI / coverage (pull_request) Successful in 37m30s
2026-02-26 22:03:24 +00:00
Compare
brent.edwards left a comment

Review Summary

Scope: new permission system domain models + PermissionService + tests/bench/docs. Security-sensitive area reviewed per playbook.

CI status isn’t visible via the API on my side. Please confirm required checks per docs/development/ci-cd.md are green (lint, typecheck, security, quality, unit_tests, integration_tests, coverage, build, docker).

Findings

P2:should-fixPermissionService.check_permission() does not validate/normalize principal or scope_id. RoleBinding trims/validates, but checks accept raw strings, so whitespace or empty values can silently miss bindings. Recommend stripping + empty checks (raise ValueError) or normalizing via a small helper before key lookup.

  • Code: src/cleveragents/application/services/permission_service.py (check_permission)

P2:should-fix — Docs and docstrings imply “server-side enforcement deferred” and “hooks at CLI/service boundaries”, but there are no call sites wiring enforce_permission into CLI or services yet. Please align docs with current behavior or add a minimal integration point.

  • Doc: docs/reference/permissions.md
  • Code: src/cleveragents/application/services/permission_service.py (module docstring)

P3:nitdocs/reference/permissions.md isn’t listed in the reference nav. Add it to docs/gen_ref_pages.py so it shows in the Reference sidebar.

Positive Notes

  • Domain model + service API shape is clean and matches existing patterns.
  • Behave + Robot coverage is comprehensive for local/server mode behavior.
  • Benchmarks are clear and use the same env toggles as tests.
## Review Summary Scope: new permission system domain models + PermissionService + tests/bench/docs. Security-sensitive area reviewed per playbook. CI status isn’t visible via the API on my side. Please confirm required checks per `docs/development/ci-cd.md` are green (lint, typecheck, security, quality, unit_tests, integration_tests, coverage, build, docker). ## Findings **P2:should-fix** — `PermissionService.check_permission()` does not validate/normalize `principal` or `scope_id`. RoleBinding trims/validates, but checks accept raw strings, so whitespace or empty values can silently miss bindings. Recommend stripping + empty checks (raise ValueError) or normalizing via a small helper before key lookup. - Code: `src/cleveragents/application/services/permission_service.py` (`check_permission`) **P2:should-fix** — Docs and docstrings imply “server-side enforcement deferred” and “hooks at CLI/service boundaries”, but there are no call sites wiring `enforce_permission` into CLI or services yet. Please align docs with current behavior or add a minimal integration point. - Doc: `docs/reference/permissions.md` - Code: `src/cleveragents/application/services/permission_service.py` (module docstring) **P3:nit** — `docs/reference/permissions.md` isn’t listed in the reference nav. Add it to `docs/gen_ref_pages.py` so it shows in the Reference sidebar. ## Positive Notes - Domain model + service API shape is clean and matches existing patterns. - Behave + Robot coverage is comprehensive for local/server mode behavior. - Benchmarks are clear and use the same env toggles as tests.
CoreRasurae force-pushed feature/m7-post-permissions from 44ed1208e4
All checks were successful
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 15s
CI / build (pull_request) Successful in 19s
CI / quality (pull_request) Successful in 27s
CI / security (pull_request) Successful in 48s
CI / typecheck (pull_request) Successful in 1m0s
CI / integration_tests (pull_request) Successful in 4m14s
CI / unit_tests (pull_request) Successful in 10m53s
CI / docker (pull_request) Successful in 52s
CI / benchmark-regression (pull_request) Successful in 22m14s
CI / coverage (pull_request) Successful in 37m30s
to 30eee519ca
All checks were successful
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 14s
CI / build (pull_request) Successful in 14s
CI / quality (pull_request) Successful in 16s
CI / security (pull_request) Successful in 30s
CI / typecheck (pull_request) Successful in 36s
CI / integration_tests (pull_request) Successful in 2m37s
CI / unit_tests (pull_request) Successful in 19m48s
CI / docker (pull_request) Successful in 1m3s
CI / benchmark-regression (pull_request) Successful in 20m15s
CI / coverage (pull_request) Successful in 47m29s
2026-02-27 17:13:18 +00:00
Compare
brent.edwards approved these changes 2026-02-27 20:25:20 +00:00
Dismissed
brent.edwards left a comment

Approved!

Approved!
CoreRasurae force-pushed feature/m7-post-permissions from 30eee519ca
All checks were successful
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 14s
CI / build (pull_request) Successful in 14s
CI / quality (pull_request) Successful in 16s
CI / security (pull_request) Successful in 30s
CI / typecheck (pull_request) Successful in 36s
CI / integration_tests (pull_request) Successful in 2m37s
CI / unit_tests (pull_request) Successful in 19m48s
CI / docker (pull_request) Successful in 1m3s
CI / benchmark-regression (pull_request) Successful in 20m15s
CI / coverage (pull_request) Successful in 47m29s
to 64af753aab
All checks were successful
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 15s
CI / build (pull_request) Successful in 17s
CI / quality (pull_request) Successful in 19s
CI / security (pull_request) Successful in 32s
CI / typecheck (pull_request) Successful in 36s
CI / integration_tests (pull_request) Successful in 2m40s
CI / unit_tests (pull_request) Successful in 11m42s
CI / docker (pull_request) Successful in 40s
CI / benchmark-regression (pull_request) Successful in 21m35s
CI / coverage (pull_request) Successful in 45m10s
CI / lint (push) Successful in 12s
CI / quality (push) Successful in 18s
CI / build (push) Successful in 23s
CI / security (push) Successful in 32s
CI / typecheck (push) Successful in 57s
CI / benchmark-regression (push) Has been skipped
CI / integration_tests (push) Successful in 2m43s
CI / unit_tests (push) Successful in 12m13s
CI / benchmark-publish (push) Successful in 12m19s
CI / docker (push) Successful in 1m2s
CI / coverage (push) Successful in 1h26m6s
2026-02-28 20:21:31 +00:00
Compare
CoreRasurae dismissed brent.edwards's review 2026-02-28 20:21:31 +00:00
Reason:

New commits pushed, approval review dismissed automatically according to repository settings

CoreRasurae scheduled this pull request to auto merge when all checks succeed 2026-02-28 20:33:14 +00:00
CoreRasurae deleted branch feature/m7-post-permissions 2026-02-28 21:07:22 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cleveragents/cleveragents-core!448
No description provided.