[PR #213] fix(api): enforce object-level authorization on Flow update/delete/read #4131

Open
opened 2026-08-30 17:55:17 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/reconurge/flowsint/pull/213
Author: @dextmorgn
Created: 8/23/2026
Status: 🔄 Open

Base: main ← Head: fix/flow-object-level-authz


📝 Commits (1)

  • dd9caf2 fix(api): enforce object-level authorization on Flow update/delete/read

📊 Changes

7 files changed (+87 additions, -12 deletions)

View changed files

➕ flowsint-api/alembic/versions/c7d1f0a92b3e_add_owner_id_to_flows.py (+45 -0)
📝 flowsint-api/app/api/routes/flows.py (+13 -4)
📝 flowsint-api/app/api/schemas/flow.py (+1 -0)
📝 flowsint-core/src/flowsint_core/core/models.py (+5 -0)
📝 flowsint-core/src/flowsint_core/core/repositories/flow_repository.py (+8 -2)
📝 flowsint-core/src/flowsint_core/core/services/flow_service.py (+14 -6)
📝 flowsint-core/tests/services/test_timezone_timestamps.py (+1 -0)

📄 Description

Summary

Flow had no ownership concept at all in the schema, so this required adding one:

  • New nullable flows.owner_id column (migration c7d1f0a92b3e). Pre-existing rows stay NULL, treated as legacy/shared: readable by everyone, but not editable or deletable by anyone via the API (no global admin role exists in this app to grant that safely).
  • FlowService.create stamps owner_id from the authenticated caller.
  • FlowService.get_by_id / update / delete now take user_id and raise PermissionDeniedError (→ HTTP 403) on ownership mismatch.
  • FlowRepository.get_all_with_optional_category filters to owner_id IS NULL OR owner_id = :user_id, fixing the "everyone sees everyone's flows" listing issue.
  • flows.py routes wire current_user.id through to all of the above and map PermissionDeniedError to 403.
  • FlowRead schema exposes owner_id so the frontend can gate edit/delete UI.

Test plan

  • flowsint-core test suite passes (397 passed), including updated test_flow_service_create_uses_timezone_aware_timestamps (now passes owner_id)
  • flowsint-core/tests/repositories/test_flow_repository.py passes unchanged (new user_id param defaults to None)
  • Manual verification against a running flowsint dev DB: PUT/DELETE /api/flows/{id} from a non-owner account now returns 403; GET /api/flows no longer returns other users' flows

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/reconurge/flowsint/pull/213 **Author:** [@dextmorgn](https://github.com/dextmorgn) **Created:** 8/23/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `fix/flow-object-level-authz` --- ### 📝 Commits (1) - [`dd9caf2`](https://github.com/reconurge/flowsint/commit/dd9caf2cb1861865c71abbe9f45bcc7d3a257bf0) fix(api): enforce object-level authorization on Flow update/delete/read ### 📊 Changes **7 files changed** (+87 additions, -12 deletions) <details> <summary>View changed files</summary> ➕ `flowsint-api/alembic/versions/c7d1f0a92b3e_add_owner_id_to_flows.py` (+45 -0) 📝 `flowsint-api/app/api/routes/flows.py` (+13 -4) 📝 `flowsint-api/app/api/schemas/flow.py` (+1 -0) 📝 `flowsint-core/src/flowsint_core/core/models.py` (+5 -0) 📝 `flowsint-core/src/flowsint_core/core/repositories/flow_repository.py` (+8 -2) 📝 `flowsint-core/src/flowsint_core/core/services/flow_service.py` (+14 -6) 📝 `flowsint-core/tests/services/test_timezone_timestamps.py` (+1 -0) </details> ### 📄 Description ## Summary Flow had no ownership concept at all in the schema, so this required adding one: - New nullable `flows.owner_id` column (migration `c7d1f0a92b3e`). Pre-existing rows stay `NULL`, treated as legacy/shared: readable by everyone, but not editable or deletable by anyone via the API (no global admin role exists in this app to grant that safely). - `FlowService.create` stamps `owner_id` from the authenticated caller. - `FlowService.get_by_id` / `update` / `delete` now take `user_id` and raise `PermissionDeniedError` (→ HTTP 403) on ownership mismatch. - `FlowRepository.get_all_with_optional_category` filters to `owner_id IS NULL OR owner_id = :user_id`, fixing the "everyone sees everyone's flows" listing issue. - `flows.py` routes wire `current_user.id` through to all of the above and map `PermissionDeniedError` to 403. - `FlowRead` schema exposes `owner_id` so the frontend can gate edit/delete UI. ## Test plan - [x] `flowsint-core` test suite passes (397 passed), including updated `test_flow_service_create_uses_timezone_aware_timestamps` (now passes `owner_id`) - [x] `flowsint-core/tests/repositories/test_flow_repository.py` passes unchanged (new `user_id` param defaults to `None`) - [ ] Manual verification against a running flowsint dev DB: `PUT`/`DELETE /api/flows/{id}` from a non-owner account now returns 403; `GET /api/flows` no longer returns other users' flows --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-08-30 17:55:17 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/flowsint#4131