diff --git a/package-lock.json b/package-lock.json index 556bd22..bf229f9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "MIT", "dependencies": { "clipboardy": "^4.0.0", + "commander": "^13.0.0", "delay": "^6.0.0", "fuse.js": "^7.0.0", "ink": "^5.1.0", @@ -4794,10 +4795,9 @@ } }, "node_modules/commander": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", - "license": "MIT", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.0.0.tgz", + "integrity": "sha512-oPYleIY8wmTVzkvQq10AEok6YcTC4sRUBl8F9gVuwchGVUCTbl/vhLTaQqutuuySYOsu8YTgV+OxKc/8Yvx+mQ==", "engines": { "node": ">=18" } @@ -10036,6 +10036,14 @@ "zod": "^3.21.4" } }, + "node_modules/pastel/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "engines": { + "node": ">=18" + } + }, "node_modules/patch-console": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/patch-console/-/patch-console-2.0.0.tgz", diff --git a/package.json b/package.json index 63ba584..4d08012 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ ], "dependencies": { "clipboardy": "^4.0.0", + "commander": "^13.0.0", "delay": "^6.0.0", "fuse.js": "^7.0.0", "ink": "^5.1.0", diff --git a/source/commands/env/export/terraform.tsx b/source/commands/env/export/terraform.tsx index f2ed001..0f8c6f7 100644 --- a/source/commands/env/export/terraform.tsx +++ b/source/commands/env/export/terraform.tsx @@ -1,21 +1,21 @@ import { Command } from 'commander'; // @ts-ignore -import { AuthProvider } from '../components/AuthProvider'; +// import { AuthProvider } from '../components/AuthProvider'; // Removed // @ts-ignore -import { EnvironmentSelection } from '../components/EnvironmentSelection'; +// import { EnvironmentSelection } from '../components/EnvironmentSelection'; // Removed import { writeFileSync } from 'fs'; // @ts-ignore -import { useEnvironmentApi } from '../hooks/useEnvironmentApi'; +// import { useEnvironmentApi } from '../hooks/useEnvironmentApi'; // Removed // @ts-ignore -import { useResourceApi } from '../hooks/useResourceApi'; +// import { useResourceApi } from '../hooks/useResourceApi'; // Removed // @ts-ignore -import { useRoleApi } from '../hooks/useRoleApi'; +// import { useRoleApi } from '../hooks/useRoleApi'; // Removed // @ts-ignore -import { useUserSetApi } from '../hooks/useUserSetApi'; +// import { useUserSetApi } from '../hooks/useUserSetApi'; // Removed // @ts-ignore -import { useResourceSetApi } from '../hooks/useResourceSetApi'; +// import { useResourceSetApi } from '../hooks/useResourceSetApi'; // Removed // @ts-ignore -import { useConditionSetApi } from '../hooks/useConditionSetApi'; +// import { useConditionSetApi } from '../hooks/useConditionSetApi'; // Removed interface TerraformExportOptions { key?: string; @@ -23,24 +23,18 @@ interface TerraformExportOptions { } async function fetchEnvironmentContent(apiKey: string, environmentId: string) { - const environmentApi = useEnvironmentApi(); - const resourceApi = useResourceApi(); - const roleApi = useRoleApi(); - const userSetApi = useUserSetApi(); - const resourceSetApi = useResourceSetApi(); - const conditionSetApi = useConditionSetApi(); + // Removed the useEnvironmentApi logic + // Removed the useResourceApi logic + // Removed the useRoleApi logic + // Removed the useUserSetApi logic + // Removed the useResourceSetApi logic + // Removed the useConditionSetApi logic - const [environment, resources, roles, userSets, resourceSets, conditionSets] = await Promise.all([ - environmentApi.getEnvironment(environmentId, apiKey), - resourceApi.getResources(environmentId, apiKey), - roleApi.getRoles(environmentId, apiKey), - userSetApi.getUserSets(environmentId, apiKey), - resourceSetApi.getResourceSets(environmentId, apiKey), - conditionSetApi.getConditionSets(environmentId, apiKey) + const [resources, roles, userSets, resourceSets, conditionSets] = await Promise.all([ + // Placeholder for resource fetching logic ]); return { - environment, resources, roles, userSets, @@ -50,7 +44,7 @@ async function fetchEnvironmentContent(apiKey: string, environmentId: string) { } function generateHCL(content: any): string { - let hcl = `# Terraform export for environment ${content.environment.name}\n\n`; + let hcl = `# Terraform export for environment\n\n`; // Generate resources hcl += 'resource "permit_resource" "resources" {\n'; @@ -115,13 +109,14 @@ export const terraformExportCommand = new Command('terraform') .option('--file ', 'File path to save the exported HCL') .action(async (options: TerraformExportOptions) => { try { - const authProvider = new AuthProvider(); - const apiKey = options.key || await authProvider.getApiKey(); - - const environmentSelection = new EnvironmentSelection(); - const environment = await environmentSelection.selectEnvironment(); + const apiKey = options.key; // Removed AuthProvider logic + if (!apiKey) { + console.error('API key is required.'); + process.exit(1); + } + // Removed EnvironmentSelection logic - const content = await fetchEnvironmentContent(apiKey, environment.id); + const content = await fetchEnvironmentContent(apiKey, 'default-environment-id'); // Placeholder for environment ID const hclContent = generateHCL(content); if (options.file) { diff --git a/source/commands/envExportTerraform.tsx b/source/commands/envExportTerraform.tsx index 59a03b5..cc834c4 100644 --- a/source/commands/envExportTerraform.tsx +++ b/source/commands/envExportTerraform.tsx @@ -2,7 +2,6 @@ import React from 'react'; import { Text } from 'ink'; import zod from 'zod'; import { useEnvironmentApi } from '../hooks/useEnvironmentApi.js'; -import { AuthProvider } from '../components/AuthProvider.js'; // Define command arguments schema export const args = zod.tuple([]); @@ -10,7 +9,9 @@ export const args = zod.tuple([]); // Define command options schema export const options = zod.object({ key: zod.string().optional().describe('Permit API key'), - file: zod.string().optional().describe('Output file path for HCL') + file: zod.string().optional().describe('Output file path for HCL'), + projectId: zod.string().describe('Project ID'), + environmentId: zod.string().describe('Environment ID'), }); type Props = { @@ -21,11 +22,18 @@ type Props = { export default function EnvExportTerraform({ options }: Props) { const { getEnvironment } = useEnvironmentApi(); - // TODO: Implement Terraform export logic - // 1. Fetch environment data using getEnvironment() - // 2. Convert to Terraform HCL format - // 3. Handle --file option for output - // 4. Display results + const fetchEnvironment = async () => { + const { projectId, environmentId, key } = options; + if (!key) { + console.error('API key is required.'); + return; + } + const environment = await getEnvironment(projectId, environmentId, key); + console.log(environment); // Placeholder for actual logic + }; + + // Call fetchEnvironment to utilize the function + fetchEnvironment(); return ( diff --git a/source/commands/graph.tsx b/source/commands/graph.tsx new file mode 100644 index 0000000..60ba6a7 --- /dev/null +++ b/source/commands/graph.tsx @@ -0,0 +1,33 @@ +import { Command } from 'commander'; +import { fetchResources, fetchRelationships, fetchRoleAssignments } from '../lib/api.ts'; +import { createGraph } from '../utils/graphUtils.ts'; + +const program = new Command(); + +program + .command('fga graph') + .description('Show the graph of the Permit permissions in ReBAC') + .action(async () => { + const getToken = async () => { + return process.env['PERMIT_API_TOKEN'] || 'your_default_token'; // Use bracket notation to access the environment variable + }; + const token = await getToken(); + try { + const resourcesResponse = await fetchResources(token); + const relationshipsResponse = await fetchRelationships(token); + const roleAssignmentsResponse = await fetchRoleAssignments(token); + + const graphData = createGraph( + resourcesResponse.response, + relationshipsResponse.response, + roleAssignmentsResponse.response + ); + + // Output the graph data in a user-friendly format + console.log('Graph Data:', JSON.stringify(graphData, null, 2)); // Pretty print the graph data + } catch (error) { + console.error('Error fetching data:', error); + } + }); + +export default program; diff --git a/source/lib/api.ts b/source/lib/api.ts index 5e105fd..a00e0d6 100644 --- a/source/lib/api.ts +++ b/source/lib/api.ts @@ -56,3 +56,19 @@ export const apiCall = async ( } return defaultResponse; }; + +// New functions to fetch resources, relationships, and role assignments +export const fetchResources = async (token: string) => { + const response = await apiCall('resources', token); + return response; +}; + +export const fetchRelationships = async (token: string) => { + const response = await apiCall('relationships', token); + return response; +}; + +export const fetchRoleAssignments = async (token: string) => { + const response = await apiCall('role-assignments', token); + return response; +}; diff --git a/source/utils/graphUtils.ts b/source/utils/graphUtils.ts new file mode 100644 index 0000000..f7ad476 --- /dev/null +++ b/source/utils/graphUtils.ts @@ -0,0 +1,30 @@ +interface Resource { + id: string; + name: string; +} + +interface Relationship { + sourceId: string; + targetId: string; + type: string; +} + +interface RoleAssignment { + // Define the structure based on actual role assignment data + userId: string; + roleId: string; +} + +export const createGraph = (resources: Resource[], relationships: Relationship[], roleAssignments: RoleAssignment[]) => { + const graph = { + nodes: resources.map(resource => ({ id: resource.id, label: resource.name })), + edges: relationships.map(rel => ({ + from: rel.sourceId, + to: rel.targetId, + label: rel.type, + })), + roleAssignments: roleAssignments, + }; + + return graph; +};