mirror of
https://github.com/SigNoz/signoz.git
synced 2026-03-14 17:12:15 +00:00
Some checks failed
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
200 lines
4.9 KiB
JavaScript
Executable File
200 lines
4.9 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const { execSync } = require('child_process');
|
|
const axios = require('axios');
|
|
|
|
const PERMISSIONS_TYPE_FILE = path.join(
|
|
__dirname,
|
|
'../src/hooks/useAuthZ/permissions.type.ts',
|
|
);
|
|
|
|
const SIGNOZ_INTEGRATION_IMAGE = 'signoz:integration';
|
|
const LOCAL_BACKEND_URL = 'http://localhost:8080';
|
|
|
|
function log(message) {
|
|
console.log(`[generate-permissions-type] ${message}`);
|
|
}
|
|
|
|
function getBackendUrlFromDocker() {
|
|
try {
|
|
const output = execSync(
|
|
`docker ps --filter "ancestor=${SIGNOZ_INTEGRATION_IMAGE}" --format "{{.Ports}}"`,
|
|
{ encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] },
|
|
).trim();
|
|
|
|
if (!output) {
|
|
return null;
|
|
}
|
|
|
|
const portMatch = output.match(/0\.0\.0\.0:(\d+)->8080\/tcp/);
|
|
if (portMatch) {
|
|
return `http://localhost:${portMatch[1]}`;
|
|
}
|
|
|
|
const ipv6Match = output.match(/:::(\d+)->8080\/tcp/);
|
|
if (ipv6Match) {
|
|
return `http://localhost:${ipv6Match[1]}`;
|
|
}
|
|
} catch (err) {
|
|
log(`Warning: Could not get port from docker: ${err.message}`);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
async function checkBackendHealth(url, maxAttempts = 3, delayMs = 1000) {
|
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
try {
|
|
await axios.get(`${url}/api/v1/health`, {
|
|
timeout: 5000,
|
|
validateStatus: (status) => status === 200,
|
|
});
|
|
return true;
|
|
} catch (err) {
|
|
if (attempt < maxAttempts) {
|
|
await new Promise((r) => setTimeout(r, delayMs));
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
async function discoverBackendUrl() {
|
|
const dockerUrl = getBackendUrlFromDocker();
|
|
if (dockerUrl) {
|
|
log(`Found ${SIGNOZ_INTEGRATION_IMAGE} container, trying ${dockerUrl}...`);
|
|
if (await checkBackendHealth(dockerUrl)) {
|
|
log(`Backend found at ${dockerUrl} (from py-test-setup)`);
|
|
return dockerUrl;
|
|
}
|
|
log(`Backend at ${dockerUrl} is not responding`);
|
|
}
|
|
|
|
log(`Trying local backend at ${LOCAL_BACKEND_URL}...`);
|
|
if (await checkBackendHealth(LOCAL_BACKEND_URL)) {
|
|
log(`Backend found at ${LOCAL_BACKEND_URL}`);
|
|
return LOCAL_BACKEND_URL;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
async function fetchResources(backendUrl) {
|
|
log('Fetching resources from API...');
|
|
const resourcesUrl = `${backendUrl}/api/v1/authz/resources`;
|
|
|
|
const { data: response } = await axios.get(resourcesUrl);
|
|
|
|
return response;
|
|
}
|
|
|
|
function transformResponse(apiResponse) {
|
|
if (!apiResponse.data) {
|
|
throw new Error('Invalid API response: missing data field');
|
|
}
|
|
|
|
const { resources, relations } = apiResponse.data;
|
|
|
|
return {
|
|
status: apiResponse.status || 'success',
|
|
data: {
|
|
resources: resources,
|
|
relations: relations,
|
|
},
|
|
};
|
|
}
|
|
|
|
function generateTypeScriptFile(data) {
|
|
const resourcesStr = data.data.resources
|
|
.map(
|
|
(r) =>
|
|
`\t\t\t{\n\t\t\t\tname: '${r.name}',\n\t\t\t\ttype: '${r.type}',\n\t\t\t}`,
|
|
)
|
|
.join(',\n');
|
|
|
|
const relationsStr = Object.entries(data.data.relations)
|
|
.map(
|
|
([type, relations]) =>
|
|
`\t\t\t${type}: [${relations.map((r) => `'${r}'`).join(', ')}]`,
|
|
)
|
|
.join(',\n');
|
|
|
|
return `// AUTO GENERATED FILE - DO NOT EDIT - GENERATED BY scripts/generate-permissions-type
|
|
export default {
|
|
\tstatus: '${data.status}',
|
|
\tdata: {
|
|
\t\tresources: [
|
|
${resourcesStr}
|
|
\t\t],
|
|
\t\trelations: {
|
|
${relationsStr}
|
|
\t\t},
|
|
\t},
|
|
} as const;
|
|
`;
|
|
}
|
|
|
|
async function main() {
|
|
try {
|
|
log('Starting permissions type generation...');
|
|
|
|
const backendUrl = await discoverBackendUrl();
|
|
|
|
if (!backendUrl) {
|
|
console.error('\n' + '='.repeat(80));
|
|
console.error('ERROR: No running SigNoz backend found!');
|
|
console.error('='.repeat(80));
|
|
console.error(
|
|
'\nThe permissions type generator requires a running SigNoz backend.',
|
|
);
|
|
console.error('\nFor local development, start the backend with:');
|
|
console.error(' make go-run-enterprise');
|
|
console.error(
|
|
'\nFor CI or integration testing, start the test environment with:',
|
|
);
|
|
console.error(' make py-test-setup');
|
|
console.error(
|
|
'\nIf running in CI and seeing this error, check that the py-test-setup',
|
|
);
|
|
console.error('step completed successfully before this step runs.');
|
|
console.error('='.repeat(80) + '\n');
|
|
process.exit(1);
|
|
}
|
|
|
|
log('Fetching resources...');
|
|
const apiResponse = await fetchResources(backendUrl);
|
|
|
|
log('Transforming response...');
|
|
const transformed = transformResponse(apiResponse);
|
|
|
|
log('Generating TypeScript file...');
|
|
const content = generateTypeScriptFile(transformed);
|
|
|
|
log(`Writing to ${PERMISSIONS_TYPE_FILE}...`);
|
|
fs.writeFileSync(PERMISSIONS_TYPE_FILE, content, 'utf8');
|
|
|
|
const rootDir = path.join(__dirname, '../..');
|
|
const relativePath = path.relative(
|
|
path.join(rootDir, 'frontend'),
|
|
PERMISSIONS_TYPE_FILE,
|
|
);
|
|
log('Linting generated file...');
|
|
execSync(`cd frontend && yarn eslint --fix ${relativePath}`, {
|
|
cwd: rootDir,
|
|
stdio: 'inherit',
|
|
});
|
|
|
|
log('Successfully generated permissions.type.ts');
|
|
} catch (error) {
|
|
log(`Error: ${error.message}`);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
if (require.main === module) {
|
|
main();
|
|
}
|
|
|
|
module.exports = { main };
|