From b4cddcc50a9d6539d4062abe13ccde5263e93b2f Mon Sep 17 00:00:00 2001 From: Slawomir Koszewski Date: Sun, 8 Feb 2026 10:44:04 +0100 Subject: [PATCH] refactor(config): load JSON configs and emit JSON-only PCA output --- scripts/create-pca.js | 35 +++++++++++++---------------- src/graph/app.js | 10 ++++----- src/index.js | 52 ++++++++++++++++++++++++------------------- 3 files changed, 50 insertions(+), 47 deletions(-) diff --git a/scripts/create-pca.js b/scripts/create-pca.js index b20bb65..87f3b9f 100755 --- a/scripts/create-pca.js +++ b/scripts/create-pca.js @@ -35,7 +35,7 @@ function runAz(args, options = {}) { async function main() { const usageText = `Usage: ${path.basename(process.argv[1])} [options] Options: - -c, --config Write config template to file (optional) + -c, --config Write JSON config to file (optional) -h, --help Show this help message and exit`; let values; let positionals; @@ -51,7 +51,7 @@ Options: })); } catch (err) { console.error(`Error: ${err.message}`); - console.log(usageText); + console.error(usageText); process.exit(1); } @@ -64,7 +64,7 @@ Options: console.error( "Error: Too many positional arguments. Only one app name positional argument is allowed.", ); - console.log(usageText); + console.error(usageText); process.exit(1); } @@ -73,7 +73,7 @@ Options: if (!appName) { console.error("Error: Application name is required."); - console.log(usageText); + console.error(usageText); process.exit(1); } @@ -89,13 +89,12 @@ Options: "tsv", ]).stdout; - let userConfirmation = ""; if (appId) { const rl = readline.createInterface({ input: process.stdin, - output: process.stdout, + output: process.stderr, }); - userConfirmation = await new Promise((resolve) => { + const answer = await new Promise((resolve) => { rl.question( `Application '${appName}' already exists. Update it? [y/N]: `, (answer) => { @@ -105,8 +104,8 @@ Options: ); }); - if (!/^(yes|y)$/i.test(userConfirmation)) { - console.log("Canceled."); + if (!/^(yes|y)$/i.test(answer)) { + console.error("Canceled."); process.exit(0); } } @@ -231,16 +230,14 @@ Options: process.exit(1); } - if (userConfirmation) { - console.log(`Updated application '${appName}'`); - } else { - console.log(`Created application '${appName}'`); - } - const configTemplate = `export const config = { - "appName": "${appName}", - "tenantId": "${tenantId}", - "clientId": "${appId}" -};`; + const configTemplate = JSON.stringify( + { + tenantId, + clientId: appId, + }, + null, + 2, + ); if (configPath) { const targetPath = path.resolve(configPath); diff --git a/src/graph/app.js b/src/graph/app.js index a92c862..3494afd 100644 --- a/src/graph/app.js +++ b/src/graph/app.js @@ -2,22 +2,22 @@ * Get an Azure application by its display name. * * @param { Object } client - * @param { string } appName + * @param { string } displayName * @returns */ -export async function getApp(client, appName) { +export async function getApp(client, displayName) { const result = await client .api("/applications") - .filter(`displayName eq '${appName}'`) + .filter(`displayName eq '${displayName}'`) .get(); // Return the first application found or null if none exists return result.value.length > 0 ? result.value[0] : null; } -export async function createApp(client, appName) { +export async function createApp(client, displayName) { const app = await client.api("/applications").post({ - displayName: appName, + displayName, }); if (!app || !app.appId) { diff --git a/src/index.js b/src/index.js index 7514208..4ccda9a 100644 --- a/src/index.js +++ b/src/index.js @@ -10,31 +10,37 @@ export function getUserConfigDir() { return process.env.XDG_CONFIG_HOME ?? path.join(os.homedir(), ".config"); } -export async function loadConfig(type) { - const configBaseDir = getUserConfigDir(); - const configType = typeof type === "string" ? type.toLowerCase() : ""; - let configFileName; - - switch (configType) { - case "public": - case "p": - configFileName = "public-config.json"; - break; - case "confidential": - case "c": - configFileName = "confidential-config.json"; - break; - default: - configFileName = null; - } - - if (!configFileName) { +async function loadConfig(configFileName) { + if (typeof configFileName !== "string" || configFileName.trim() === "") { throw new Error( - `Invalid config type: ${type}. Expected "public"|"p" or "confidential"|"c".`, + 'Invalid config file name. Expected a non-empty string like "public-config.json" or "confidential-config.json".', ); } - const configPath = path.join(configBaseDir, "sk-az-tools", configFileName); - const configJson = await readFile(configPath, "utf8"); - return JSON.parse(configJson); + const config = { + tenantId: process.env.AZURE_TENANT_ID, + clientId: process.env.AZURE_CLIENT_ID, + }; + + const configPath = path.join(getUserConfigDir(), "sk-az-tools", configFileName); + return readFile(configPath, "utf8") + .then((configJson) => JSON.parse(configJson)) + .catch((err) => { + if (err?.code === "ENOENT") { + return {}; + } + throw err; + }) + .then((json) => ({ + tenantId: json.tenantId || config.tenantId, + clientId: json.clientId || config.clientId, + })); +} + +export function loadPublicConfig() { + return loadConfig("public-config.json"); +} + +export function loadConfidentialConfig() { + return loadConfig("confidential-config.json"); }