Skip to content

feat(api): restrict blocked teams per-endpoint via OpenAPI extension#2456

Draft
mishushakov wants to merge 1 commit intomainfrom
mishushakov/block-team-endpoints
Draft

feat(api): restrict blocked teams per-endpoint via OpenAPI extension#2456
mishushakov wants to merge 1 commit intomainfrom
mishushakov/block-team-endpoints

Conversation

@mishushakov
Copy link
Copy Markdown
Member

Summary

  • Blocked teams now authenticate and reach most endpoints; mutation endpoints opt in to blocking via x-disable-team-blocked: true in spec/openapi.yml (applied to 18 sandbox/template/volume routes).
  • New middleware.BlockedTeam scans the embedded swagger at startup to build a (method, gin-route) lookup and returns 403 for blocked teams on marked routes; wired into packages/api/main.go after auth and LD context, before rate limiting.
  • validateTeamUsage no longer short-circuits on IsBlocked (ban check unchanged); api.gen.go regenerated so the embedded spec carries the new extensions.

Test plan

  • go test ./packages/api/... ./packages/auth/... (passing locally)
  • Manual: blocked team can GET /sandboxes but gets 403 on POST /sandboxes, DELETE /sandboxes/{id}, POST /volumes, etc.
  • Manual: non-blocked team behavior unchanged on all endpoints

Blocked teams can now authenticate and access most endpoints; restricted
endpoints opt in with `x-disable-team-blocked: true`. A new middleware
reads the embedded spec at startup and returns 403 for blocked teams
hitting any marked route (sandbox/template mutations, volume create).
@cursor
Copy link
Copy Markdown

cursor Bot commented Apr 20, 2026

PR Summary

Medium Risk
Changes authorization behavior for blocked teams from global deny-at-auth to route-scoped deny, so any mismatch between OpenAPI paths and Gin FullPath() (or missing x-disable-team-blocked tags) could inadvertently allow blocked teams to hit sensitive endpoints. Middleware relies on OpenAPI extension typing/serialization and method casing, so spec-generation or routing differences could cause silent gaps in enforcement.

Overview
Blocked-team handling is moved from authentication-time rejection to per-endpoint enforcement: a new BlockedTeam Gin middleware builds a (method, route) allow/deny map from the OpenAPI extension x-disable-team-blocked and returns 403 (with BlockedReason when present) only for marked routes. The OpenAPI spec is updated to tag key sandbox/template/volume mutation endpoints with this extension, the server wires the middleware after auth/LaunchDarkly context, and the embedded generated swagger (api.gen.go) is regenerated to include the new annotations.

Reviewed by Cursor Bugbot for commit ecbd86e. Bugbot is set up for automated code reviews on this repo. Configure here.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ecbd86e. Configure here.

c.Next()

return
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Blocked team check bypassed via AccessTokenAuth authentication

Medium Severity

The BlockedTeam middleware silently passes through when auth.GetTeamInfo returns no team info (!ok). Endpoints that accept AccessTokenAuth (which calls SetUserID, not SetTeamInfo) will never have team info in the gin context, so blocked team members can bypass the restriction by authenticating with an access token. This affects non-deprecated endpoints like PATCH /v2/templates/{templateID}, which lists AccessTokenAuth as a valid security scheme alongside ApiKeyAuth.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ecbd86e. Configure here.

@jakubno jakubno assigned jakubno and unassigned ValentaTomas Apr 20, 2026
Comment thread spec/openapi.yml
delete:
description: Kill a sandbox
tags: [sandboxes]
x-disable-team-blocked: true
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Blocked teams cannot kill their own running sandboxes. Since TTL refresh and timeout extension are also blocked, any sandbox a team had at block-time will idle until its current TTL expires naturally. This means the platform continues serving compute for a blocked team until expiry, and an admin must intervene manually for faster cleanup. Consider whether DELETE /sandboxes/{sandboxID} should remain unblocked - it is a cleanup operation that reduces resource consumption, not a new-resource creation.

Copy link
Copy Markdown
Member

@jakubno jakubno left a comment

Choose a reason for hiding this comment

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

Don't add it like that, please pass the intent to validateTeamUsage

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.

3 participants