diff --git a/packages/context/src/ingest/tools/warehouse-verification/discover-data.tool.test.ts b/packages/context/src/ingest/tools/warehouse-verification/discover-data.tool.test.ts index a9fb4bdf..b7e00b41 100644 --- a/packages/context/src/ingest/tools/warehouse-verification/discover-data.tool.test.ts +++ b/packages/context/src/ingest/tools/warehouse-verification/discover-data.tool.test.ts @@ -55,6 +55,16 @@ describe('DiscoverDataTool', () => { expect(result.structured.raw?.hits).toHaveLength(1); }); + it('refuses explicit out-of-scope connection names', async () => { + const result = await tool.call({ query: 'orders', connectionName: 'billing' }, context); + + expect(result.markdown).toContain('Connection "billing" is not available to this ingest stage.'); + expect(result.structured).toEqual({ wiki: null, sl: null, raw: null }); + expect(wikiSearchTool.call).not.toHaveBeenCalled(); + expect(slDiscoverTool.call).not.toHaveBeenCalled(); + expect(catalog.searchByName).not.toHaveBeenCalled(); + }); + it('delegates sourceName inspect mode to sl_discover only', async () => { slDiscoverTool.call.mockResolvedValueOnce({ markdown: 'source detail', diff --git a/packages/context/src/ingest/tools/warehouse-verification/discover-data.tool.ts b/packages/context/src/ingest/tools/warehouse-verification/discover-data.tool.ts index cb5a817b..4bd56509 100644 --- a/packages/context/src/ingest/tools/warehouse-verification/discover-data.tool.ts +++ b/packages/context/src/ingest/tools/warehouse-verification/discover-data.tool.ts @@ -41,6 +41,10 @@ function totalSources(structured: unknown): number { : 0; } +function allowedConnectionNames(context: ToolContext): ReadonlySet | null { + return context.session?.allowedConnectionNames ?? null; +} + export class DiscoverDataTool extends BaseTool { readonly name = 'discover_data'; @@ -57,6 +61,14 @@ export class DiscoverDataTool extends BaseTool { } async call(input: DiscoverDataInput, context: ToolContext): Promise> { + const allowed = allowedConnectionNames(context); + if (input.connectionName && allowed && !allowed.has(input.connectionName)) { + return { + markdown: `Connection "${input.connectionName}" is not available to this ingest stage.`, + structured: { wiki: null, sl: null, raw: null }, + }; + } + if (input.sourceName) { const sl = await this.deps.slDiscoverTool.call( { sourceName: input.sourceName, connectionId: input.connectionName }, @@ -95,9 +107,7 @@ export class DiscoverDataTool extends BaseTool { } const catalog = this.deps.catalogFactory(context); - const connections = input.connectionName - ? [input.connectionName] - : [...(context.session?.allowedConnectionNames ?? [])].sort(); + const connections = input.connectionName ? [input.connectionName] : [...(allowed ?? [])].sort(); const rawHits: RawSchemaHit[] = []; for (const connectionName of connections) { rawHits.push(...(await catalog.searchByName(connectionName, query, limit)));