Skip to content

Commit e65345b

Browse files
authored
test(table): pin the executor auth pairing on the table read route (#6603)
* test(table): pin the executor auth pairing on the table read route fetchTableSchema reaches GET /api/table/[tableId] with a legacy type:'internal' token, which only works while that route authenticates through checkSessionOrInternalAuth. Its sibling table routes already moved to the delegation policy, which rejects that token outright, so migrating this one without moving the caller in the same change would break every table tool on an Agent block. Assert the route still authenticates through the legacy path so that migration fails here first, and record on the caller why it is deliberately not on buildExecutorDelegationHeaders yet. * test(table): assert the Bearer header reaches the legacy verifier Address review: the pairing test sent no Authorization header and its name claimed to verify token acceptance, which is pinned separately in lib/auth/internal.test.ts. Send a representative header, assert it reaches checkSessionOrInternalAuth unmodified, and scope the name and docs to what this guard actually covers — the route's choice of verifier.
1 parent 0d640aa commit e65345b

2 files changed

Lines changed: 58 additions & 1 deletion

File tree

apps/sim/app/api/table/[tableId]/route.test.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ vi.mock('@/app/api/table/utils', () => ({
5555
tableLockErrorResponse: () => null,
5656
}))
5757

58-
import { PATCH } from '@/app/api/table/[tableId]/route'
58+
import { GET, PATCH } from '@/app/api/table/[tableId]/route'
5959

6060
const TABLE = {
6161
id: 'tbl_1',
@@ -162,3 +162,47 @@ describe('PATCH /api/table/[tableId] folder moves', () => {
162162
expect(mockRenameTable).not.toHaveBeenCalled()
163163
})
164164
})
165+
166+
/**
167+
* Pins which auth path this route hands a Bearer token to.
168+
*
169+
* `fetchTableSchema` in `@/tools/schema-enrichers` reaches this route with a legacy
170+
* `type: 'internal'` token from the deprecated `buildAuthHeaders`. Only
171+
* `checkSessionOrInternalAuth` accepts that token; the delegation policy the sibling
172+
* table routes use rejects it outright. Migrating this route without moving that caller
173+
* to `buildExecutorDelegationHeaders` in the same change breaks every table tool on an
174+
* Agent block, so this fails first and names the caller.
175+
*
176+
* Scope: this pins the *route's* choice of verifier. That the legacy token is actually
177+
* valid for that verifier — and rejected by the delegation one — is pinned separately in
178+
* `@/lib/auth/internal.test.ts`. Both halves are needed; neither implies the other.
179+
*/
180+
describe('GET /api/table/[tableId] executor auth pairing', () => {
181+
beforeEach(() => {
182+
vi.clearAllMocks()
183+
hybridAuthMockFns.mockCheckSessionOrInternalAuth.mockResolvedValue({
184+
success: true,
185+
userId: 'user-1',
186+
authType: 'internal_jwt',
187+
})
188+
mockCheckAccess.mockResolvedValue({ ok: true, table: TABLE })
189+
mockGetLimits.mockResolvedValue({ maxRowsPerTable: 1000 })
190+
})
191+
192+
it('routes a Bearer token to the legacy verifier fetchTableSchema mints for', async () => {
193+
const request = new NextRequest('http://localhost:3000/api/table/tbl_1?workspaceId=workspace-1')
194+
request.headers.set('authorization', 'Bearer legacy-internal-token')
195+
196+
const response = await GET(request, routeContext)
197+
198+
expect(response.status).toBe(200)
199+
expect(hybridAuthMockFns.mockCheckSessionOrInternalAuth).toHaveBeenCalledWith(
200+
expect.objectContaining({
201+
headers: expect.objectContaining({ get: expect.any(Function) }),
202+
}),
203+
expect.anything()
204+
)
205+
const [forwarded] = hybridAuthMockFns.mockCheckSessionOrInternalAuth.mock.calls[0]
206+
expect(forwarded.headers.get('authorization')).toBe('Bearer legacy-internal-token')
207+
})
208+
})

apps/sim/tools/schema-enrichers.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,19 @@ import type { WorkflowToolExecutionContext } from '@/tools/types'
77

88
const logger = createLogger('SchemaEnrichers')
99

10+
/**
11+
* Reads a table's schema as the acting user.
12+
*
13+
* Deliberately still on the deprecated `buildAuthHeaders`, unlike its siblings in this
14+
* file: `GET /api/table/[tableId]` authenticates through `checkSessionOrInternalAuth`,
15+
* which accepts a legacy `type: 'internal'` token and rejects an executor delegation.
16+
* Swapping this to `buildExecutorDelegationHeaders` before that route migrates would
17+
* break every table tool on an Agent block. The route's own test pins the pairing.
18+
*
19+
* Unlike the workflow and knowledge enrichers, a failure here is loud — this runs as a
20+
* tool-level `toolEnrichment`, so `createLLMToolSchema` surfaces it as a
21+
* `ToolSchemaEnrichmentError` naming the tool rather than degrading the schema silently.
22+
*/
1023
async function fetchTableSchema(
1124
tableId: string,
1225
context: WorkflowToolExecutionContext

0 commit comments

Comments
 (0)