From e83d1ab9bd74f79620d73b70318346362d1faa65 Mon Sep 17 00:00:00 2001 From: Dan Yishai Date: Mon, 3 Nov 2025 16:19:49 +0200 Subject: [PATCH 1/4] Add createColumnResources option to Trino configuration and update related components - Introduced `createColumnResources` boolean option in Trino options, defaulting to false. - Updated `mapTrinoSchemaToPermitResources` to conditionally create column resources based on the new option. - Modified `TrinoComponent` to pass `createColumnResources` prop. - Enhanced `PDPRunComponent` to accept a `tag` prop for specifying the PDP image tag. - Adjusted Docker command in `PDPRunComponent` to use the provided tag. - Updated Trino resource naming for better clarity in the mapping function. - Reduced healthcheck interval in Docker Compose for faster feedback during tests. --- source/commands/env/apply/trino.tsx | 10 ++ source/commands/pdp/run.tsx | 12 +- .../components/env/trino/TrinoComponent.tsx | 4 +- source/components/env/trino/types.ts | 1 + source/components/pdp/PDPRunComponent.tsx | 4 +- source/utils/trinoUtils.ts | 105 ++++++++++-------- tests/trino/docker-compose.yml | 4 +- .../trino_config/access-control.properties | 5 + 8 files changed, 90 insertions(+), 55 deletions(-) create mode 100644 tests/trino/trino_config/access-control.properties diff --git a/source/commands/env/apply/trino.tsx b/source/commands/env/apply/trino.tsx index ea1d9db6..9194a728 100644 --- a/source/commands/env/apply/trino.tsx +++ b/source/commands/env/apply/trino.tsx @@ -56,6 +56,16 @@ export const options = zod.object({ alias: 's', }), ), + createColumnResources: zod + .boolean() + .optional() + .default(false) + .describe( + option({ + description: 'Create individual column resources (default: false)', + alias: 'cols', + }), + ), }); export default function Trino({ options }: { options: TrinoOptions }) { diff --git a/source/commands/pdp/run.tsx b/source/commands/pdp/run.tsx index edb8c1b5..6e01e5d6 100644 --- a/source/commands/pdp/run.tsx +++ b/source/commands/pdp/run.tsx @@ -28,16 +28,24 @@ export const options = object({ alias: 'k', }), ), + tag: string() + .default('latest') + .describe( + option({ + description: 'The tag of the PDP image to use', + alias: 't', + }), + ), }); type Props = { options: zInfer; }; -export default function Run({ options: { opa, dryRun, apiKey } }: Props) { +export default function Run({ options: { opa, dryRun, apiKey, tag } }: Props) { return ( - + ); } diff --git a/source/components/env/trino/TrinoComponent.tsx b/source/components/env/trino/TrinoComponent.tsx index 7b7b2e41..a74a5b49 100644 --- a/source/components/env/trino/TrinoComponent.tsx +++ b/source/components/env/trino/TrinoComponent.tsx @@ -21,7 +21,9 @@ export default function TrinoComponent( catalog: props.catalog, schema: props.schema, }); - const permitResources = mapTrinoSchemaToPermitResources(trinoSchema); + const permitResources = mapTrinoSchemaToPermitResources(trinoSchema, { + createColumnResources: props.createColumnResources, + }); setCreatedResources(permitResources); await processTrinoSchema(props); })(); diff --git a/source/components/env/trino/types.ts b/source/components/env/trino/types.ts index 413099dc..8c59d8dd 100644 --- a/source/components/env/trino/types.ts +++ b/source/components/env/trino/types.ts @@ -5,6 +5,7 @@ export type TrinoOptions = { password?: string; catalog?: string; schema?: string; + createColumnResources?: boolean; }; export interface PermitResource { diff --git a/source/components/pdp/PDPRunComponent.tsx b/source/components/pdp/PDPRunComponent.tsx index c9100d11..a968e315 100644 --- a/source/components/pdp/PDPRunComponent.tsx +++ b/source/components/pdp/PDPRunComponent.tsx @@ -16,6 +16,7 @@ type Props = { onComplete?: () => void; onError?: (error: string) => void; skipWaitScreen?: boolean; // New prop to control wait behavior + tag?: string; }; export default function PDPRunComponent({ @@ -24,6 +25,7 @@ export default function PDPRunComponent({ onComplete, onError, skipWaitScreen = true, // Default to showing wait screen + tag = 'latest', }: Props) { const { authToken } = useAuth(); const [loading, setLoading] = useState(true); @@ -82,7 +84,7 @@ export default function PDPRunComponent({ // Generate the Docker command const cmd = `docker run -d -p 7766:7000 ${ opa ? `-p ${opa}:8181` : '' - } -e PDP_API_KEY=${token} -e PDP_CONTROL_PLANE=${config.controlPlane || 'https://api.permit.io'} permitio/pdp-v2:latest`; + } -e PDP_API_KEY=${token} -e PDP_CONTROL_PLANE=${config.controlPlane || 'https://api.permit.io'} permitio/pdp-v2:${tag}`; setDockerCommand(cmd); diff --git a/source/utils/trinoUtils.ts b/source/utils/trinoUtils.ts index 6a951e4c..b90f7426 100644 --- a/source/utils/trinoUtils.ts +++ b/source/utils/trinoUtils.ts @@ -105,20 +105,24 @@ export function trinoTypeToPermitType( /** * Map Trino schema data to Permit resources. - * - Each catalog, schema, table, and column is a resource. + * - Each catalog, schema, table, and optionally column is a resource. * - Each table resource includes columns as attributes (with type/description). + * @param trino - The Trino schema data to map + * @param options - Configuration options + * @param options.createColumnResources - Whether to create individual column resources (default: false) */ export function mapTrinoSchemaToPermitResources( trino: TrinoSchemaData, + options: { createColumnResources?: boolean } = {}, ): PermitResource[] { const resources: PermitResource[] = []; - const SEP = '-'; + const SEP = '_'; // Catalogs for (const catalog of trino.catalogs) { resources.push({ key: `trino${SEP}catalog${SEP}${catalog.name}`, - name: catalog.name, + name: `Catalog: ${catalog.name}`, description: `Trino resource type: catalog. Trino catalog: ${catalog.name}`, actions: [ 'AccessCatalog', @@ -133,7 +137,7 @@ export function mapTrinoSchemaToPermitResources( for (const schema of trino.schemas) { resources.push({ key: `trino${SEP}schema${SEP}${schema.catalog}${SEP}${schema.name}`, - name: `${schema.catalog}.${schema.name}`, + name: `Schema: ${schema.catalog}.${schema.name}`, description: `Trino resource type: schema. Schema ${schema.name} in catalog ${schema.catalog}`, actions: [ 'CreateSchema', @@ -175,7 +179,7 @@ export function mapTrinoSchemaToPermitResources( const tableKey = `trino${SEP}table${SEP}${table.catalog}${SEP}${table.schema}${SEP}${table.name}`; resources.push({ key: tableKey, - name: `${table.catalog}.${table.schema}.${table.name}`, + name: `Table: ${table.catalog}.${table.schema}.${table.name}`, description: `Trino resource type: ${table.type.toLowerCase()}. ${table.type} ${table.name} in ${table.catalog}.${table.schema}`, actions: TABLE_AND_COLUMN_ACTIONS, attributes: table.columns.reduce( @@ -202,29 +206,32 @@ export function mapTrinoSchemaToPermitResources( }, ), }); - // Columns as resources - for (const column of table.columns) { - resources.push({ - key: `trino${SEP}column${SEP}${table.catalog}${SEP}${table.schema}${SEP}${table.name}${SEP}${column.name}`, - name: `${table.catalog}.${table.schema}.${table.name}.${column.name}`, - description: `Trino resource type: column. Column ${column.name} in ${table.catalog}.${table.schema}.${table.name}`, - actions: TABLE_AND_COLUMN_ACTIONS, - attributes: { - parent_table: { - type: 'string', - description: `${table.catalog}.${table.schema}.${table.name}`, - }, - table_type: { type: 'string', description: table.type.toLowerCase() }, - type: { - type: trinoTypeToPermitType(column.type), - description: column.type, - }, - nullable: { - type: 'bool', - description: column.nullable ? 'nullable' : undefined, + + // Create column resources if requested + if (options.createColumnResources) { + for (const column of table.columns) { + resources.push({ + key: `trino${SEP}column${SEP}${table.catalog}${SEP}${table.schema}${SEP}${table.name}${SEP}${column.name}`, + name: `Column: ${table.catalog}.${table.schema}.${table.name}.${column.name}`, + description: `Trino resource type: column. Column ${column.name} in ${table.catalog}.${table.schema}.${table.name}`, + actions: TABLE_AND_COLUMN_ACTIONS, + attributes: { + parent_table: { + type: 'string', + description: `${table.catalog}.${table.schema}.${table.name}`, + }, + table_type: { type: 'string', description: table.type.toLowerCase() }, + type: { + type: trinoTypeToPermitType(column.type), + description: column.type, + }, + nullable: { + type: 'bool', + description: column.nullable ? 'nullable' : undefined, + }, }, - }, - }); + }); + } } } @@ -232,7 +239,7 @@ export function mapTrinoSchemaToPermitResources( for (const view of trino.views) { resources.push({ key: `trino${SEP}view${SEP}${view.catalog}${SEP}${view.schema}${SEP}${view.name}`, - name: `${view.catalog}.${view.schema}.${view.name}`, + name: `View: ${view.catalog}.${view.schema}.${view.name}`, description: `Trino resource type: view. View ${view.name} in ${view.catalog}.${view.schema}`, actions: [ 'CreateView', @@ -272,7 +279,7 @@ export function mapTrinoSchemaToPermitResources( for (const mview of trino.materializedViews) { resources.push({ key: `trino${SEP}materialized_view${SEP}${mview.catalog}${SEP}${mview.schema}${SEP}${mview.name}`, - name: `${mview.catalog}.${mview.schema}.${mview.name}`, + name: `Materialized View: ${mview.catalog}.${mview.schema}.${mview.name}`, description: `Trino resource type: materialized view. Materialized view ${mview.name} in ${mview.catalog}.${mview.schema}`, actions: [ 'CreateMaterializedView', @@ -311,7 +318,7 @@ export function mapTrinoSchemaToPermitResources( for (const fn of trino.functions) { resources.push({ key: `trino${SEP}function${SEP}${fn.catalog}${SEP}${fn.schema}${SEP}${fn.name}`, - name: `${fn.catalog}.${fn.schema}.${fn.name}`, + name: `Function: ${fn.catalog}.${fn.schema}.${fn.name}`, description: `Trino resource type: function. Function ${fn.name} in ${fn.catalog}.${fn.schema}`, actions: [ 'ShowFunctions', @@ -333,7 +340,7 @@ export function mapTrinoSchemaToPermitResources( for (const proc of trino.procedures) { resources.push({ key: `trino${SEP}procedure${SEP}${proc.catalog}${SEP}${proc.schema}${SEP}${proc.name}`, - name: `${proc.catalog}.${proc.schema}.${proc.name}`, + name: `Procedure: ${proc.catalog}.${proc.schema}.${proc.name}`, description: `Trino resource type: procedure. Procedure ${proc.name} in ${proc.catalog}.${proc.schema}`, actions: ['ExecuteProcedure', 'ExecuteTableProcedure'], attributes: { @@ -426,20 +433,20 @@ export async function fetchTrinoFunctionsAndProceduresPassthrough( if (catalog.toLowerCase() === 'postgresql') { const passthrough = `SELECT * FROM TABLE(postgresql.system.query(query => ' - SELECT p.proname as function_name, n.nspname as schema_name, - pg_catalog.pg_get_function_result(p.oid) as return_type, - pg_catalog.pg_get_function_arguments(p.oid) as arguments, - CASE p.prokind - WHEN ''f'' THEN ''FUNCTION'' - WHEN ''p'' THEN ''PROCEDURE'' - WHEN ''a'' THEN ''AGGREGATE'' - WHEN ''w'' THEN ''WINDOW'' - ELSE p.prokind::text - END as kind - FROM pg_catalog.pg_proc p - LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace - WHERE n.nspname = ''${schema}'' - AND p.proname NOT LIKE ''pg_%'' + SELECT p.proname as function_name, n.nspname as schema_name, + pg_catalog.pg_get_function_result(p.oid) as return_type, + pg_catalog.pg_get_function_arguments(p.oid) as arguments, + CASE p.prokind + WHEN ''f'' THEN ''FUNCTION'' + WHEN ''p'' THEN ''PROCEDURE'' + WHEN ''a'' THEN ''AGGREGATE'' + WHEN ''w'' THEN ''WINDOW'' + ELSE p.prokind::text + END as kind + FROM pg_catalog.pg_proc p + LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace + WHERE n.nspname = ''${schema}'' + AND p.proname NOT LIKE ''pg_%'' ORDER BY p.proname '))`; try { @@ -472,8 +479,8 @@ export async function fetchTrinoFunctionsAndProceduresPassthrough( } } else if (catalog.toLowerCase() === 'mysql') { const passthrough = `SELECT * FROM TABLE(mysql.system.query(query => ' - SELECT routine_name, routine_type, data_type, routine_definition - FROM information_schema.routines + SELECT routine_name, routine_type, data_type, routine_definition + FROM information_schema.routines WHERE routine_schema = ''${schema}'' '))`; try { @@ -556,8 +563,8 @@ export async function fetchTrinoSchema( const tableComments = new Map(); try { const commentsQuery = ` - SELECT catalog_name, schema_name, table_name, comment - FROM system.metadata.table_comments + SELECT catalog_name, schema_name, table_name, comment + FROM system.metadata.table_comments WHERE comment IS NOT NULL `; const commentRows = await executeTrinoQuery(client, commentsQuery); diff --git a/tests/trino/docker-compose.yml b/tests/trino/docker-compose.yml index e7815389..7e670b7f 100644 --- a/tests/trino/docker-compose.yml +++ b/tests/trino/docker-compose.yml @@ -14,7 +14,7 @@ services: - ./sample_data/postgres_init.sql:/docker-entrypoint-initdb.d/init.sql healthcheck: test: ['CMD-SHELL', 'pg_isready -U testuser -d testdb'] - interval: 10s + interval: 5s timeout: 5s retries: 5 @@ -42,7 +42,7 @@ services: 'testuser', '-ptestpass', ] - interval: 10s + interval: 5s timeout: 5s retries: 5 diff --git a/tests/trino/trino_config/access-control.properties b/tests/trino/trino_config/access-control.properties new file mode 100644 index 00000000..96e1dac8 --- /dev/null +++ b/tests/trino/trino_config/access-control.properties @@ -0,0 +1,5 @@ +# access-control.name=allow-all +access-control.name=opa +opa.policy.uri=http://host.docker.internal:7766/trino/allowed +opa.log-requests=true +opa.log-responses=true From 83285d6cb1cbfabcd3fc7ee0c5b23d2f1fe1f3e8 Mon Sep 17 00:00:00 2001 From: Dan Yishai Date: Tue, 4 Nov 2025 12:11:36 +0200 Subject: [PATCH 2/4] Fix lint --- source/utils/trinoUtils.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/utils/trinoUtils.ts b/source/utils/trinoUtils.ts index b90f7426..ffeaa658 100644 --- a/source/utils/trinoUtils.ts +++ b/source/utils/trinoUtils.ts @@ -220,7 +220,10 @@ export function mapTrinoSchemaToPermitResources( type: 'string', description: `${table.catalog}.${table.schema}.${table.name}`, }, - table_type: { type: 'string', description: table.type.toLowerCase() }, + table_type: { + type: 'string', + description: table.type.toLowerCase(), + }, type: { type: trinoTypeToPermitType(column.type), description: column.type, From d3816582b4df993d019a75c81ae706b691ac97de Mon Sep 17 00:00:00 2001 From: Dan Yishai Date: Wed, 5 Nov 2025 18:42:53 +0200 Subject: [PATCH 3/4] Refactor Trino resource mapping tests for improved clarity and consistency - Updated resource keys in tests to use underscores instead of hyphens for consistency. - Enhanced test assertions to include resource type prefixes (e.g., 'Catalog:', 'Schema:', 'Table:') for better readability. - Added `createColumnResources` option in the `mapTrinoSchemaToPermitResources` function call to align with recent changes. --- tests/utils/trinoUtils.test.tsx | 152 ++++++++++++++++---------------- 1 file changed, 77 insertions(+), 75 deletions(-) diff --git a/tests/utils/trinoUtils.test.tsx b/tests/utils/trinoUtils.test.tsx index 635adba9..f8a6269d 100644 --- a/tests/utils/trinoUtils.test.tsx +++ b/tests/utils/trinoUtils.test.tsx @@ -35,45 +35,47 @@ describe('mapTrinoSchemaToPermitResources', () => { ], }, ], - functions: [], - views: [], - materializedViews: [], - procedures: [], - }; - const resources = mapTrinoSchemaToPermitResources(schema); + functions: [], + views: [], + materializedViews: [], + procedures: [], + }; + const resources = mapTrinoSchemaToPermitResources(schema, { + createColumnResources: true, + }); - // Check catalogs - const catalog = resources.find(r => r.key === 'trino-catalog-testcat'); - expect(catalog).toBeDefined(); - expect(catalog?.name).toBe('testcat'); - expect(catalog?.actions).toContain('AccessCatalog'); + // Check catalogs + const catalog = resources.find(r => r.key === 'trino_catalog_testcat'); + expect(catalog).toBeDefined(); + expect(catalog?.name).toBe('Catalog: testcat'); + expect(catalog?.actions).toContain('AccessCatalog'); - // Check schemas - const schemaResource = resources.find( - r => r.key === 'trino-schema-testcat-public', - ); - expect(schemaResource).toBeDefined(); - expect(schemaResource?.name).toBe('testcat.public'); - expect(schemaResource?.actions).toContain('CreateSchema'); + // Check schemas + const schemaResource = resources.find( + r => r.key === 'trino_schema_testcat_public', + ); + expect(schemaResource).toBeDefined(); + expect(schemaResource?.name).toBe('Schema: testcat.public'); + expect(schemaResource?.actions).toContain('CreateSchema'); - // Check tables - const table = resources.find( - r => r.key === 'trino-table-testcat-public-users', - ); - expect(table).toBeDefined(); - expect(table?.name).toBe('testcat.public.users'); - expect(table?.actions).toContain('CreateTable'); - expect(table?.attributes).toBeDefined(); - expect(table?.attributes?.id).toEqual({ type: 'number' }); - expect(table?.attributes?.email).toEqual({ type: 'string' }); + // Check tables + const table = resources.find( + r => r.key === 'trino_table_testcat_public_users', + ); + expect(table).toBeDefined(); + expect(table?.name).toBe('Table: testcat.public.users'); + expect(table?.actions).toContain('CreateTable'); + expect(table?.attributes).toBeDefined(); + expect(table?.attributes?.id).toEqual({ type: 'number' }); + expect(table?.attributes?.email).toEqual({ type: 'string' }); - // Check columns - const column = resources.find( - r => r.key === 'trino-column-testcat-public-users-id', - ); - expect(column).toBeDefined(); - expect(column?.name).toBe('testcat.public.users.id'); - expect(column?.actions).toContain('SelectFromColumns'); + // Check columns + const column = resources.find( + r => r.key === 'trino_column_testcat_public_users_id', + ); + expect(column).toBeDefined(); + expect(column?.name).toBe('Column: testcat.public.users.id'); + expect(column?.actions).toContain('SelectFromColumns'); }); it('maps Trino functions, views, materialized views, and procedures to Permit resources', () => { @@ -121,48 +123,48 @@ describe('mapTrinoSchemaToPermitResources', () => { const resources = mapTrinoSchemaToPermitResources(schema); - // Check function - const func = resources.find( - r => r.key === 'trino-function-testcat-public-my_func', - ); - expect(func).toBeDefined(); - expect(func?.name).toBe('testcat.public.my_func'); - expect(func?.actions).toContain('ExecuteFunction'); - expect(func?.actions).toContain('ShowFunctions'); - expect(func?.attributes?.returnType).toEqual({ type: 'number' }); - expect(func?.attributes?.argumentTypes).toEqual({ type: 'array' }); + // Check function + const func = resources.find( + r => r.key === 'trino_function_testcat_public_my_func', + ); + expect(func).toBeDefined(); + expect(func?.name).toBe('Function: testcat.public.my_func'); + expect(func?.actions).toContain('ExecuteFunction'); + expect(func?.actions).toContain('ShowFunctions'); + expect(func?.attributes?.returnType).toEqual({ type: 'number' }); + expect(func?.attributes?.argumentTypes).toEqual({ type: 'array' }); - // Check view - const view = resources.find( - r => r.key === 'trino-view-testcat-public-my_view', - ); - expect(view).toBeDefined(); - expect(view?.name).toBe('testcat.public.my_view'); - expect(view?.actions).toContain('CreateView'); - expect(view?.actions).toContain('DropView'); - expect(view?.attributes?.col1).toEqual({ type: 'string' }); - expect(view?.attributes?.col2).toEqual({ - type: 'number', - description: 'nullable', - }); + // Check view + const view = resources.find( + r => r.key === 'trino_view_testcat_public_my_view', + ); + expect(view).toBeDefined(); + expect(view?.name).toBe('View: testcat.public.my_view'); + expect(view?.actions).toContain('CreateView'); + expect(view?.actions).toContain('DropView'); + expect(view?.attributes?.col1).toEqual({ type: 'string' }); + expect(view?.attributes?.col2).toEqual({ + type: 'number', + description: 'nullable', + }); - // Check materialized view - const mview = resources.find( - r => r.key === 'trino-materialized_view-testcat-public-my_mview', - ); - expect(mview).toBeDefined(); - expect(mview?.name).toBe('testcat.public.my_mview'); - expect(mview?.actions).toContain('CreateMaterializedView'); - expect(mview?.actions).toContain('RefreshMaterializedView'); - expect(mview?.attributes?.total).toEqual({ type: 'number' }); + // Check materialized view + const mview = resources.find( + r => r.key === 'trino_materialized_view_testcat_public_my_mview', + ); + expect(mview).toBeDefined(); + expect(mview?.name).toBe('Materialized View: testcat.public.my_mview'); + expect(mview?.actions).toContain('CreateMaterializedView'); + expect(mview?.actions).toContain('RefreshMaterializedView'); + expect(mview?.attributes?.total).toEqual({ type: 'number' }); - // Check procedure - const proc = resources.find( - r => r.key === 'trino-procedure-testcat-public-my_proc', - ); - expect(proc).toBeDefined(); - expect(proc?.name).toBe('testcat.public.my_proc'); - expect(proc?.actions).toContain('ExecuteProcedure'); - expect(proc?.attributes?.argumentTypes).toEqual({ type: 'array' }); + // Check procedure + const proc = resources.find( + r => r.key === 'trino_procedure_testcat_public_my_proc', + ); + expect(proc).toBeDefined(); + expect(proc?.name).toBe('Procedure: testcat.public.my_proc'); + expect(proc?.actions).toContain('ExecuteProcedure'); + expect(proc?.attributes?.argumentTypes).toEqual({ type: 'array' }); }); }); From a6952637318e229c40cf65d96e6cad3f4058347a Mon Sep 17 00:00:00 2001 From: Dan Yishai Date: Thu, 6 Nov 2025 12:55:56 +0200 Subject: [PATCH 4/4] Fix lint --- tests/utils/trinoUtils.test.tsx | 154 ++++++++++++++++---------------- 1 file changed, 77 insertions(+), 77 deletions(-) diff --git a/tests/utils/trinoUtils.test.tsx b/tests/utils/trinoUtils.test.tsx index f8a6269d..fd87550d 100644 --- a/tests/utils/trinoUtils.test.tsx +++ b/tests/utils/trinoUtils.test.tsx @@ -35,47 +35,47 @@ describe('mapTrinoSchemaToPermitResources', () => { ], }, ], - functions: [], - views: [], - materializedViews: [], - procedures: [], - }; - const resources = mapTrinoSchemaToPermitResources(schema, { - createColumnResources: true, - }); + functions: [], + views: [], + materializedViews: [], + procedures: [], + }; + const resources = mapTrinoSchemaToPermitResources(schema, { + createColumnResources: true, + }); - // Check catalogs - const catalog = resources.find(r => r.key === 'trino_catalog_testcat'); - expect(catalog).toBeDefined(); - expect(catalog?.name).toBe('Catalog: testcat'); - expect(catalog?.actions).toContain('AccessCatalog'); + // Check catalogs + const catalog = resources.find(r => r.key === 'trino_catalog_testcat'); + expect(catalog).toBeDefined(); + expect(catalog?.name).toBe('Catalog: testcat'); + expect(catalog?.actions).toContain('AccessCatalog'); - // Check schemas - const schemaResource = resources.find( - r => r.key === 'trino_schema_testcat_public', - ); - expect(schemaResource).toBeDefined(); - expect(schemaResource?.name).toBe('Schema: testcat.public'); - expect(schemaResource?.actions).toContain('CreateSchema'); + // Check schemas + const schemaResource = resources.find( + r => r.key === 'trino_schema_testcat_public', + ); + expect(schemaResource).toBeDefined(); + expect(schemaResource?.name).toBe('Schema: testcat.public'); + expect(schemaResource?.actions).toContain('CreateSchema'); - // Check tables - const table = resources.find( - r => r.key === 'trino_table_testcat_public_users', - ); - expect(table).toBeDefined(); - expect(table?.name).toBe('Table: testcat.public.users'); - expect(table?.actions).toContain('CreateTable'); - expect(table?.attributes).toBeDefined(); - expect(table?.attributes?.id).toEqual({ type: 'number' }); - expect(table?.attributes?.email).toEqual({ type: 'string' }); + // Check tables + const table = resources.find( + r => r.key === 'trino_table_testcat_public_users', + ); + expect(table).toBeDefined(); + expect(table?.name).toBe('Table: testcat.public.users'); + expect(table?.actions).toContain('CreateTable'); + expect(table?.attributes).toBeDefined(); + expect(table?.attributes?.id).toEqual({ type: 'number' }); + expect(table?.attributes?.email).toEqual({ type: 'string' }); - // Check columns - const column = resources.find( - r => r.key === 'trino_column_testcat_public_users_id', - ); - expect(column).toBeDefined(); - expect(column?.name).toBe('Column: testcat.public.users.id'); - expect(column?.actions).toContain('SelectFromColumns'); + // Check columns + const column = resources.find( + r => r.key === 'trino_column_testcat_public_users_id', + ); + expect(column).toBeDefined(); + expect(column?.name).toBe('Column: testcat.public.users.id'); + expect(column?.actions).toContain('SelectFromColumns'); }); it('maps Trino functions, views, materialized views, and procedures to Permit resources', () => { @@ -123,48 +123,48 @@ describe('mapTrinoSchemaToPermitResources', () => { const resources = mapTrinoSchemaToPermitResources(schema); - // Check function - const func = resources.find( - r => r.key === 'trino_function_testcat_public_my_func', - ); - expect(func).toBeDefined(); - expect(func?.name).toBe('Function: testcat.public.my_func'); - expect(func?.actions).toContain('ExecuteFunction'); - expect(func?.actions).toContain('ShowFunctions'); - expect(func?.attributes?.returnType).toEqual({ type: 'number' }); - expect(func?.attributes?.argumentTypes).toEqual({ type: 'array' }); + // Check function + const func = resources.find( + r => r.key === 'trino_function_testcat_public_my_func', + ); + expect(func).toBeDefined(); + expect(func?.name).toBe('Function: testcat.public.my_func'); + expect(func?.actions).toContain('ExecuteFunction'); + expect(func?.actions).toContain('ShowFunctions'); + expect(func?.attributes?.returnType).toEqual({ type: 'number' }); + expect(func?.attributes?.argumentTypes).toEqual({ type: 'array' }); - // Check view - const view = resources.find( - r => r.key === 'trino_view_testcat_public_my_view', - ); - expect(view).toBeDefined(); - expect(view?.name).toBe('View: testcat.public.my_view'); - expect(view?.actions).toContain('CreateView'); - expect(view?.actions).toContain('DropView'); - expect(view?.attributes?.col1).toEqual({ type: 'string' }); - expect(view?.attributes?.col2).toEqual({ - type: 'number', - description: 'nullable', - }); + // Check view + const view = resources.find( + r => r.key === 'trino_view_testcat_public_my_view', + ); + expect(view).toBeDefined(); + expect(view?.name).toBe('View: testcat.public.my_view'); + expect(view?.actions).toContain('CreateView'); + expect(view?.actions).toContain('DropView'); + expect(view?.attributes?.col1).toEqual({ type: 'string' }); + expect(view?.attributes?.col2).toEqual({ + type: 'number', + description: 'nullable', + }); - // Check materialized view - const mview = resources.find( - r => r.key === 'trino_materialized_view_testcat_public_my_mview', - ); - expect(mview).toBeDefined(); - expect(mview?.name).toBe('Materialized View: testcat.public.my_mview'); - expect(mview?.actions).toContain('CreateMaterializedView'); - expect(mview?.actions).toContain('RefreshMaterializedView'); - expect(mview?.attributes?.total).toEqual({ type: 'number' }); + // Check materialized view + const mview = resources.find( + r => r.key === 'trino_materialized_view_testcat_public_my_mview', + ); + expect(mview).toBeDefined(); + expect(mview?.name).toBe('Materialized View: testcat.public.my_mview'); + expect(mview?.actions).toContain('CreateMaterializedView'); + expect(mview?.actions).toContain('RefreshMaterializedView'); + expect(mview?.attributes?.total).toEqual({ type: 'number' }); - // Check procedure - const proc = resources.find( - r => r.key === 'trino_procedure_testcat_public_my_proc', - ); - expect(proc).toBeDefined(); - expect(proc?.name).toBe('Procedure: testcat.public.my_proc'); - expect(proc?.actions).toContain('ExecuteProcedure'); - expect(proc?.attributes?.argumentTypes).toEqual({ type: 'array' }); + // Check procedure + const proc = resources.find( + r => r.key === 'trino_procedure_testcat_public_my_proc', + ); + expect(proc).toBeDefined(); + expect(proc?.name).toBe('Procedure: testcat.public.my_proc'); + expect(proc?.actions).toContain('ExecuteProcedure'); + expect(proc?.attributes?.argumentTypes).toEqual({ type: 'array' }); }); });