From b2f8997afe71554c9ae54adc19e9ec487629d070 Mon Sep 17 00:00:00 2001 From: Molecule AI Backend Engineer Date: Fri, 17 Apr 2026 02:50:43 +0000 Subject: [PATCH] =?UTF-8?q?fix(issue-541):=20move=20PATCH=20/budget=20to?= =?UTF-8?q?=20adminAuth=20=E2=80=94=20workspace=20must=20not=20self-clear?= =?UTF-8?q?=20ceiling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Workspace agents could previously call PATCH /workspaces/:id/budget with their own bearer token and set budget_limit=null, defeating the entire spend enforcement feature. GET stays on wsAuth (reading own budget is legitimate); PATCH moves to inline AdminAuth using the same pattern as /approvals/pending. No existing tests needed updating — all budget PATCH tests call the handler directly and are unaffected by router-level middleware changes. Co-Authored-By: Claude Sonnet 4.6 --- platform/internal/router/router.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platform/internal/router/router.go b/platform/internal/router/router.go index b6669059..8e735e45 100644 --- a/platform/internal/router/router.go +++ b/platform/internal/router/router.go @@ -257,10 +257,12 @@ func Setup(hub *ws.Hub, broadcaster *events.Broadcaster, prov *provisioner.Provi r.GET("/workspaces/:id/schedules/health", schedh.Health) // Budget — per-workspace spend ceiling and current usage (#541). - // GET returns the current state; PATCH sets or clears the ceiling. + // GET stays on wsAuth — a workspace agent reading its own budget is legitimate. + // PATCH is admin-only — workspace agents must not be able to self-clear their + // spending ceiling (that would defeat the entire budget enforcement feature). budgeth := handlers.NewBudgetHandler() wsAuth.GET("/budget", budgeth.GetBudget) - wsAuth.PATCH("/budget", budgeth.PatchBudget) + r.PATCH("/workspaces/:id/budget", middleware.AdminAuth(db.DB), budgeth.PatchBudget) // Token management (user-facing create/list/revoke) tokh := handlers.NewTokenHandler()