sin-github-issues / scripts /check-github-app-routing.mjs
OpenCode
Deploy latest SIN-GitHub-Issues runtime
cd455f6
Raw
History Blame Contribute Delete
3.93 kB
#!/usr/bin/env node
import { readFile } from 'node:fs/promises';
import path from 'node:path';
const cwd = process.cwd();
const args = process.argv.slice(2);
function parseArgs(argv) {
const out = {};
for (let i = 0; i < argv.length; i += 1) {
const token = argv[i];
if (!token.startsWith('--')) continue;
const key = token.slice(2);
const next = argv[i + 1];
if (!next || next.startsWith('--')) {
out[key] = 'true';
continue;
}
out[key] = next;
i += 1;
}
return out;
}
const parsedArgs = parseArgs(args);
const configPath = path.resolve(
cwd,
parsedArgs['config'] || process.env.SIN_GITHUB_APP_ROUTING_PATH || './config/github-app-routing.local.json',
);
function firstString(...values) {
for (const value of values) {
if (typeof value === 'string' && value.trim()) return value.trim();
}
return null;
}
function readEnv(name) {
if (!name) return null;
const value = process.env[name];
return typeof value === 'string' && value.trim() ? value.trim() : null;
}
function parseList(value) {
if (!value || typeof value !== 'string') return [];
return value
.split(',')
.map((item) => item.trim())
.filter(Boolean);
}
function toRoute(entry, defaultWebhookPath) {
const appId = firstString(String(entry.appId || '').trim(), readEnv(entry.appIdEnv));
const clientId = firstString(entry.clientId, readEnv(entry.clientIdEnv));
const routePath = firstString(entry.routePath, entry.webhookPath, defaultWebhookPath || '/github/webhook');
const agentSlug = firstString(entry.agentSlug, entry.preferredAgentSlug, entry.appSlug);
const privateKey = firstString(entry.privateKeyPem, readEnv(entry.privateKeyEnv));
const webhookSecret = firstString(entry.webhookSecret, readEnv(entry.webhookSecretEnv));
return {
agentSlug,
appSlug: firstString(entry.appSlug),
botName: firstString(entry.botName),
routePath,
appId,
clientId,
privateKeyRef: firstString(entry.privateKeyEnv, entry.privateKeyPath, entry.privateKeyPem ? 'inline' : null),
webhookSecretRef: firstString(entry.webhookSecretEnv, entry.webhookSecretPath, entry.webhookSecret ? 'inline' : null),
privateKeyResolved: Boolean(privateKey),
webhookSecretResolved: Boolean(webhookSecret),
};
}
async function main() {
const raw = await readFile(configPath, 'utf8');
const config = JSON.parse(raw);
const defaultWebhookPath = firstString(config.defaultWebhookPath, '/github/webhook');
const agentsFilter = new Set(parseList(parsedArgs.agents || parsedArgs.agent));
const configuredOnly = parsedArgs['configured-only'] === 'true';
const apps = (Array.isArray(config.apps) ? config.apps.map((entry) => toRoute(entry, defaultWebhookPath)) : []).filter((app) => {
const matchesAgent = agentsFilter.size === 0 || agentsFilter.has(app.agentSlug || '') || agentsFilter.has(app.appSlug || '');
const isConfigured = !configuredOnly || Boolean(app.appId || app.clientId || app.privateKeyResolved || app.webhookSecretResolved);
return matchesAgent && isConfigured;
});
const missing = apps.flatMap((app) => {
const failures = [];
if (!app.agentSlug) failures.push('agentSlug');
if (!app.appId) failures.push('appId');
if (!app.clientId) failures.push('clientId');
if (!app.privateKeyResolved) failures.push('privateKey');
if (!app.webhookSecretResolved) failures.push('webhookSecret');
return failures.length ? [{ agentSlug: app.agentSlug || app.appSlug || 'unknown', missing: failures }] : [];
});
console.log(JSON.stringify({
ok: missing.length === 0,
configPath,
defaultWebhookPath,
filters: {
agents: [...agentsFilter],
configuredOnly,
},
apps,
missing,
}, null, 2));
if (missing.length > 0) process.exitCode = 1;
}
main().catch((error) => {
console.error(error instanceof Error ? error.message : String(error));
process.exit(1);
});