From 3caf02d5ac3d3d08e577675fd2cded9213da8625 Mon Sep 17 00:00:00 2001 From: YanaXu Date: Tue, 17 Oct 2023 18:01:43 +0800 Subject: [PATCH] create a type for PS Script output and add some test cases --- __tests__/PowerShell/AzPSLogin.test.ts | 29 +++++++++++++++++-- .../PowerShell/AzPSScriptBuilder.test.ts | 23 ++++++++++++++- action.yml | 2 +- src/PowerShell/AzPSConstants.ts | 5 ---- src/PowerShell/AzPSLogin.ts | 15 +++++++--- src/PowerShell/AzPSScriptBuilder.ts | 14 +++++---- 6 files changed, 68 insertions(+), 20 deletions(-) diff --git a/__tests__/PowerShell/AzPSLogin.test.ts b/__tests__/PowerShell/AzPSLogin.test.ts index 772f2966e..7fcd72935 100644 --- a/__tests__/PowerShell/AzPSLogin.test.ts +++ b/__tests__/PowerShell/AzPSLogin.test.ts @@ -54,11 +54,12 @@ describe('Testing runPSScript', () => { $ErrorActionPreference = "Stop" $WarningPreference = "SilentlyContinue" $output = @{} - $output['${AzPSConstants.Success}'] = "true" - $output['${AzPSConstants.Result}'] = $PSVersionTable.PSVersion.ToString() + $output['Success'] = $true + $output['Result'] = $PSVersionTable.PSVersion.ToString() } catch { - $output['${AzPSConstants.Error}'] = $_.exception.Message + $output['Success'] = $false + $output['Error'] = $_.exception.Message } return ConvertTo-Json $output`; @@ -66,4 +67,26 @@ describe('Testing runPSScript', () => { expect(psVersion === null).toBeFalsy(); }); + test('Get PowerShell Version with Wrong Name', async () => { + let script = `try { + $ErrorActionPreference = "Stop" + $WarningPreference = "SilentlyContinue" + $output = @{} + $output['Success'] = $true + $output['Result'] = $PSVersionTableWrongName.PSVersion.ToString() + } + catch { + $output['Success'] = $false + $output['Error'] = $_.exception.Message + } + return ConvertTo-Json $output`; + + try{ + await AzPSLogin.runPSScript(script); + throw new Error("The last step should fail."); + }catch(error){ + expect(error.message.includes("Azure PowerShell login failed with error: You cannot call a method on a null-valued expression.")).toBeTruthy(); + } + }); + }); \ No newline at end of file diff --git a/__tests__/PowerShell/AzPSScriptBuilder.test.ts b/__tests__/PowerShell/AzPSScriptBuilder.test.ts index 8f736e129..6a42060be 100644 --- a/__tests__/PowerShell/AzPSScriptBuilder.test.ts +++ b/__tests__/PowerShell/AzPSScriptBuilder.test.ts @@ -31,7 +31,7 @@ describe("Getting AzLogin PS script", () => { setEnv('auth-type', 'SERVICE_PRINCIPAL'); let creds = { 'clientId': 'client-id', - 'clientSecret': 'client-secret', + 'clientSecret': "client-secret", 'tenantId': 'tenant-id', 'subscriptionId': 'subscription-id' } @@ -45,6 +45,27 @@ describe("Getting AzLogin PS script", () => { }); }); + test('getAzPSLoginScript for SP+secret with allowNoSubscriptionsLogin=true, secret with single-quote', () => { + setEnv('environment', 'azurecloud'); + setEnv('enable-AzPSSession', 'true'); + setEnv('allow-no-subscriptions', 'true'); + setEnv('auth-type', 'SERVICE_PRINCIPAL'); + let creds = { + 'clientId': 'client-id', + 'clientSecret': "client-se'cret", + 'tenantId': 'tenant-id', + 'subscriptionId': 'subscription-id' + } + setEnv('creds', JSON.stringify(creds)); + + let loginConfig = new LoginConfig(); + loginConfig.initialize(); + return AzPSSCriptBuilder.getAzPSLoginScript(loginConfig).then(([loginMethod, loginScript]) => { + expect(loginScript.includes("Clear-AzContext -Scope Process; Clear-AzContext -Scope CurrentUser -Force -ErrorAction SilentlyContinue; $psLoginSecrets = ConvertTo-SecureString 'client-se''cret' -AsPlainText -Force; $psLoginCredential = New-Object System.Management.Automation.PSCredential('client-id', $psLoginSecrets); Connect-AzAccount -ServicePrincipal -Environment 'azurecloud' -Tenant 'tenant-id' -Subscription 'subscription-id' -Credential $psLoginCredential | out-null;")).toBeTruthy(); + expect(loginMethod).toBe('service principal with secret'); + }); + }); + test('getAzPSLoginScript for SP+secret with allowNoSubscriptionsLogin=false', () => { setEnv('environment', 'azurecloud'); setEnv('enable-AzPSSession', 'true'); diff --git a/action.yml b/action.yml index e3eea6e71..77aba20bf 100644 --- a/action.yml +++ b/action.yml @@ -1,6 +1,6 @@ # Login to Azure subscription name: 'Azure Login' -description: 'Authenticate to Azure using OIDC and run your Azure CLI or Azure PowerShell based actions or scripts. github.com/Azure/Actions' +description: 'Authenticate to Azure and run your Azure CLI or Azure PowerShell based actions or scripts.' inputs: creds: description: 'Paste output of `az ad sp create-for-rbac` as value of secret variable: AZURE_CREDENTIALS' diff --git a/src/PowerShell/AzPSConstants.ts b/src/PowerShell/AzPSConstants.ts index 43e521b49..d0b569e1b 100644 --- a/src/PowerShell/AzPSConstants.ts +++ b/src/PowerShell/AzPSConstants.ts @@ -2,11 +2,6 @@ export default class AzPSConstants { static readonly DEFAULT_AZ_PATH_ON_LINUX: string = '/usr/share'; static readonly DEFAULT_AZ_PATH_ON_WINDOWS: string = 'C:\\Modules'; static readonly AzAccounts: string = "Az.Accounts"; - static readonly PowerShell_CmdName = "pwsh"; - - static readonly Success: string = "Success"; - static readonly Error: string = "Error"; - static readonly Result: string = "Result"; } diff --git a/src/PowerShell/AzPSLogin.ts b/src/PowerShell/AzPSLogin.ts index ec9188bcf..c14f327e7 100644 --- a/src/PowerShell/AzPSLogin.ts +++ b/src/PowerShell/AzPSLogin.ts @@ -8,6 +8,12 @@ import AzPSScriptBuilder from './AzPSScriptBuilder'; import AzPSConstants from './AzPSConstants'; import { LoginConfig } from '../common/LoginConfig'; +interface PSResultType { + Result: string; + Success: boolean; + Error: string; +} + export class AzPSLogin { loginConfig: LoginConfig; @@ -83,11 +89,12 @@ export class AzPSLogin { if (commandStdErr) { throw new Error('Azure PowerShell login failed with errors.'); } - const result: any = JSON.parse(outputString.trim()); - if (!(AzPSConstants.Success in result)) { - throw new Error(`Azure PowerShell login failed with error: ${result[AzPSConstants.Error]}`); + const result: PSResultType = JSON.parse(outputString.trim()); + console.log(result); + if (!(result.Success)) { + throw new Error(`Azure PowerShell login failed with error: ${result.Error}`); } - return result[AzPSConstants.Result]; + return result.Result; } } diff --git a/src/PowerShell/AzPSScriptBuilder.ts b/src/PowerShell/AzPSScriptBuilder.ts index b392e4917..73ca860b6 100644 --- a/src/PowerShell/AzPSScriptBuilder.ts +++ b/src/PowerShell/AzPSScriptBuilder.ts @@ -10,11 +10,12 @@ export default class AzPSScriptBuilder { $output = @{} $latestModulePath = (Get-Module -Name '${moduleName}' -ListAvailable | Sort-Object Version -Descending | Select-Object -First 1).Path Import-Module -Name $latestModulePath - $output['${AzPSConstants.Result}'] = $latestModulePath - $output['${AzPSConstants.Success}'] = "true" + $output['Success'] = $true + $output['Result'] = $latestModulePath } catch { - $output['${AzPSConstants.Error}'] = $_.exception.Message + $output['Success'] = $false + $output['Error'] = $_.exception.Message } return ConvertTo-Json $output`; @@ -52,11 +53,12 @@ export default class AzPSScriptBuilder { $WarningPreference = "SilentlyContinue" $output = @{} ${commands} - $output['${AzPSConstants.Success}'] = "true" - $output['${AzPSConstants.Result}'] = "" + $output['Success'] = $true + $output['Result'] = "" } catch { - $output['${AzPSConstants.Error}'] = $_.exception.Message + $output['Success'] = $false + $output['Error'] = $_.exception.Message } return ConvertTo-Json $output`;