From 18fd6e262cd7c95b7847d4ab03858edaf86656bb Mon Sep 17 00:00:00 2001 From: Dotta Date: Fri, 5 Jun 2026 17:50:30 +0000 Subject: [PATCH] fix: propagate denied low-trust issue policy Co-Authored-By: Paperclip --- .../low-trust-red-team-routes.test.ts | 27 +++++++++++++++++++ server/src/routes/issues.ts | 3 +++ 2 files changed, 30 insertions(+) diff --git a/server/src/__tests__/low-trust-red-team-routes.test.ts b/server/src/__tests__/low-trust-red-team-routes.test.ts index 337b68a8993..911465db461 100644 --- a/server/src/__tests__/low-trust-red-team-routes.test.ts +++ b/server/src/__tests__/low-trust-red-team-routes.test.ts @@ -572,6 +572,33 @@ describeEmbeddedPostgres("low-trust red-team HTTP route regression suite", () => }); }); + it("propagates denied low-trust policy conflicts on control-plane guards", async () => { + const fixture = await seedLowTrustFixture(db); + const conflictingExecutionPolicy = { + authorizationPolicy: { + trustBoundary: { + mode: LOW_TRUST_REVIEW_PRESET, + companyId: fixture.company.id, + rootIssueId: fixture.issues.siblingOutOfScope.id, + }, + }, + }; + await db.update(heartbeatRuns) + .set({ + contextSnapshot: { + issueId: fixture.issues.assignedReview.id, + executionPolicy: conflictingExecutionPolicy, + }, + }) + .where(eq(heartbeatRuns.id, fixture.runs.lowTrust.id)); + + const res = await request(createApp(db, agentActor(fixture))) + .get(`/api/issues/${fixture.issues.assignedReview.id}/approvals`); + + expect(res.status, JSON.stringify(res.body)).toBe(403); + expect(res.body.error).toBe("Low-trust boundary root issue scopes do not overlap."); + }); + it("restricts low-trust self inspection without changing standard-agent visibility", async () => { const fixture = await seedLowTrustFixture(db); diff --git a/server/src/routes/issues.ts b/server/src/routes/issues.ts index 32a2d2c222f..729851ec5ac 100644 --- a/server/src/routes/issues.ts +++ b/server/src/routes/issues.ts @@ -1040,6 +1040,9 @@ export function issueRoutes( agentId: req.actor.agentId, runId: req.actor.runId, }, companyId, issue); + if (resolution?.kind === "denied") { + throw forbidden(resolution.detail); + } return resolution?.kind === "low_trust_review"; }