Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Stage 1: Build Stage
FROM node:lts-slim AS build

# Install libsecret for keytar
RUN apt-get update && apt-get install -y libsecret-1-0 && rm -rf /var/lib/apt/lists/*

# Set the working directory
WORKDIR /app

# Copy package.json and package-lock.json for caching npm install
COPY package.json package-lock.json* ./

# Install dependencies
RUN npm install

# Copy the rest of the source code
COPY . .

# Build the TypeScript code
RUN npm run build

# Stage 2: Runtime Stage
FROM node:lts-slim

# Install only necessary libraries for runtime
RUN apt-get update && apt-get install -y libsecret-1-0 && rm -rf /var/lib/apt/lists/*

# Create non-root user
RUN groupadd -r cli-group && useradd -r -g cli-group cli-user

# Set the working directory
WORKDIR /app

# Copy only the built files and necessary runtime files from the build stage
COPY --from=build /app/dist /app/dist
COPY --from=build /app/package.json /app/package.json
COPY --from=build /app/node_modules /app/node_modules

# Rebuild native dependencies for the current environment
RUN npm rebuild

# Switch to non-root user
USER cli-user

# Set the ENTRYPOINT to your CLI tool
ENTRYPOINT ["node", "/app/dist/cli.js"]

# Provide a default argument (like --help) which users can override
CMD ["--help"]
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions source/commands/env/apply/trino.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 }) {
Expand Down
12 changes: 10 additions & 2 deletions source/commands/pdp/run.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<typeof options>;
};

export default function Run({ options: { opa, dryRun, apiKey } }: Props) {
export default function Run({ options: { opa, dryRun, apiKey, tag } }: Props) {
return (
<AuthProvider permit_key={apiKey} scope={'environment'}>
<PDPRunComponent opa={opa} dryRun={dryRun} />
<PDPRunComponent opa={opa} dryRun={dryRun} tag={tag} />
</AuthProvider>
);
}
4 changes: 3 additions & 1 deletion source/components/env/trino/TrinoComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
})();
Expand Down
1 change: 1 addition & 0 deletions source/components/env/trino/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export type TrinoOptions = {
password?: string;
catalog?: string;
schema?: string;
createColumnResources?: boolean;
};

export interface PermitResource {
Expand Down
4 changes: 3 additions & 1 deletion source/components/pdp/PDPRunComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -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);
Expand Down Expand Up @@ -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);

Expand Down
107 changes: 57 additions & 50 deletions source/utils/trinoUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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',
Expand Down Expand Up @@ -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(
Expand All @@ -202,37 +206,40 @@ 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,
},
},
},
});
});
}
}
}

// Views
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',
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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',
Expand All @@ -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: {
Expand All @@ -344,7 +351,7 @@ export function mapTrinoSchemaToPermitResources(

// Add Trino System resource
resources.push({
key: 'trino_sys',
key: 'trino.sys',
name: 'Trino System',
description: 'Trino system-level resource for system-wide actions.',
actions: [
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -556,8 +563,8 @@ export async function fetchTrinoSchema(
const tableComments = new Map<string, string>();
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);
Expand Down
4 changes: 2 additions & 2 deletions tests/trino/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -42,7 +42,7 @@ services:
'testuser',
'-ptestpass',
]
interval: 10s
interval: 5s
timeout: 5s
retries: 5

Expand Down
5 changes: 5 additions & 0 deletions tests/trino/trino_config/access-control.properties
Original file line number Diff line number Diff line change
@@ -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
Loading