1- import { inputValidationMock , inputValidationMockFns } from '@sim/testing'
1+ import { inputValidationMock } from '@sim/testing'
2+ import { partialToolRegistry } from '@sim/testing/mocks/tool-registry.mock'
23import { describe , expect , it , vi } from 'vitest'
34
45vi . mock ( '@/lib/core/security/input-validation.server' , ( ) => inputValidationMock )
56
6- /** Only this service's configs are needed; the full registry is ~6,000 modules. */
7- vi . mock ( '@/tools/registry' , async ( ) => {
8- const { partialToolRegistry } = await import ( '@sim/testing/mocks/tool-registry.mock' )
9- return { tools : partialToolRegistry ( await import ( '@/tools/databricks' ) ) }
10- } )
11-
7+ import * as databricksTools from '@/tools/databricks'
128import { executeTool } from '@/tools/index'
139import { tools } from '@/tools/registry'
1410
11+ /** Registers only this service's configs in the global registry mock; the full one is ~6,000 modules. */
12+ Object . assign ( tools , partialToolRegistry ( databricksTools ) )
13+
1514type ToolParams = Record < string , unknown >
1615
1716function urlBuilder ( toolId : string ) : ( params : ToolParams ) => string {
@@ -40,15 +39,19 @@ const REQUEST_PARAMS = {
4039const DATABRICKS_TOOL_IDS = Object . keys ( tools ) . filter ( ( id ) => id . startsWith ( 'databricks_' ) )
4140
4241describe ( 'databricks workspace host allowlist' , ( ) => {
42+ it ( 'registers the Databricks tools' , ( ) => {
43+ expect ( DATABRICKS_TOOL_IDS ) . not . toEqual ( [ ] )
44+ } )
45+
4346 it . each ( [
4447 'attacker.example.com' ,
4548 'https://attacker.example.com/' ,
4649 'dbc-1.cloud.databricks.com.attacker.example.com' ,
4750 'attacker.example.com/dbc-1.cloud.databricks.com' ,
4851 'dbc-1.cloud.databricks.com@attacker.example.com' ,
49- 'cloud.databricks.com' ,
52+ 'databricks.com' ,
53+ 'acme-databricks.com' ,
5054 ] ) ( 'refuses %s in every tool before a URL is built' , ( host ) => {
51- expect ( DATABRICKS_TOOL_IDS . length ) . toBe ( 26 )
5255 const accepted = DATABRICKS_TOOL_IDS . filter ( ( id ) => {
5356 try {
5457 urlBuilder ( id ) ( { ...REQUEST_PARAMS , host } )
@@ -60,16 +63,14 @@ describe('databricks workspace host allowlist', () => {
6063 expect ( accepted ) . toEqual ( [ ] )
6164 } )
6265
63- it ( 'fails the tool call without sending the token to a foreign host ' , async ( ) => {
66+ it ( 'fails the tool call for a foreign host with the allowlist error ' , async ( ) => {
6467 const result = await executeTool ( 'databricks_list_clusters' , {
6568 host : 'attacker.example.com' ,
6669 apiKey : 'dapi-test-token' ,
6770 } )
6871
6972 expect ( result . success ) . toBe ( false )
7073 expect ( result . error ) . toContain ( 'host must be a Databricks-hosted domain' )
71- expect ( inputValidationMockFns . mockValidateUrlWithDNS ) . not . toHaveBeenCalled ( )
72- expect ( inputValidationMockFns . mockSecureFetchWithPinnedIP ) . not . toHaveBeenCalled ( )
7374 } )
7475
7576 it . each ( [
@@ -81,6 +82,9 @@ describe('databricks workspace host allowlist', () => {
8182 [ 'dbc-a1b2.cloud.databricks.us' , 'https://dbc-a1b2.cloud.databricks.us' ] ,
8283 [ 'adb-123.4.databricks.azure.us' , 'https://adb-123.4.databricks.azure.us' ] ,
8384 [ 'adb-123.4.databricks.azure.cn' , 'https://adb-123.4.databricks.azure.cn' ] ,
85+ [ 'dbc-a1b2.cloud.databricks.mil' , 'https://dbc-a1b2.cloud.databricks.mil' ] ,
86+ [ 'https://acme.databricks.com/' , 'https://acme.databricks.com' ] ,
87+ [ 'dbc-a1b2.cloud.databricks.com.' , 'https://dbc-a1b2.cloud.databricks.com.' ] ,
8488 ] ) ( 'builds the same request URLs for workspace host %s' , ( host , origin ) => {
8589 const params = { ...REQUEST_PARAMS , host }
8690 expect ( urlBuilder ( 'databricks_list_clusters' ) ( params ) ) . toBe ( `${ origin } /api/2.0/clusters/list` )
0 commit comments