Skip to content

fix(server): apply workspace/scene filters to authenticated requests (SEC-01) - #2348

Merged
wilfredmulenga merged 8 commits into
mainfrom
fix/sec-01-workspace-filter-middleware-order
Aug 18, 2026
Merged

fix(server): apply workspace/scene filters to authenticated requests (SEC-01)#2348
wilfredmulenga merged 8 commits into
mainfrom
fix/sec-01-workspace-filter-middleware-order

Conversation

@wilfredmulenga

Copy link
Copy Markdown
Contributor

Summary

UsecaseMiddleware ran globally, before the auth middleware, so its operator was always nil and the workspace/scene filters never got applied to the repos. Any authenticated user could read another workspace's projects and scenes, private ones included, since the repos ended up unrestricted.

The fix re-runs the same middleware on the private route group, after the operator is attached, so authenticated requests get their usecase container rebuilt with the operator's filters actually applied. Public routes keep the original global registration, unchanged.

Test plan

  • Unit test on UsecaseMiddleware pinning the filtering behavior with and without an operator on the context
  • End to end test through the real HTTP server, confirmed to fail against the unpatched code (returned another workspace's project) and pass with the fix
  • Confirmed the workspace owner can still read their own projects after the fix

…(SEC-01)

UsecaseMiddleware was registered globally, before the auth middleware runs,
so its operator was always nil and repos.Filtered was never applied. Any
authenticated user could read another workspace's projects and scenes,
including private ones, since the resulting repos had no read/write
restriction at all.

Re-run the same middleware on the private route group, after the operator
is attached, so authenticated requests get their usecase container rebuilt
with the operator's workspace/scene filters actually applied.

Adds a unit test pinning UsecaseMiddleware's filtering behavior and an e2e
test that goes through the real HTTP server, confirmed to fail against the
unpatched code and pass with the fix.
Copilot AI review requested due to automatic review settings August 3, 2026 09:23
@github-actions github-actions Bot added the server label Aug 3, 2026

Copilot AI 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.

Pull request overview

This PR fixes a security issue (SEC-01) where authenticated requests could access projects/scenes in other workspaces because UsecaseMiddleware was executed before the auth middleware, resulting in unscoped (unfiltered) repositories being used for private routes.

Changes:

  • Re-register UsecaseMiddleware on apiPrivateRoute after operator attachment so authenticated requests rebuild the usecase container with workspace/scene filters applied.
  • Add a unit test covering UsecaseMiddleware behavior with and without an operator present on the context.
  • Add an end-to-end GraphQL regression test ensuring cross-tenant project listing is blocked while owner access still works.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
server/internal/app/app.go Re-runs usecase construction on private routes post-auth via newUsecaseMiddleware to ensure repo scoping is applied.
server/internal/app/usecase_test.go Unit regression test verifying workspace scoping is applied when an operator is present at middleware execution time.
server/e2e/gql_project_workspace_scoping_test.go E2E regression test validating route wiring prevents cross-tenant project reads for authenticated users.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@airslice airslice 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.

Non-blocking: this fixes the immediate issue, but having UsecaseMiddleware registered globally and then re-run for authenticated routes makes the authorization behavior somewhat dependent on middleware ordering.
It might be worth considering later whether public/private usecase construction can be separated more explicitly, so authenticated routes never receive an unrestricted container in the first place.

@wilfredmulenga

Copy link
Copy Markdown
Contributor Author

Non-blocking: this fixes the immediate issue, but having UsecaseMiddleware registered globally and then re-run for authenticated routes makes the authorization behavior somewhat dependent on middleware ordering. It might be worth considering later whether public/private usecase construction can be separated more explicitly, so authenticated routes never receive an unrestricted container in the first place.

Thanks. I will create a task to refactor this.

@wilfredmulenga
wilfredmulenga merged commit 811d8f0 into main Aug 18, 2026
19 checks passed
@wilfredmulenga
wilfredmulenga deleted the fix/sec-01-workspace-filter-middleware-order branch August 18, 2026 06:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants