Skip to content

fix(tasks): require owner permission to cancel a task via REST#308

Merged
asherfink merged 1 commit into
mainfrom
asher.fink/fix-task-cancel-owner-only
Jun 15, 2026
Merged

fix(tasks): require owner permission to cancel a task via REST#308
asherfink merged 1 commit into
mainfrom
asher.fink/fix-task-cancel-owner-only

Conversation

@asherfink

@asherfink asherfink commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Problem

POST /tasks/{task_id}/cancel authorizes AuthorizedOperationType.update. Editors hold update, so a task editor who is not the owner can cancel a task through the REST route. Cancellation is intended to be owner-only.

The RPC task/cancel path already authorizes the owner-only cancel action, so the two entry points to the same operation disagreed.

Fix

Authorize cancel on the REST route, matching the RPC path and the schema. The sibling lifecycle routes (complete/fail/terminate/timeout) intentionally keep update — those are state transitions, not the owner-only cancel.

Tests

Adds a unit test pinning the REST cancel route to the cancel action (mirrors the existing per-RPC operation-routing tests). End-to-end behavioral coverage lives in the authorization e2e suite.

Greptile Summary

This PR fixes a privilege escalation bug in the REST POST /tasks/{task_id}/cancel endpoint where it previously authorized update (allowing editors), but cancellation is owner-only. The fix aligns the REST route with the RPC task/cancel path by switching to AuthorizedOperationType.cancel.

  • tasks.py: Changes cancel_task's DAuthorizedId call from AuthorizedOperationType.update to AuthorizedOperationType.cancel, adding a clarifying comment about the intent.
  • test_tasks_authz.py: Adds TestRestCancelRouteRequiresOwner — a unit test that introspects the function signature to assert the dependency checks cancel, mirroring the existing per-RPC routing tests.

Confidence Score: 5/5

Safe to merge — the change is a one-line auth operation swap on a single route, and the new test directly pins the expected behavior.

The change is minimal and surgical: one enum value replaced in one route, with a well-scoped unit test that introspects the function signature at test time to verify the correct operation is wired. The sibling lifecycle routes (complete/fail/terminate/timeout) are intentionally left on update and are unaffected. The RPC path already used cancel and is also untouched. No edge cases, no new dependencies, no schema changes.

No files require special attention.

Important Files Changed

Filename Overview
agentex/src/api/routes/tasks.py Single-line auth fix: cancel_task's DAuthorizedId now uses AuthorizedOperationType.cancel instead of update; comment explains the intentional difference from sibling lifecycle routes.
agentex/tests/unit/api/test_tasks_authz.py New TestRestCancelRouteRequiresOwner class introspects the cancel_task signature at test time and asserts the dependency resolves to the cancel operation; mirrors existing RPC routing test patterns.

Sequence Diagram

sequenceDiagram
    participant Client
    participant REST as REST POST /tasks/{id}/cancel
    participant RPC as RPC task/cancel
    participant Authz as Authorization Service

    Note over REST,Authz: Before this PR (bug)
    Client->>REST: "POST /tasks/{id}/cancel"
    REST->>Authz: check(task, update) editors allowed
    Authz-->>REST: authorized (editor or owner)
    REST-->>Client: task canceled

    Note over REST,Authz: After this PR (fix)
    Client->>REST: "POST /tasks/{id}/cancel"
    REST->>Authz: check(task, cancel) owner-only
    Authz-->>REST: authorized (owner only)
    REST-->>Client: task canceled

    Client->>RPC: task/cancel
    RPC->>Authz: check(task, cancel) owner-only (unchanged)
    Authz-->>RPC: authorized (owner only)
    RPC-->>Client: task canceled
Loading

Reviews (1): Last reviewed commit: "fix(tasks): require owner permission to ..." | Re-trigger Greptile

POST /tasks/{task_id}/cancel authorized the `update` permission, which editors
hold, so a task editor who is not the owner could cancel a task through the REST
route. Cancellation is owner-only — the RPC task/cancel path already checks the
`cancel` action — so the two entry points disagreed. Align the REST route to
check `cancel`. The sibling lifecycle routes (complete/fail/terminate/timeout)
intentionally keep `update`.

Adds a unit test pinning the REST cancel route to the `cancel` action.
@asherfink asherfink marked this pull request as ready for review June 15, 2026 19:38
@asherfink asherfink requested a review from a team as a code owner June 15, 2026 19:38
@asherfink asherfink merged commit aff7376 into main Jun 15, 2026
31 checks passed
@asherfink asherfink deleted the asher.fink/fix-task-cancel-owner-only branch June 15, 2026 22:13
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.

2 participants