Skip to content

feat: add tasks:manage permission level - #540

Merged
taylorwilsdon merged 8 commits into
taylorwilsdon:mainfrom
mickey-mikey:feat/tasks-manage-permission
Mar 5, 2026
Merged

feat: add tasks:manage permission level#540
taylorwilsdon merged 8 commits into
taylorwilsdon:mainfrom
mickey-mikey:feat/tasks-manage-permission

Conversation

@mickey-mikey

@mickey-mikey mickey-mikey commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds a manage permission level for the tasks service (between readonly and full) that grants write access but denies destructive actions (delete and clear_completed)
  • Introduces a SERVICE_DENIED_ACTIONS registry and is_action_denied() helper so tools can enforce action-level restrictions based on the configured permission level
  • Guards both manage_task and manage_task_list against denied actions

Motivation

The consolidation of create_task, update_task, delete_task, and move_task into a single manage_task tool means that destructive actions can no longer be excluded via tool tiers or scope-based filtering — all actions share the same OAuth scope. This adds a permission level that lets operators allow task writes while blocking destructive operations.

Usage

uv run main.py --permissions tasks:manage   # create, update, move — no delete/clear_completed
uv run main.py --permissions tasks:full     # all actions (unchanged)

Design

  • Non-breaking: tasks:full behaviour is unchanged; manage is opt-in
  • Extensible: SERVICE_DENIED_ACTIONS can be extended for other services/levels without changing the helper
  • Minimal surface: 4 files changed

Test plan

  • All 30 permission tests pass (tests/test_permissions.py)
  • Verify --permissions tasks:manage blocks delete and clear_completed via MCP client
  • Verify --permissions tasks:full still allows all actions
  • Verify no permissions mode (default) allows all actions

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added granular Task permission levels: "readonly", "manage", and "full" (levels are cumulative).
    • "manage" permits create/update/move but blocks deletion and clearing completed tasks.
    • Task operations now enforce these action-level permission restrictions and will block disallowed actions.
  • Tests

    • Added coverage for Task scopes, levels, and action-denial behavior across permission states.
  • Documentation

    • README updated to document the new Task permission levels and behavior.

…ng other writes

The consolidated manage_task tool bundles create/update/delete/move into a
single tool, making it impossible to deny just the delete action via tool
tiers or scope-based filtering.

This adds:
- A `manage` permission level for tasks (between readonly and full)
- A SERVICE_DENIED_ACTIONS registry mapping (service, level) to denied actions
- An is_action_denied() helper that tools call before executing actions
- Guards in manage_task and manage_task_list that reject denied actions

Usage: --permissions tasks:manage
Allows create, update, move. Denies delete.
tasks:full remains unchanged (all actions allowed).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1c4083b9-aebf-48df-bb02-30dd02195448

📥 Commits

Reviewing files that changed from the base of the PR and between f26c2f9 and c7b0afa.

📒 Files selected for processing (2)
  • README.md
  • tests/test_permissions.py

📝 Walkthrough

Walkthrough

Adds Tasks granular permission levels ("readonly", "manage", "full"), a per-service denied-actions mapping and is_action_denied API, enforces denied task actions in gtasks entry points (raises UserInputError), and updates README and tests to document/verify behavior.

Changes

Cohort / File(s) Summary
Docs
README.md
Documents new Tasks granular permission levels and semantics (readonly, manage, full).
Permissions framework
auth/permissions.py
Adds SERVICE_DENIED_ACTIONS mapping, is_action_denied(service, action), is_permissions_mode(); changes set_permissions signature to accept Optional[Dict[str, str]]; typing additions and new helpers for allowed scopes.
Task operation enforcement
gtasks/tasks_tools.py
Imports is_action_denied and blocks denied actions in manage_task_list and manage_task, raising UserInputError when an action is denied by current permissions.
Tests
tests/test_permissions.py
Adds fixtures and tests for TASKS scopes and is_action_denied across permission states; exposes new public API symbols in tests.
Manifests / config
manifest-file-name, manifest_file, pyproject.toml
Minor manifest/config line changes.

Sequence Diagram(s)

sequenceDiagram
  participant User as "User / Client"
  participant TasksAPI as "gtasks.tasks_tools"
  participant Perms as "auth.permissions"
  participant Store as "TaskStore"

  User->>TasksAPI: request(action: create/update/move/delete/clear_completed)
  TasksAPI->>Perms: is_action_denied("tasks", action)?
  alt denied
    Perms-->>TasksAPI: true
    TasksAPI-->>User: raise UserInputError (action denied)
  else allowed
    Perms-->>TasksAPI: false
    TasksAPI->>Store: perform action
    Store-->>TasksAPI: result
    TasksAPI-->>User: success/response
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped through code with careful paws,
New levels set and tidy laws.
Manage moves but delete stays barred,
Clear crumbs spared — the tasks are guarded,
I nibble bugs and leave it yours. 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: add tasks:manage permission level' accurately and concisely describes the main feature being added, which is a new permission level for task management.
Description check ✅ Passed The pull request description includes a comprehensive summary, clear motivation, usage examples, design principles, and test plan, covering all key aspects beyond the template requirements.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@auth/permissions.py`:
- Around line 139-143: SERVICE_DENIED_ACTIONS currently denies only "delete" for
the "tasks" -> "manage" scope, leaving the destructive "clear_completed" action
allowed; update the SERVICE_DENIED_ACTIONS entry for the "tasks" key (under the
"manage" subkey) to include "clear_completed" in the frozenset alongside
"delete" so that both destructive actions are denied by the permission
enforcement logic.

ℹ️ Review info
Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b0834a6a-ab7f-437b-9c0d-a73d539ed71d

📥 Commits

Reviewing files that changed from the base of the PR and between 89e1974 and 3777910.

📒 Files selected for processing (4)
  • README.md
  • auth/permissions.py
  • gtasks/tasks_tools.py
  • tests/test_permissions.py

Comment thread auth/permissions.py
Addresses CodeRabbit review — clear_completed is destructive and should
be blocked alongside delete at the manage permission level.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/test_permissions.py`:
- Around line 139-180: Tests in TestIsActionDenied leak module-global permission
state because set_permissions() mutates shared state; add a per-test reset so
each test starts with a clean state by adding a teardown_method (or
setup_method) on the TestIsActionDenied class that calls set_permissions(None)
(or call set_permissions(None) at start of each test) to ensure set_permissions
is cleared between tests; locate TestIsActionDenied and add the
teardown_method(self, method) that invokes set_permissions(None) to avoid
order-dependent failures.

ℹ️ Review info
Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c053f92c-3863-4f73-84b5-1e5bca68d8ea

📥 Commits

Reviewing files that changed from the base of the PR and between 3777910 and 0fce7c7.

📒 Files selected for processing (2)
  • auth/permissions.py
  • tests/test_permissions.py

Comment thread tests/test_permissions.py
- Add docstrings to test methods for coverage threshold
- Add autouse fixture to reset permission state between tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/test_permissions.py (1)

131-135: Expand tasks:full assertion to verify full cumulative inheritance.

This test currently checks write scope only; asserting readonly scope too will better guard cumulative behavior regressions.

Suggested test tweak
     def test_tasks_full_includes_write_scope(self):
         """Full level should include write scope from manage."""
         scopes = get_scopes_for_permission("tasks", "full")
         assert TASKS_SCOPE in scopes
+        assert TASKS_READONLY_SCOPE in scopes
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_permissions.py` around lines 131 - 135, The test
test_tasks_full_includes_write_scope should also assert that the readonly
permission is included to validate cumulative inheritance; after calling
get_scopes_for_permission("tasks", "full") and asserting TASKS_SCOPE is in
scopes, add an assertion that TASKS_READONLY_SCOPE (or the constant representing
the tasks readonly scope used elsewhere) is also in scopes so the test verifies
both write and readonly scopes are present for "tasks:full".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@tests/test_permissions.py`:
- Around line 131-135: The test test_tasks_full_includes_write_scope should also
assert that the readonly permission is included to validate cumulative
inheritance; after calling get_scopes_for_permission("tasks", "full") and
asserting TASKS_SCOPE is in scopes, add an assertion that TASKS_READONLY_SCOPE
(or the constant representing the tasks readonly scope used elsewhere) is also
in scopes so the test verifies both write and readonly scopes are present for
"tasks:full".

ℹ️ Review info
Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c63e6f2b-196c-44b8-acde-04ff2476b909

📥 Commits

Reviewing files that changed from the base of the PR and between 0fce7c7 and 69dd506.

📒 Files selected for processing (1)
  • tests/test_permissions.py

Addresses CodeRabbit Review 3 nitpick: verify TASKS_READONLY_SCOPE is
present at full level, confirming cumulative scope expansion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/test_permissions.py (1)

137-140: Consider moving this test to TestParsePermissionsArg.

This test validates parse_permissions_arg() behavior but is placed in TestGetScopesForPermission. Moving it to the appropriate class would improve test organization and discoverability.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_permissions.py` around lines 137 - 140, The test method
test_tasks_manage_is_valid_level belongs with other parse_permissions_arg tests:
move the method from the TestGetScopesForPermission test case into the
TestParsePermissionsArg test class and keep its body unchanged (calling
parse_permissions_arg(["tasks:manage"]) and asserting {"tasks": "manage"}) so it
lives next to other parse_permissions_arg-related tests for better organization.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@tests/test_permissions.py`:
- Around line 137-140: The test method test_tasks_manage_is_valid_level belongs
with other parse_permissions_arg tests: move the method from the
TestGetScopesForPermission test case into the TestParsePermissionsArg test class
and keep its body unchanged (calling parse_permissions_arg(["tasks:manage"]) and
asserting {"tasks": "manage"}) so it lives next to other
parse_permissions_arg-related tests for better organization.

ℹ️ Review info
Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dec2f00d-0828-4608-ae04-deffc7ac2dca

📥 Commits

Reviewing files that changed from the base of the PR and between 69dd506 and acc3e66.

📒 Files selected for processing (1)
  • tests/test_permissions.py

…nsArg

Addresses CodeRabbit Review 4 nitpick: the test validates
parse_permissions_arg() so it belongs with that test class.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Mar 4, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Reviews resumed.

@taylorwilsdon taylorwilsdon self-assigned this Mar 5, 2026
@taylorwilsdon taylorwilsdon added the enhancement New feature or request label Mar 5, 2026
@taylorwilsdon

Copy link
Copy Markdown
Owner

Appreciate the diligent PR feedback updates! Will get this merged today.

@taylorwilsdon
taylorwilsdon merged commit dc4cefc into taylorwilsdon:main Mar 5, 2026
4 of 5 checks passed
@mickey-mikey
mickey-mikey deleted the feat/tasks-manage-permission branch March 19, 2026 05:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants