diff --git a/package.json b/package.json index e896821e..c33cbbb6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@p0security/cli", - "version": "0.13.1", + "version": "0.13.2", "description": "Execute infra CLI commands with P0 grants", "main": "index.ts", "repository": { diff --git a/src/plugins/azure/auth.ts b/src/plugins/azure/auth.ts index 33041639..dc61f5dd 100644 --- a/src/plugins/azure/auth.ts +++ b/src/plugins/azure/auth.ts @@ -10,6 +10,31 @@ You should have received a copy of the GNU General Public License along with @p0 **/ import { print2 } from "../../drivers/stdio"; import { exec } from "../../util"; +import { KnownError } from "./types"; + +const knownLoginErrors: KnownError[] = [ + { + pattern: + /WARNING: A web browser has been opened at .+ Please continue the login in the web browser.+/, + message: "Login attempt was cancelled. Please try again.", + }, +]; + +const knownAccountSetErrors: KnownError[] = [ + { + pattern: /ERROR: The subscription of '.+' doesn't exist in cloud '.+'.+/, + message: "Failed to set the active Azure subscription. Please try again.", + }, +]; + +const normalizeAzureCliError = (error: any, normalizedErrors: KnownError[]) => { + for (const { pattern, message } of normalizedErrors) { + if (pattern.test(error.stderr)) { + throw message; + } + } + throw error; +}; export const azLoginCommand = () => ({ command: "az", @@ -26,16 +51,7 @@ export const azAccountSetCommand = (subscriptionId: string) => ({ args: ["account", "set", "--subscription", subscriptionId], }); -export const azLogin = async ( - subscriptionId: string, - options: { debug?: boolean } = {} -) => { - const { debug } = options; - - if (debug) print2("Logging in to Azure..."); - - // Logging out first ensures that any cached credentials are cleared. - // https://github.com/Azure/azure-cli/issues/29161 +const performLogout = async ({ debug }: { debug?: boolean }) => { try { const { command: azLogoutExe, args: azLogoutArgs } = azLogoutCommand(); const logoutResult = await exec(azLogoutExe, azLogoutArgs, { check: true }); @@ -50,24 +66,58 @@ export const azLogin = async ( print2(`Skipping logout: ${error.stderr}`); } } +}; - const { command: azLoginExe, args: azLoginArgs } = azLoginCommand(); - const loginResult = await exec(azLoginExe, azLoginArgs, { check: true }); +const performLogin = async ( + subscriptionId: string, + { debug }: { debug?: boolean } +) => { + try { + const { command: azLoginExe, args: azLoginArgs } = azLoginCommand(); + const loginResult = await exec(azLoginExe, azLoginArgs, { check: true }); - if (debug) { - print2(loginResult.stdout); - print2(loginResult.stderr); - print2(`Setting active Azure subscription to ${subscriptionId}...`); + if (debug) { + print2(loginResult.stdout); + print2(loginResult.stderr); + print2(`Setting active Azure subscription to ${subscriptionId}...`); + } + } catch (error: any) { + throw normalizeAzureCliError(error, knownLoginErrors); } +}; - const { command: azAccountSetExe, args: azAccountSetArgs } = - azAccountSetCommand(subscriptionId); - const accountSetResult = await exec(azAccountSetExe, azAccountSetArgs, { - check: true, - }); +const performSetAccount = async ( + subscriptionId: string, + { debug }: { debug?: boolean } +) => { + try { + const { command: azAccountSetExe, args: azAccountSetArgs } = + azAccountSetCommand(subscriptionId); + const accountSetResult = await exec(azAccountSetExe, azAccountSetArgs, { + check: true, + }); - if (debug) { - print2(accountSetResult.stdout); - print2(accountSetResult.stderr); + if (debug) { + print2(accountSetResult.stdout); + print2(accountSetResult.stderr); + } + } catch (error) { + throw normalizeAzureCliError(error, knownAccountSetErrors); } }; + +export const azLogin = async ( + subscriptionId: string, + options: { debug?: boolean } = {} +) => { + const { debug } = options; + if (debug) print2("Logging in to Azure..."); + + // Logging out first ensures that any cached credentials are cleared. + // https://github.com/Azure/azure-cli/issues/29161 + await performLogout(options); + + await performLogin(subscriptionId, options); + + await performSetAccount(subscriptionId, options); +}; diff --git a/src/plugins/azure/types.ts b/src/plugins/azure/types.ts index 91c51af4..a4d769bb 100644 --- a/src/plugins/azure/types.ts +++ b/src/plugins/azure/types.ts @@ -12,6 +12,11 @@ import { PermissionSpec } from "../../types/request"; import { CliPermissionSpec } from "../../types/ssh"; import { CommonSshPermissionSpec } from "../ssh/types"; +export type KnownError = { + pattern: RegExp; + message: string; +}; + export type AzureSshPermissionSpec = PermissionSpec<"ssh", AzureSshPermission>; export type AzureSsh = CliPermissionSpec<