From 345d72610c4a5b7ab776624cb55bc11a004e73b5 Mon Sep 17 00:00:00 2001 From: jace-roell Date: Tue, 30 Jul 2024 14:52:40 -0400 Subject: [PATCH 01/24] ssh keyPassphrase prompt snapshot Signed-off-by: jace-roell --- .../src/session/ConnectionPropsForSessCfg.ts | 37 +++++++++--- .../session/doc/IOptionsForAddConnProps.ts | 14 +++-- .../session/doc/IOverridePromptConnProps.ts | 6 +- packages/zosuss/src/SshBaseHandler.ts | 56 +++++++++++++++++-- 4 files changed, 95 insertions(+), 18 deletions(-) diff --git a/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts b/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts index f7af5e7f4c..3316ad759b 100644 --- a/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts +++ b/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts @@ -20,6 +20,9 @@ import { ISession } from "./doc/ISession"; import { IProfileProperty } from "../../../profiles"; import { ConfigAutoStore } from "../../../config/src/ConfigAutoStore"; import { ConfigUtils } from "../../../config/src/ConfigUtils"; +import { utils } from "ssh2"; +import * as fs from "fs"; + /** * Extend options for IPromptOptions for internal wrapper method @@ -97,7 +100,7 @@ export class ConnectionPropsForSessCfg { public static async addPropsOrPrompt( initialSessCfg: SessCfgType, cmdArgs: ICommandArguments, - connOpts: IOptionsForAddConnProps = {} + connOpts: IOptionsForAddConnProps = {} ): Promise { const impLogger = Logger.getImperativeLogger(); @@ -127,13 +130,23 @@ export class ConnectionPropsForSessCfg { if (cmdArgs[argName] != null) { (sessCfgToUse as any)[override.propertyName] = cmdArgs[argName]; } for (const prop of override.propertiesOverridden) { // Make sure we do not prompt for the overridden property. - if (!doNotPromptForValues.includes(prop)) { doNotPromptForValues.push(prop); } + if (!doNotPromptForValues.includes(prop as any)) { doNotPromptForValues.push(prop as any); } if (prop in sessCfgToUse) { (sessCfgToUse as any)[prop] = undefined; } } } } } + if(connOpts.propsToPromptFor?.length > 0) + { + connOpts.propsToPromptFor.forEach(obj => { + if(obj.secure == null) obj.secure = true; + if(obj.secure) this.secureSessCfgProps.add(obj.name.toString()); + promptForValues.push(obj.name as keyof ISession); + this.promptTextForValues[obj.name.toString()] = obj.description; + }); + } + // check what properties are needed to be prompted if (ConnectionPropsForSessCfg.propHasValue(sessCfgToUse.hostname) === false && !doNotPromptForValues.includes("hostname")) { promptForValues.push("hostname"); @@ -161,13 +174,19 @@ export class ConnectionPropsForSessCfg { this.loadSecureSessCfgProps(connOptsToUse.parms, promptForValues); if (connOptsToUse.getValuesBack == null && connOptsToUse.doPrompting) { - connOptsToUse.getValuesBack = this.getValuesBack(connOptsToUse); + connOptsToUse.getValuesBack = this.getValuesBack(connOptsToUse as any); } if (connOptsToUse.getValuesBack != null) { // put all the needed properties in an array and call the external function const answers = await connOptsToUse.getValuesBack(promptForValues); + // Attempt to validate keypassPhrase/privateKey + let saveKP: boolean = true; + let result = utils.parseKey(fs.readFileSync((sessCfgToUse as any)["privateKey"]),(answers as any)["keyPassphrase"]); + try{saveKP = !result.message.includes("no passphrase given") && !result.message.includes("bad passphrase");} + catch(e){} + // validate what values are given back and move it to sessCfgToUse for (const value of promptForValues) { if (ConnectionPropsForSessCfg.propHasValue(answers[value])) { @@ -175,8 +194,12 @@ export class ConnectionPropsForSessCfg { } } + let propsToStore = promptForValues; + let valuesToRemove: string[] = ["keyPassphrase"]; + if(!saveKP) propsToStore = propsToStore.filter(item => !valuesToRemove.includes(item)); + if (connOptsToUse.autoStore !== false && connOptsToUse.parms != null) { - await ConfigAutoStore.storeSessCfgProps(connOptsToUse.parms, sessCfgToUse, promptForValues); + await ConfigAutoStore.storeSessCfgProps(connOptsToUse.parms, sessCfgToUse, propsToStore); } } @@ -216,7 +239,7 @@ export class ConnectionPropsForSessCfg { public static resolveSessCfgProps( sessCfg: SessCfgType, cmdArgs: ICommandArguments = { $0: "", _: [] }, - connOpts: IOptionsForAddConnProps = {} + connOpts: IOptionsForAddConnProps = {} ) { const impLogger = Logger.getImperativeLogger(); @@ -307,7 +330,7 @@ export class ConnectionPropsForSessCfg { impLogger.debug("Using basic authentication"); sessCfg.type = SessConstants.AUTH_TYPE_BASIC; } - ConnectionPropsForSessCfg.setTypeForTokenRequest(sessCfg, connOpts, cmdArgs.tokenType); + ConnectionPropsForSessCfg.setTypeForTokenRequest(sessCfg, connOpts as any, cmdArgs.tokenType); ConnectionPropsForSessCfg.logSessCfg(sessCfg); } @@ -392,7 +415,7 @@ export class ConnectionPropsForSessCfg { let answer; while (answer === undefined) { const hideText = profileSchema[value]?.secure || this.secureSessCfgProps.has(value); - let promptText = `${this.promptTextForValues[value]} ${serviceDescription}`; + let promptText = `${this.promptTextForValues[value] ?? `Enter your ${value} for`} ${serviceDescription}`; if (hideText) { promptText += " (will be hidden)"; } diff --git a/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts b/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts index 706e40a11a..53002f667e 100644 --- a/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts +++ b/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts @@ -9,7 +9,7 @@ * */ -import { SessConstants } from "../../.."; +import { ISession, SessConstants } from "../../.."; import { IHandlerParameters } from "../../../../cmd"; import { AUTH_TYPE_CHOICES } from "../SessConstants"; import { IOverridePromptConnProps } from "./IOverridePromptConnProps"; @@ -19,8 +19,7 @@ import { IOverridePromptConnProps } from "./IOverridePromptConnProps"; * @export * @interface ISession */ -export interface IOptionsForAddConnProps { - +export interface IOptionsForAddConnProps { /** * Indicates that we want to generate a token. * When true, we use the user and password for the operation @@ -51,7 +50,14 @@ export interface IOptionsForAddConnProps { * Specifies a list of authentication properties, and what they should override. * If one of these properties is available on the session, do not prompt for the other property. */ - propertyOverrides?: IOverridePromptConnProps[]; + propertyOverrides?: IOverridePromptConnProps[]; + + propsToPromptFor?: + { + name: keyof SessCfgType, + secure?: boolean, + description?: string + }[]; /** * Specifies the functionality that external applications will use for prompting. diff --git a/packages/imperative/src/rest/src/session/doc/IOverridePromptConnProps.ts b/packages/imperative/src/rest/src/session/doc/IOverridePromptConnProps.ts index db0a928409..d59b011011 100644 --- a/packages/imperative/src/rest/src/session/doc/IOverridePromptConnProps.ts +++ b/packages/imperative/src/rest/src/session/doc/IOverridePromptConnProps.ts @@ -16,7 +16,7 @@ import { ISession } from "./ISession"; * @export * @interface IOverridePromptConnProps */ -export interface IOverridePromptConnProps { +export interface IOverridePromptConnProps { /** * Indicates the session property that should be considered in the prompting logic. */ @@ -34,5 +34,7 @@ export interface IOverridePromptConnProps { * Prompting logic is only in place for host, port, user, and password, but cert, certKey, tokenType, and tokenValue may also need * to be overridden. */ - propertiesOverridden: (keyof ISession)[]; + propertiesOverridden: (keyof SessCfgType)[]; + + propsToPromptFor?: (keyof SessCfgType)[]; } \ No newline at end of file diff --git a/packages/zosuss/src/SshBaseHandler.ts b/packages/zosuss/src/SshBaseHandler.ts index cf76092a5f..a2bb2700cd 100644 --- a/packages/zosuss/src/SshBaseHandler.ts +++ b/packages/zosuss/src/SshBaseHandler.ts @@ -58,12 +58,12 @@ export abstract class SshBaseHandler implements ICommandHandler { public async process(commandParameters: IHandlerParameters) { this.mHandlerParams = commandParameters; - const sshSessCfgOverride: IOverridePromptConnProps[] = [{ + let sshSessCfgOverride: IOverridePromptConnProps[] = [{ propertyName: "privateKey", - propertiesOverridden: ["password", "tokenType", "tokenValue", "cert", "certKey", "passphrase"] + propertiesOverridden: ["password", "tokenType", "tokenValue", "cert", "certKey"] }]; - const sshSessCfg: ISshSession = SshSession.createSshSessCfgFromArgs(commandParameters.arguments); - const sshSessCfgWithCreds = await ConnectionPropsForSessCfg.addPropsOrPrompt( + let sshSessCfg: ISshSession = SshSession.createSshSessCfgFromArgs(commandParameters.arguments); + let sshSessCfgWithCreds = await ConnectionPropsForSessCfg.addPropsOrPrompt( sshSessCfg, commandParameters.arguments, { parms: commandParameters, propertyOverrides: sshSessCfgOverride, @@ -73,7 +73,53 @@ export abstract class SshBaseHandler implements ICommandHandler { this.mSession = new SshSession(sshSessCfgWithCreds); this.mArguments = commandParameters.arguments; - await this.processCmd(commandParameters); + let maxAttempts = 3; + let attempt = 0; + let success = false; + + try { + await this.processCmd(commandParameters); + } catch (e) { + console.log("Initial key passphrase authentication failed!"); + + if (e.message.includes("bad passphrase?")) { + throw e; + } + + if (e.message.includes("but no passphrase given")) { + let maxAttempts = 3; + let attempt = 0; + let success = false; + + while (attempt < maxAttempts && !success) { + try { + let sshSessCfg = SshSession.createSshSessCfgFromArgs(commandParameters.arguments); + let sshSessCfgWithCreds = await ConnectionPropsForSessCfg.addPropsOrPrompt( + sshSessCfg, commandParameters.arguments, { + parms: commandParameters, + propertyOverrides: sshSessCfgOverride, + supportedAuthTypes: [SessConstants.AUTH_TYPE_BASIC], + propsToPromptFor: [ + { + name: "keyPassphrase" + } + ], + } + ); + this.mSession = new SshSession(sshSessCfgWithCreds); + await this.processCmd(commandParameters); + success = true; + } catch (retryError) { + console.log(`Retry attempt ${attempt + 1} failed!`); + attempt++; + + if (attempt >= maxAttempts) { + throw new Error("Maximum retry attempts reached. Authentication failed."); + } + } + } + } + } } /** From ae93e644545518fe1594d098d84101fbb0be5dd7 Mon Sep 17 00:00:00 2001 From: jace-roell Date: Thu, 1 Aug 2024 08:53:28 -0400 Subject: [PATCH 02/24] added 3 attempts for keyPassphrase in the event there is no stored/stored value is incorrect Signed-off-by: jace-roell --- .../issue/ssh/Ssh.handler.unit.test.ts | 85 +++++++++- .../Ssh.handler.unit.test.ts.snap | 8 + packages/imperative/CHANGELOG.md | 5 + .../src/plugins/cmd/list/list.handler.ts | 3 +- .../src/session/ConnectionPropsForSessCfg.ts | 27 ++-- .../session/doc/IOptionsForAddConnProps.ts | 3 +- packages/zosuss/src/SshBaseHandler.ts | 147 +++++++++++------- 7 files changed, 206 insertions(+), 72 deletions(-) diff --git a/packages/cli/__tests__/zosuss/__unit__/issue/ssh/Ssh.handler.unit.test.ts b/packages/cli/__tests__/zosuss/__unit__/issue/ssh/Ssh.handler.unit.test.ts index 6fe5fc3b96..41e3686a0c 100644 --- a/packages/cli/__tests__/zosuss/__unit__/issue/ssh/Ssh.handler.unit.test.ts +++ b/packages/cli/__tests__/zosuss/__unit__/issue/ssh/Ssh.handler.unit.test.ts @@ -11,7 +11,7 @@ jest.mock("../../../../../../zosuss/lib/Shell"); -import { IHandlerParameters, IProfile, CommandProfiles } from "@zowe/imperative"; +import { IHandlerParameters, IProfile, CommandProfiles, ConnectionPropsForSessCfg } from "@zowe/imperative"; import * as SshHandler from "../../../../../src/zosuss/issue/ssh/Ssh.handler"; import * as SshDefinition from "../../../../../src/zosuss/issue/ssh/Ssh.definition"; import { Shell } from "@zowe/zos-uss-for-zowe-sdk"; @@ -33,6 +33,13 @@ const UNIT_TEST_SSH_PROF_OPTS_PRIVATE_KEY = { user: "someone", privateKey: normalize(join(__dirname, "..", "..", "..", "..", "..", "..", "zosuss", "__tests__", "__unit__", "__resources__", "fake_id_rsa")) }; +const UNIT_TEST_SSH_PROF_OPTS_PRIVATE_KEY_WITH_PASSPHRASE = { + host: "somewhere.com", + port: "22", + user: "someone", + privateKey: normalize(join(__dirname, "..", "..", "..", "..", "..", "..", "zosuss", "__tests__", "__unit__", "__resources__", "fake_id_rsa")), + keyPassPhrase: "dummyPassPhrase123" +}; // A mocked profile map with ssh profile const UNIT_TEST_PROFILE_MAP = new Map(); @@ -53,8 +60,17 @@ UNIT_TEST_PROFILE_MAP_PRIVATE_KEY.set( ...UNIT_TEST_SSH_PROF_OPTS_PRIVATE_KEY }] ); -const UNIT_TEST_PROFILES_SSH_PRIVATE_KEY = new CommandProfiles(UNIT_TEST_PROFILE_MAP_PRIVATE_KEY); +const UNIT_TEST_PROFILE_MAP_PRIVATE_KEY_WITH_PASSPHRASE = new Map(); +UNIT_TEST_PROFILE_MAP_PRIVATE_KEY_WITH_PASSPHRASE.set( + "ssh", [{ + name: "ssh", + type: "ssh", + ...UNIT_TEST_SSH_PROF_OPTS_PRIVATE_KEY_WITH_PASSPHRASE + }] +); +const UNIT_TEST_PROFILES_SSH_PRIVATE_KEY = new CommandProfiles(UNIT_TEST_PROFILE_MAP_PRIVATE_KEY); +const UNIT_TEST_PROFILES_SSH_PRIVATE_KEY_WITH_PASSPHRASE = new CommandProfiles(UNIT_TEST_PROFILE_MAP_PRIVATE_KEY_WITH_PASSPHRASE); // Mocked parameters for the unit tests const DEFAULT_PARAMETERS: IHandlerParameters = mockHandlerParameters({ arguments: UNIT_TEST_SSH_PROF_OPTS, @@ -70,6 +86,13 @@ const DEFAULT_PARAMETERS_PRIVATE_KEY: IHandlerParameters = mockHandlerParameters profiles: UNIT_TEST_PROFILES_SSH_PRIVATE_KEY }); +const DEFAULT_PARAMETERS_KEY_PASSPHRASE: IHandlerParameters = mockHandlerParameters({ + arguments: UNIT_TEST_SSH_PROF_OPTS_PRIVATE_KEY_WITH_PASSPHRASE, + positionals: ["zos-uss", "issue", "ssh"], + definition: SshDefinition.SshDefinition, + profiles: UNIT_TEST_PROFILES_SSH_PRIVATE_KEY_WITH_PASSPHRASE, +}); + const testOutput = "TEST OUTPUT"; describe("issue ssh handler tests", () => { @@ -90,6 +113,62 @@ describe("issue ssh handler tests", () => { expect(testOutput).toMatchSnapshot(); }); + it("should be able to get stdout with private key and key passphrase", async () => { + Shell.executeSsh = jest.fn(async (session, command, stdoutHandler) => { + stdoutHandler(testOutput); + }); + const handler = new SshHandler.default(); + const params = Object.assign({}, ...[DEFAULT_PARAMETERS_KEY_PASSPHRASE]); + params.arguments.command = "echo test"; + await handler.process(params); + expect(Shell.executeSsh).toHaveBeenCalledTimes(1); + expect(testOutput).toMatchSnapshot(); + }); + it("should prompt user for keyPassphrase if none is stored and privateKey requires one", async () => { + Shell.executeSsh = jest.fn(async (session, command, stdoutHandler) => { + stdoutHandler(testOutput); + }); + const handler = new SshHandler.default(); + const params = Object.assign({}, ...[DEFAULT_PARAMETERS_KEY_PASSPHRASE]); + params.arguments.command = "echo test"; + jest.spyOn(handler,"processCmd").mockImplementationOnce(() => {throw new Error("but no passphrase given");}); + jest.spyOn(ConnectionPropsForSessCfg as any,"getValuesBack").mockReturnValue(() => ({ + keyPassphrase: "validPassword" + })); + await handler.process(params); + expect(Shell.executeSsh).toHaveBeenCalledTimes(1); + expect(testOutput).toMatchSnapshot(); + }); + it("should reprompt user for keyPassphrase up to 3 times if stored passphrase failed", async () => { + Shell.executeSsh = jest.fn(async (session, command, stdoutHandler) => { + stdoutHandler(testOutput); + }); + const handler = new SshHandler.default(); + const params = Object.assign({}, ...[DEFAULT_PARAMETERS_KEY_PASSPHRASE]); + params.arguments.command = "echo test"; + jest.spyOn(handler,"processCmd").mockImplementationOnce(() => {throw new Error("bad passphrase?");}); + jest.spyOn(ConnectionPropsForSessCfg as any,"getValuesBack").mockReturnValue(() => ({ + keyPassphrase: "validPassword" + })); + await handler.process(params); + expect(Shell.executeSsh).toHaveBeenCalledTimes(1); + expect(testOutput).toMatchSnapshot(); + }); + it("should fail if user fails to enter incorrect key passphrase in 3 attempts", async () => { + const testOutput = "Maximum retry attempts reached. Authentication failed."; + Shell.executeSsh = jest.fn(async (session, command, stdoutHandler) => { + stdoutHandler(testOutput); + }); + const handler = new SshHandler.default(); + const params = { ...DEFAULT_PARAMETERS_KEY_PASSPHRASE }; + params.arguments.command = "echo test"; + jest.spyOn(handler, "processCmd").mockImplementation(() => { + throw new Error("bad passphrase?"); + }); + await expect(handler.process(params)).rejects.toThrow("Maximum retry attempts reached. Authentication failed."); + expect(handler.processCmd).toHaveBeenCalledTimes(4); + expect(testOutput).toMatchSnapshot(); + }); it("should be able to get stdout with privateKey", async () => { Shell.executeSsh = jest.fn(async (session, command, stdoutHandler) => { stdoutHandler(testOutput); @@ -101,7 +180,6 @@ describe("issue ssh handler tests", () => { expect(Shell.executeSsh).toHaveBeenCalledTimes(1); expect(testOutput).toMatchSnapshot(); }); - it("should be able to get stdout with cwd option", async () => { Shell.executeSshCwd = jest.fn(async (session, command, cwd, stdoutHandler) => { stdoutHandler(testOutput); @@ -114,5 +192,4 @@ describe("issue ssh handler tests", () => { expect(Shell.executeSshCwd).toHaveBeenCalledTimes(1); expect(testOutput).toMatchSnapshot(); }); - }); diff --git a/packages/cli/__tests__/zosuss/__unit__/issue/ssh/__snapshots__/Ssh.handler.unit.test.ts.snap b/packages/cli/__tests__/zosuss/__unit__/issue/ssh/__snapshots__/Ssh.handler.unit.test.ts.snap index 802e164178..88f8d3c1a4 100644 --- a/packages/cli/__tests__/zosuss/__unit__/issue/ssh/__snapshots__/Ssh.handler.unit.test.ts.snap +++ b/packages/cli/__tests__/zosuss/__unit__/issue/ssh/__snapshots__/Ssh.handler.unit.test.ts.snap @@ -6,4 +6,12 @@ exports[`issue ssh handler tests should be able to get stdout 2`] = `"TEST OUTPU exports[`issue ssh handler tests should be able to get stdout with cwd option 1`] = `"TEST OUTPUT"`; +exports[`issue ssh handler tests should be able to get stdout with private key and key passphrase 1`] = `"TEST OUTPUT"`; + exports[`issue ssh handler tests should be able to get stdout with privateKey 1`] = `"TEST OUTPUT"`; + +exports[`issue ssh handler tests should fail if user fails to enter incorrect key passphrase in 3 attempts 1`] = `"Maximum retry attempts reached. Authentication failed."`; + +exports[`issue ssh handler tests should prompt user for keyPassphrase if none is stored and privateKey requires one 1`] = `"TEST OUTPUT"`; + +exports[`issue ssh handler tests should reprompt user for keyPassphrase up to 3 times if stored passphrase failed 1`] = `"TEST OUTPUT"`; diff --git a/packages/imperative/CHANGELOG.md b/packages/imperative/CHANGELOG.md index 38f957a5a4..efceabeebe 100644 --- a/packages/imperative/CHANGELOG.md +++ b/packages/imperative/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes to the Imperative package will be documented in this file. +## Recent Changes + +- BugFix: Resolved bug that resulted in user not being prompted for a keyPassphrase if in the secure array of ssh profile. [#1770](https://github.com/zowe/zowe-cli/issues/1770) +- Enhancement: SshBaseHandler will now prompt user up to 3 times to enter the correct keyPassphrase in the case that the stored value is incorrect or no value is stored. [#1770](https://github.com/zowe/zowe-cli/issues/1770) + ## `8.0.0-next.202407181255` - BugFix: Resolved bug that resulted in each plug-in to have identical public registries regardless of actual installation location/reference. [#2189](https://github.com/zowe/zowe-cli/pull/2189) diff --git a/packages/imperative/src/imperative/src/plugins/cmd/list/list.handler.ts b/packages/imperative/src/imperative/src/plugins/cmd/list/list.handler.ts index 4d2bd581df..9fc6a09fe3 100644 --- a/packages/imperative/src/imperative/src/plugins/cmd/list/list.handler.ts +++ b/packages/imperative/src/imperative/src/plugins/cmd/list/list.handler.ts @@ -98,7 +98,8 @@ export default class ListHandler implements ICommandHandler { if(containsLegacyPlugin) { - listOutput = listOutput + `${chalk.yellow.bold("Plug-ins marked with (?) may be invalid or out of date, and might need to be reinstalled.")}` + "\n"; + listOutput = listOutput + `${chalk.yellow.bold("Plug-ins marked with (?) may be invalid or out of date, and might need to be reinstalled.")}`; + listOutput = listOutput + "\n"; } if (listOutput === "") { diff --git a/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts b/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts index 3316ad759b..fe0949ba81 100644 --- a/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts +++ b/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts @@ -20,9 +20,6 @@ import { ISession } from "./doc/ISession"; import { IProfileProperty } from "../../../profiles"; import { ConfigAutoStore } from "../../../config/src/ConfigAutoStore"; import { ConfigUtils } from "../../../config/src/ConfigUtils"; -import { utils } from "ssh2"; -import * as fs from "fs"; - /** * Extend options for IPromptOptions for internal wrapper method @@ -116,7 +113,7 @@ export class ConnectionPropsForSessCfg { ); // This function will provide all the needed properties in one array - const promptForValues: (keyof ISession)[] = []; + let promptForValues: (keyof ISession)[] = []; const doNotPromptForValues: (keyof ISession)[] = []; /* Add the override properties to the session object. @@ -137,6 +134,7 @@ export class ConnectionPropsForSessCfg { } } + // Set default values on propsToPromptFor if(connOpts.propsToPromptFor?.length > 0) { connOpts.propsToPromptFor.forEach(obj => { @@ -181,11 +179,15 @@ export class ConnectionPropsForSessCfg { // put all the needed properties in an array and call the external function const answers = await connOptsToUse.getValuesBack(promptForValues); - // Attempt to validate keypassPhrase/privateKey - let saveKP: boolean = true; - let result = utils.parseKey(fs.readFileSync((sessCfgToUse as any)["privateKey"]),(answers as any)["keyPassphrase"]); - try{saveKP = !result.message.includes("no passphrase given") && !result.message.includes("bad passphrase");} - catch(e){} + if(connOpts.propsToPromptFor?.length > 0) + { + connOpts.propsToPromptFor.forEach(obj => { + if(obj.isGivenValueValid != null) + { + if(!obj.isGivenValueValid(answers)) promptForValues = promptForValues.filter(item => obj.name !== item); + } + }); + } // validate what values are given back and move it to sessCfgToUse for (const value of promptForValues) { @@ -194,12 +196,9 @@ export class ConnectionPropsForSessCfg { } } - let propsToStore = promptForValues; - let valuesToRemove: string[] = ["keyPassphrase"]; - if(!saveKP) propsToStore = propsToStore.filter(item => !valuesToRemove.includes(item)); - + // if (connOptsToUse.autoStore !== false && connOptsToUse.parms != null) { - await ConfigAutoStore.storeSessCfgProps(connOptsToUse.parms, sessCfgToUse, propsToStore); + await ConfigAutoStore.storeSessCfgProps(connOptsToUse.parms, sessCfgToUse, promptForValues); } } diff --git a/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts b/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts index 53002f667e..e66dc92543 100644 --- a/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts +++ b/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts @@ -56,7 +56,8 @@ export interface IOptionsForAddConnProps { name: keyof SessCfgType, secure?: boolean, - description?: string + description?: string, + isGivenValueValid?: (givenValue: {[key: string]: any}) => boolean }[]; /** diff --git a/packages/zosuss/src/SshBaseHandler.ts b/packages/zosuss/src/SshBaseHandler.ts index a2bb2700cd..c9435419d4 100644 --- a/packages/zosuss/src/SshBaseHandler.ts +++ b/packages/zosuss/src/SshBaseHandler.ts @@ -1,13 +1,13 @@ /* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ import { // AbstractSession, @@ -22,16 +22,17 @@ import { IImperativeError, ImperativeError, ConnectionPropsForSessCfg, - SessConstants + SessConstants, } from "@zowe/imperative"; import { SshSession } from "./SshSession"; import { ISshSession } from "./doc/ISshSession"; +import { utils } from "ssh2"; +import * as fs from "fs"; /** * This class is used by the various handlers in the project as the base class for their implementation. */ export abstract class SshBaseHandler implements ICommandHandler { - /** * The session creating from the command line arguments / profile */ @@ -58,63 +59,103 @@ export abstract class SshBaseHandler implements ICommandHandler { public async process(commandParameters: IHandlerParameters) { this.mHandlerParams = commandParameters; - let sshSessCfgOverride: IOverridePromptConnProps[] = [{ - propertyName: "privateKey", - propertiesOverridden: ["password", "tokenType", "tokenValue", "cert", "certKey"] - }]; - let sshSessCfg: ISshSession = SshSession.createSshSessCfgFromArgs(commandParameters.arguments); - let sshSessCfgWithCreds = await ConnectionPropsForSessCfg.addPropsOrPrompt( - sshSessCfg, commandParameters.arguments, { - parms: commandParameters, - propertyOverrides: sshSessCfgOverride, - supportedAuthTypes: [SessConstants.AUTH_TYPE_BASIC] - } + const sshSessCfgOverride: IOverridePromptConnProps[] = [ + { + propertyName: "privateKey", + propertiesOverridden: [ + "password", + "tokenType", + "tokenValue", + "cert", + "certKey", + ], + }, + ]; + const sshSessCfg: ISshSession = SshSession.createSshSessCfgFromArgs( + commandParameters.arguments ); + let sshSessCfgWithCreds = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + sshSessCfg, + commandParameters.arguments, + { + parms: commandParameters, + propertyOverrides: sshSessCfgOverride, + supportedAuthTypes: [SessConstants.AUTH_TYPE_BASIC], + } + ); this.mSession = new SshSession(sshSessCfgWithCreds); this.mArguments = commandParameters.arguments; - let maxAttempts = 3; - let attempt = 0; - let success = false; - + try { await this.processCmd(commandParameters); } catch (e) { - console.log("Initial key passphrase authentication failed!"); - - if (e.message.includes("bad passphrase?")) { - throw e; - } - - if (e.message.includes("but no passphrase given")) { - let maxAttempts = 3; + commandParameters.response.console.log("Initial key passphrase authentication failed!" + "\n"); + if ( + e.message.includes("but no passphrase given") || + e.message.includes("bad passphrase?") + ) { + const maxAttempts = 3; let attempt = 0; let success = false; - while (attempt < maxAttempts && !success) { try { - let sshSessCfg = SshSession.createSshSessCfgFromArgs(commandParameters.arguments); - let sshSessCfgWithCreds = await ConnectionPropsForSessCfg.addPropsOrPrompt( - sshSessCfg, commandParameters.arguments, { - parms: commandParameters, - propertyOverrides: sshSessCfgOverride, - supportedAuthTypes: [SessConstants.AUTH_TYPE_BASIC], - propsToPromptFor: [ - { - name: "keyPassphrase" - } - ], - } - ); + sshSessCfgWithCreds = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + sshSessCfgWithCreds, + commandParameters.arguments, + { + parms: commandParameters, + propertyOverrides: sshSessCfgOverride, + supportedAuthTypes: [ + SessConstants.AUTH_TYPE_BASIC, + ], + propsToPromptFor: [ + { + name: "keyPassphrase", + isGivenValueValid: (givenValue: { + [key: string]: any; + }) => { + let saveKP: boolean = true; + const result = utils.parseKey( + fs.readFileSync( + sshSessCfgWithCreds[ + "privateKey" + ] + ), + givenValue.keyPassphrase + ); + if (result instanceof Error) + saveKP = + !result.message.includes( + "no passphrase given" + ) && + !result.message.includes( + "bad passphrase" + ); + return saveKP; + }, + }, + ], + } + ); this.mSession = new SshSession(sshSessCfgWithCreds); await this.processCmd(commandParameters); success = true; } catch (retryError) { - console.log(`Retry attempt ${attempt + 1} failed!`); + commandParameters.response.console.log( + "\n" + + `Key passphrase authentication failed! (${ + attempt + 1 + }/${maxAttempts})` + + "\n" + ); attempt++; - if (attempt >= maxAttempts) { - throw new Error("Maximum retry attempts reached. Authentication failed."); + throw new Error( + "Maximum retry attempts reached. Authentication failed." + ); } } } @@ -168,5 +209,7 @@ export abstract class SshBaseHandler implements ICommandHandler { * @param {IHandlerParameters} commandParameters Command parameters sent to the handler. * */ - public abstract processCmd(commandParameters: IHandlerParameters): Promise; + public abstract processCmd( + commandParameters: IHandlerParameters + ): Promise; } From ad9916cb127611cc3a81c7a7a35add94455c0647 Mon Sep 17 00:00:00 2001 From: jace-roell Date: Thu, 1 Aug 2024 09:19:33 -0400 Subject: [PATCH 03/24] fix changelog Signed-off-by: jace-roell --- packages/imperative/CHANGELOG.md | 5 ----- packages/zosuss/CHANGELOG.md | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/imperative/CHANGELOG.md b/packages/imperative/CHANGELOG.md index 548639899f..835f8bd7e4 100644 --- a/packages/imperative/CHANGELOG.md +++ b/packages/imperative/CHANGELOG.md @@ -2,11 +2,6 @@ All notable changes to the Imperative package will be documented in this file. -## Recent Changes - -- BugFix: Resolved bug that resulted in user not being prompted for a keyPassphrase if in the secure array of ssh profile. [#1770](https://github.com/zowe/zowe-cli/issues/1770) -- Enhancement: SshBaseHandler will now prompt user up to 3 times to enter the correct keyPassphrase in the case that the stored value is incorrect or no value is stored. [#1770](https://github.com/zowe/zowe-cli/issues/1770) - ## `8.0.0-next.202407262216` - Update: See `5.26.1` for details diff --git a/packages/zosuss/CHANGELOG.md b/packages/zosuss/CHANGELOG.md index 1bce6dca38..7b4b6452a5 100644 --- a/packages/zosuss/CHANGELOG.md +++ b/packages/zosuss/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes to the Zowe z/OS USS SDK package will be documented in this file. +## Recent Changes + +- BugFix: Resolved bug that resulted in user not being prompted for a keyPassphrase if in the secure array of ssh profile. [#1770](https://github.com/zowe/zowe-cli/issues/1770) +- Enhancement: SshBaseHandler will now prompt user up to 3 times to enter the correct keyPassphrase in the case that the stored value is incorrect or no value is stored. [#1770](https://github.com/zowe/zowe-cli/issues/1770) + ## `8.0.0-next.202403132009` - Enhancement: Provide more legible errors to user when they are missing user/password credentials while From d0d8a97ca04b7999827fe32a22ca6f5ebbfaea79 Mon Sep 17 00:00:00 2001 From: jace-roell Date: Thu, 1 Aug 2024 09:21:32 -0400 Subject: [PATCH 04/24] fix changelog 2 Signed-off-by: jace-roell --- packages/imperative/CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/imperative/CHANGELOG.md b/packages/imperative/CHANGELOG.md index 835f8bd7e4..548639899f 100644 --- a/packages/imperative/CHANGELOG.md +++ b/packages/imperative/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes to the Imperative package will be documented in this file. +## Recent Changes + +- BugFix: Resolved bug that resulted in user not being prompted for a keyPassphrase if in the secure array of ssh profile. [#1770](https://github.com/zowe/zowe-cli/issues/1770) +- Enhancement: SshBaseHandler will now prompt user up to 3 times to enter the correct keyPassphrase in the case that the stored value is incorrect or no value is stored. [#1770](https://github.com/zowe/zowe-cli/issues/1770) + ## `8.0.0-next.202407262216` - Update: See `5.26.1` for details From eec34cea599155759ed2102bc53ab4b2a64c6f54 Mon Sep 17 00:00:00 2001 From: jace-roell Date: Thu, 1 Aug 2024 11:40:08 -0400 Subject: [PATCH 05/24] added test Signed-off-by: jace-roell --- .../issue/ssh/Ssh.handler.unit.test.ts | 39 +++++++++++++++++++ .../Ssh.handler.unit.test.ts.snap | 4 ++ 2 files changed, 43 insertions(+) diff --git a/packages/cli/__tests__/zosuss/__unit__/issue/ssh/Ssh.handler.unit.test.ts b/packages/cli/__tests__/zosuss/__unit__/issue/ssh/Ssh.handler.unit.test.ts index 41e3686a0c..20f9b9bc37 100644 --- a/packages/cli/__tests__/zosuss/__unit__/issue/ssh/Ssh.handler.unit.test.ts +++ b/packages/cli/__tests__/zosuss/__unit__/issue/ssh/Ssh.handler.unit.test.ts @@ -40,6 +40,13 @@ const UNIT_TEST_SSH_PROF_OPTS_PRIVATE_KEY_WITH_PASSPHRASE = { privateKey: normalize(join(__dirname, "..", "..", "..", "..", "..", "..", "zosuss", "__tests__", "__unit__", "__resources__", "fake_id_rsa")), keyPassPhrase: "dummyPassPhrase123" }; +const UNIT_TEST_SSH_PROF_OPTS_PRIVATE_KEY_WITH_PASSPHRASE_NO_USER = { + host: "somewhere.com", + port: "22", + privateKey: normalize(join(__dirname, "..", "..", "..", "..", "..", "..", "zosuss", "__tests__", "__unit__", "__resources__", "fake_id_rsa")), + keyPassPhrase: "dummyPassPhrase123" +}; + // A mocked profile map with ssh profile const UNIT_TEST_PROFILE_MAP = new Map(); @@ -68,9 +75,19 @@ UNIT_TEST_PROFILE_MAP_PRIVATE_KEY_WITH_PASSPHRASE.set( ...UNIT_TEST_SSH_PROF_OPTS_PRIVATE_KEY_WITH_PASSPHRASE }] ); +const UNIT_TEST_PROFILE_MAP_PRIVATE_KEY_WITH_PASSPHRASE_NO_USER = new Map(); +UNIT_TEST_PROFILE_MAP_PRIVATE_KEY_WITH_PASSPHRASE.set( + "ssh", [{ + name: "ssh", + type: "ssh", + ...UNIT_TEST_SSH_PROF_OPTS_PRIVATE_KEY_WITH_PASSPHRASE_NO_USER + }] +); const UNIT_TEST_PROFILES_SSH_PRIVATE_KEY = new CommandProfiles(UNIT_TEST_PROFILE_MAP_PRIVATE_KEY); const UNIT_TEST_PROFILES_SSH_PRIVATE_KEY_WITH_PASSPHRASE = new CommandProfiles(UNIT_TEST_PROFILE_MAP_PRIVATE_KEY_WITH_PASSPHRASE); +const UNIT_TEST_PROFILES_SSH_PRIVATE_KEY_WITH_PASSPHRASE_NO_USER = new CommandProfiles(UNIT_TEST_PROFILE_MAP_PRIVATE_KEY_WITH_PASSPHRASE_NO_USER); + // Mocked parameters for the unit tests const DEFAULT_PARAMETERS: IHandlerParameters = mockHandlerParameters({ arguments: UNIT_TEST_SSH_PROF_OPTS, @@ -92,6 +109,12 @@ const DEFAULT_PARAMETERS_KEY_PASSPHRASE: IHandlerParameters = mockHandlerParamet definition: SshDefinition.SshDefinition, profiles: UNIT_TEST_PROFILES_SSH_PRIVATE_KEY_WITH_PASSPHRASE, }); +const DEFAULT_PARAMETERS_KEY_PASSPHRASE_NO_USER: IHandlerParameters = mockHandlerParameters({ + arguments: UNIT_TEST_SSH_PROF_OPTS_PRIVATE_KEY_WITH_PASSPHRASE_NO_USER, + positionals: ["zos-uss", "issue", "ssh"], + definition: SshDefinition.SshDefinition, + profiles: UNIT_TEST_PROFILES_SSH_PRIVATE_KEY_WITH_PASSPHRASE_NO_USER, +}); const testOutput = "TEST OUTPUT"; @@ -169,6 +192,22 @@ describe("issue ssh handler tests", () => { expect(handler.processCmd).toHaveBeenCalledTimes(4); expect(testOutput).toMatchSnapshot(); }); + it("should prompt for user and keyPassphrase if neither is stored", async () => { + const testOutput = "test"; + Shell.executeSsh = jest.fn(async (session, command, stdoutHandler) => { + stdoutHandler(testOutput); + }); + const handler = new SshHandler.default(); + const params = { ...DEFAULT_PARAMETERS_KEY_PASSPHRASE_NO_USER }; + params.arguments.command = "echo test"; + jest.spyOn(ConnectionPropsForSessCfg as any,"getValuesBack").mockReturnValue(() => ({ + user: "someone", + keyPassphrase: "validPassword" + })); + await handler.process(params); + expect(Shell.executeSsh).toHaveBeenCalledTimes(1); + expect(testOutput).toMatchSnapshot(); + }); it("should be able to get stdout with privateKey", async () => { Shell.executeSsh = jest.fn(async (session, command, stdoutHandler) => { stdoutHandler(testOutput); diff --git a/packages/cli/__tests__/zosuss/__unit__/issue/ssh/__snapshots__/Ssh.handler.unit.test.ts.snap b/packages/cli/__tests__/zosuss/__unit__/issue/ssh/__snapshots__/Ssh.handler.unit.test.ts.snap index 88f8d3c1a4..f0d2c34f0e 100644 --- a/packages/cli/__tests__/zosuss/__unit__/issue/ssh/__snapshots__/Ssh.handler.unit.test.ts.snap +++ b/packages/cli/__tests__/zosuss/__unit__/issue/ssh/__snapshots__/Ssh.handler.unit.test.ts.snap @@ -12,6 +12,10 @@ exports[`issue ssh handler tests should be able to get stdout with privateKey 1` exports[`issue ssh handler tests should fail if user fails to enter incorrect key passphrase in 3 attempts 1`] = `"Maximum retry attempts reached. Authentication failed."`; +exports[`issue ssh handler tests should prompt for user and keyPassphrase if neither is stored 1`] = `"test"`; + +exports[`issue ssh handler tests should prompt for user and keyPassphrase if neither is stored 2`] = `"test"`; + exports[`issue ssh handler tests should prompt user for keyPassphrase if none is stored and privateKey requires one 1`] = `"TEST OUTPUT"`; exports[`issue ssh handler tests should reprompt user for keyPassphrase up to 3 times if stored passphrase failed 1`] = `"TEST OUTPUT"`; From a83895d6085143945caadb4717c6bc25cc87a481 Mon Sep 17 00:00:00 2001 From: jace-roell Date: Fri, 2 Aug 2024 10:32:05 -0400 Subject: [PATCH 06/24] fixed unit tests and added documentation Signed-off-by: jace-roell --- .../issue/ssh/Ssh.handler.unit.test.ts | 18 +- .../session/doc/IOptionsForAddConnProps.ts | 4 + .../session/doc/IOverridePromptConnProps.ts | 4 + .../__unit__/SshBaseHandler.unit.test.ts | 231 ++++++++++++++++++ .../SshBaseHandler.unit.test.ts.snap | 17 ++ packages/zosuss/src/SshBaseHandler.ts | 4 +- 6 files changed, 267 insertions(+), 11 deletions(-) create mode 100644 packages/zosuss/__tests__/__unit__/SshBaseHandler.unit.test.ts create mode 100644 packages/zosuss/__tests__/__unit__/__snapshots__/SshBaseHandler.unit.test.ts.snap diff --git a/packages/cli/__tests__/zosuss/__unit__/issue/ssh/Ssh.handler.unit.test.ts b/packages/cli/__tests__/zosuss/__unit__/issue/ssh/Ssh.handler.unit.test.ts index 20f9b9bc37..58c1fedba0 100644 --- a/packages/cli/__tests__/zosuss/__unit__/issue/ssh/Ssh.handler.unit.test.ts +++ b/packages/cli/__tests__/zosuss/__unit__/issue/ssh/Ssh.handler.unit.test.ts @@ -12,7 +12,7 @@ jest.mock("../../../../../../zosuss/lib/Shell"); import { IHandlerParameters, IProfile, CommandProfiles, ConnectionPropsForSessCfg } from "@zowe/imperative"; -import * as SshHandler from "../../../../../src/zosuss/issue/ssh/Ssh.handler"; +import SshHandler from "../../../../../src/zosuss/issue/ssh/Ssh.handler"; import * as SshDefinition from "../../../../../src/zosuss/issue/ssh/Ssh.definition"; import { Shell } from "@zowe/zos-uss-for-zowe-sdk"; import { mockHandlerParameters } from "@zowe/cli-test-utils"; @@ -128,7 +128,7 @@ describe("issue ssh handler tests", () => { Shell.executeSsh = jest.fn(async (session, command, stdoutHandler) => { stdoutHandler(testOutput); }); - const handler = new SshHandler.default(); + const handler = new SshHandler(); const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); params.arguments.command = "pwd"; await handler.process(params); @@ -140,7 +140,7 @@ describe("issue ssh handler tests", () => { Shell.executeSsh = jest.fn(async (session, command, stdoutHandler) => { stdoutHandler(testOutput); }); - const handler = new SshHandler.default(); + const handler = new SshHandler(); const params = Object.assign({}, ...[DEFAULT_PARAMETERS_KEY_PASSPHRASE]); params.arguments.command = "echo test"; await handler.process(params); @@ -151,7 +151,7 @@ describe("issue ssh handler tests", () => { Shell.executeSsh = jest.fn(async (session, command, stdoutHandler) => { stdoutHandler(testOutput); }); - const handler = new SshHandler.default(); + const handler = new SshHandler(); const params = Object.assign({}, ...[DEFAULT_PARAMETERS_KEY_PASSPHRASE]); params.arguments.command = "echo test"; jest.spyOn(handler,"processCmd").mockImplementationOnce(() => {throw new Error("but no passphrase given");}); @@ -166,7 +166,7 @@ describe("issue ssh handler tests", () => { Shell.executeSsh = jest.fn(async (session, command, stdoutHandler) => { stdoutHandler(testOutput); }); - const handler = new SshHandler.default(); + const handler = new SshHandler(); const params = Object.assign({}, ...[DEFAULT_PARAMETERS_KEY_PASSPHRASE]); params.arguments.command = "echo test"; jest.spyOn(handler,"processCmd").mockImplementationOnce(() => {throw new Error("bad passphrase?");}); @@ -182,7 +182,7 @@ describe("issue ssh handler tests", () => { Shell.executeSsh = jest.fn(async (session, command, stdoutHandler) => { stdoutHandler(testOutput); }); - const handler = new SshHandler.default(); + const handler = new SshHandler(); const params = { ...DEFAULT_PARAMETERS_KEY_PASSPHRASE }; params.arguments.command = "echo test"; jest.spyOn(handler, "processCmd").mockImplementation(() => { @@ -197,7 +197,7 @@ describe("issue ssh handler tests", () => { Shell.executeSsh = jest.fn(async (session, command, stdoutHandler) => { stdoutHandler(testOutput); }); - const handler = new SshHandler.default(); + const handler = new SshHandler(); const params = { ...DEFAULT_PARAMETERS_KEY_PASSPHRASE_NO_USER }; params.arguments.command = "echo test"; jest.spyOn(ConnectionPropsForSessCfg as any,"getValuesBack").mockReturnValue(() => ({ @@ -212,7 +212,7 @@ describe("issue ssh handler tests", () => { Shell.executeSsh = jest.fn(async (session, command, stdoutHandler) => { stdoutHandler(testOutput); }); - const handler = new SshHandler.default(); + const handler = new SshHandler(); const params = Object.assign({}, ...[DEFAULT_PARAMETERS_PRIVATE_KEY]); params.arguments.command = "pwd"; await handler.process(params); @@ -223,7 +223,7 @@ describe("issue ssh handler tests", () => { Shell.executeSshCwd = jest.fn(async (session, command, cwd, stdoutHandler) => { stdoutHandler(testOutput); }); - const handler = new SshHandler.default(); + const handler = new SshHandler(); const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); params.arguments.command = "pwd"; params.arguments.cwd = "/user/home"; diff --git a/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts b/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts index e66dc92543..de99e558ee 100644 --- a/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts +++ b/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts @@ -52,6 +52,10 @@ export interface IOptionsForAddConnProps */ propertyOverrides?: IOverridePromptConnProps[]; + /** + * Allows for passing for additional properties to prompt for. + * Utilized in the case of a incorrect/not stored key passphrase. s + */ propsToPromptFor?: { name: keyof SessCfgType, diff --git a/packages/imperative/src/rest/src/session/doc/IOverridePromptConnProps.ts b/packages/imperative/src/rest/src/session/doc/IOverridePromptConnProps.ts index d59b011011..819017b927 100644 --- a/packages/imperative/src/rest/src/session/doc/IOverridePromptConnProps.ts +++ b/packages/imperative/src/rest/src/session/doc/IOverridePromptConnProps.ts @@ -36,5 +36,9 @@ export interface IOverridePromptConnProps */ propertiesOverridden: (keyof SessCfgType)[]; + /** + * Allows for passing for additional properties to prompt for. + * Utilized in the case of a incorrect/not stored key passphrase. + */ propsToPromptFor?: (keyof SessCfgType)[]; } \ No newline at end of file diff --git a/packages/zosuss/__tests__/__unit__/SshBaseHandler.unit.test.ts b/packages/zosuss/__tests__/__unit__/SshBaseHandler.unit.test.ts new file mode 100644 index 0000000000..5e9365250a --- /dev/null +++ b/packages/zosuss/__tests__/__unit__/SshBaseHandler.unit.test.ts @@ -0,0 +1,231 @@ +/* +* This program and the accompanying materials are made available under the terms of the +* Eclipse Public License v2.0 which accompanies this distribution, and is available at +* https://www.eclipse.org/legal/epl-v20.html +* +* SPDX-License-Identifier: EPL-2.0 +* +* Copyright Contributors to the Zowe Project. +* +*/ + +import { IHandlerParameters, IProfile, CommandProfiles, ConnectionPropsForSessCfg } from "@zowe/imperative"; +import { mockHandlerParameters } from "@zowe/cli-test-utils"; +import { join, normalize } from "path"; +import { Shell } from "../../src/Shell"; +import { SshBaseHandler } from "../../src/SshBaseHandler"; +import * as fs from "fs"; + +process.env.FORCE_COLOR = "0"; + +const UNIT_TEST_SSH_PROF_OPTS = { + host: "somewhere.com", + port: "22", + user: "someone", + password: "somesecret" +}; + +const UNIT_TEST_SSH_PROF_OPTS_PRIVATE_KEY = { + host: "somewhere.com", + port: "22", + user: "someone", + privateKey: normalize(join(__dirname, "..", "..", "..", "..", "..", "..", "zosuss", "__tests__", "__unit__", "__resources__", "fake_id_rsa")) +}; +const UNIT_TEST_SSH_PROF_OPTS_PRIVATE_KEY_WITH_PASSPHRASE = { + host: "somewhere.com", + port: "22", + user: "someone", + privateKey: normalize(join(__dirname, "..", "..", "..", "..", "..", "..", "zosuss", "__tests__", "__unit__", "__resources__", "fake_id_rsa")), + keyPassPhrase: "dummyPassPhrase123" +}; +const UNIT_TEST_SSH_PROF_OPTS_PRIVATE_KEY_WITH_PASSPHRASE_NO_USER = { + host: "somewhere.com", + port: "22", + privateKey: normalize(join(__dirname, "..", "..", "..", "..", "..", "..", "zosuss", "__tests__", "__unit__", "__resources__", "fake_id_rsa")), + keyPassPhrase: "dummyPassPhrase123" +}; + + +// A mocked profile map with ssh profile +const UNIT_TEST_PROFILE_MAP = new Map(); +UNIT_TEST_PROFILE_MAP.set( + "ssh", [{ + name: "ssh", + type: "ssh", + ...UNIT_TEST_SSH_PROF_OPTS + }] +); +const UNIT_TEST_PROFILES_SSH = new CommandProfiles(UNIT_TEST_PROFILE_MAP); + +const UNIT_TEST_PROFILE_MAP_PRIVATE_KEY = new Map(); +UNIT_TEST_PROFILE_MAP_PRIVATE_KEY.set( + "ssh", [{ + name: "ssh", + type: "ssh", + ...UNIT_TEST_SSH_PROF_OPTS_PRIVATE_KEY + }] +); +const UNIT_TEST_PROFILE_MAP_PRIVATE_KEY_WITH_PASSPHRASE = new Map(); +UNIT_TEST_PROFILE_MAP_PRIVATE_KEY_WITH_PASSPHRASE.set( + "ssh", [{ + name: "ssh", + type: "ssh", + ...UNIT_TEST_SSH_PROF_OPTS_PRIVATE_KEY_WITH_PASSPHRASE + }] +); +const UNIT_TEST_PROFILE_MAP_PRIVATE_KEY_WITH_PASSPHRASE_NO_USER = new Map(); +UNIT_TEST_PROFILE_MAP_PRIVATE_KEY_WITH_PASSPHRASE.set( + "ssh", [{ + name: "ssh", + type: "ssh", + ...UNIT_TEST_SSH_PROF_OPTS_PRIVATE_KEY_WITH_PASSPHRASE_NO_USER + }] +); + +const UNIT_TEST_PROFILES_SSH_PRIVATE_KEY = new CommandProfiles(UNIT_TEST_PROFILE_MAP_PRIVATE_KEY); +const UNIT_TEST_PROFILES_SSH_PRIVATE_KEY_WITH_PASSPHRASE = new CommandProfiles(UNIT_TEST_PROFILE_MAP_PRIVATE_KEY_WITH_PASSPHRASE); +const UNIT_TEST_PROFILES_SSH_PRIVATE_KEY_WITH_PASSPHRASE_NO_USER = new CommandProfiles(UNIT_TEST_PROFILE_MAP_PRIVATE_KEY_WITH_PASSPHRASE_NO_USER); + +// Mocked parameters for the unit tests +const DEFAULT_PARAMETERS: IHandlerParameters = mockHandlerParameters({ + arguments: UNIT_TEST_SSH_PROF_OPTS, + positionals: ["zos-uss", "issue", "ssh"], + definition: {} as any, + profiles: UNIT_TEST_PROFILES_SSH +}); + +const DEFAULT_PARAMETERS_PRIVATE_KEY: IHandlerParameters = mockHandlerParameters({ + arguments: UNIT_TEST_SSH_PROF_OPTS_PRIVATE_KEY, + positionals: ["zos-uss", "issue", "ssh"], + definition: {} as any, + profiles: UNIT_TEST_PROFILES_SSH_PRIVATE_KEY +}); + +const DEFAULT_PARAMETERS_KEY_PASSPHRASE: IHandlerParameters = mockHandlerParameters({ + arguments: UNIT_TEST_SSH_PROF_OPTS_PRIVATE_KEY_WITH_PASSPHRASE, + positionals: ["zos-uss", "issue", "ssh"], + definition: {} as any, + profiles: UNIT_TEST_PROFILES_SSH_PRIVATE_KEY_WITH_PASSPHRASE, +}); +const DEFAULT_PARAMETERS_KEY_PASSPHRASE_NO_USER: IHandlerParameters = mockHandlerParameters({ + arguments: UNIT_TEST_SSH_PROF_OPTS_PRIVATE_KEY_WITH_PASSPHRASE_NO_USER, + positionals: ["zos-uss", "issue", "ssh"], + definition: {} as any, + profiles: UNIT_TEST_PROFILES_SSH_PRIVATE_KEY_WITH_PASSPHRASE_NO_USER, +}); + +class myHandler extends SshBaseHandler { + public async processCmd(commandParameters: IHandlerParameters): Promise { + return await Shell.executeSsh( + this.mSession, + commandParameters.arguments.command, + (data: any) => commandParameters.response.console.log(Buffer.from(data)) + ); + } +} +const testOutput = "TEST OUTPUT"; + +describe("issue ssh handler tests", () => { + + afterEach(() => { + jest.resetAllMocks(); + }); + + it("should be able to get stdout", async () => { + Shell.executeSsh = jest.fn(async (session, command, stdoutHandler) => { + stdoutHandler(testOutput); + }); + const handler = new myHandler(); + const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); + params.arguments.command = "pwd"; + await handler.process(params); + expect(Shell.executeSsh).toHaveBeenCalledTimes(1); + expect(testOutput).toMatchSnapshot(); + }); + + it("should be able to get stdout with private key and key passphrase", async () => { + Shell.executeSsh = jest.fn(async (session, command, stdoutHandler) => { + stdoutHandler(testOutput); + }); + const handler = new myHandler(); + const params = Object.assign({}, ...[DEFAULT_PARAMETERS_KEY_PASSPHRASE]); + params.arguments.command = "echo test"; + await handler.process(params); + expect(Shell.executeSsh).toHaveBeenCalledTimes(1); + expect(testOutput).toMatchSnapshot(); + }); + it("should prompt user for keyPassphrase if none is stored and privateKey requires one", async () => { + Shell.executeSsh = jest.fn(async (session, command, stdoutHandler) => { + stdoutHandler(testOutput); + }); + jest.spyOn(fs,"readFileSync").mockReturnValue("dummyPrivateKey"); + const handler = new myHandler(); + jest.spyOn(handler,"processCmd").mockImplementationOnce(() => {throw new Error("but no passphrase given");}); + const params = Object.assign({}, ...[DEFAULT_PARAMETERS_KEY_PASSPHRASE]); + params.arguments.command = "echo test"; + jest.spyOn(ConnectionPropsForSessCfg as any,"getValuesBack").mockReturnValue(() => ({ + keyPassphrase: "validPassword" + })); + await handler.process(params); + expect(Shell.executeSsh).toHaveBeenCalledTimes(1); + expect(testOutput).toMatchSnapshot(); + }); + it("should reprompt user for keyPassphrase up to 3 times if stored passphrase failed", async () => { + Shell.executeSsh = jest.fn(async (session, command, stdoutHandler) => { + stdoutHandler(testOutput); + }); + jest.spyOn(fs,"readFileSync").mockReturnValue("dummyPrivateKey"); + const handler = new myHandler(); + const params = Object.assign({}, ...[DEFAULT_PARAMETERS_KEY_PASSPHRASE]); + params.arguments.command = "echo test"; + jest.spyOn(handler,"processCmd").mockImplementationOnce(() => {throw new Error("bad passphrase?");}); + jest.spyOn(ConnectionPropsForSessCfg as any,"getValuesBack").mockReturnValue(() => ({ + keyPassphrase: "validPassword" + })); + await handler.process(params); + expect(Shell.executeSsh).toHaveBeenCalledTimes(1); + expect(testOutput).toMatchSnapshot(); + }); + it("should fail if user fails to enter incorrect key passphrase in 3 attempts", async () => { + const testOutput = "Maximum retry attempts reached. Authentication failed."; + Shell.executeSsh = jest.fn(async (session, command, stdoutHandler) => { + stdoutHandler(testOutput); + }); + const handler = new myHandler(); + const params = { ...DEFAULT_PARAMETERS_KEY_PASSPHRASE }; + params.arguments.command = "echo test"; + jest.spyOn(handler, "processCmd").mockImplementation(() => { + throw new Error("bad passphrase?"); + }); + await expect(handler.process(params)).rejects.toThrow("Maximum retry attempts reached. Authentication failed."); + expect(handler.processCmd).toHaveBeenCalledTimes(4); + expect(testOutput).toMatchSnapshot(); + }); + it("should prompt for user and keyPassphrase if neither is stored", async () => { + const testOutput = "test"; + Shell.executeSsh = jest.fn(async (session, command, stdoutHandler) => { + stdoutHandler(testOutput); + }); + const handler = new myHandler(); + const params = { ...DEFAULT_PARAMETERS_KEY_PASSPHRASE_NO_USER }; + params.arguments.command = "echo test"; + jest.spyOn(ConnectionPropsForSessCfg as any,"getValuesBack").mockReturnValue(() => ({ + user: "someone", + keyPassphrase: "validPassword" + })); + await handler.process(params); + expect(Shell.executeSsh).toHaveBeenCalledTimes(1); + expect(testOutput).toMatchSnapshot(); + }); + it("should be able to get stdout with privateKey", async () => { + Shell.executeSsh = jest.fn(async (session, command, stdoutHandler) => { + stdoutHandler(testOutput); + }); + const handler = new myHandler(); + const params = Object.assign({}, ...[DEFAULT_PARAMETERS_PRIVATE_KEY]); + params.arguments.command = "pwd"; + await handler.process(params); + expect(Shell.executeSsh).toHaveBeenCalledTimes(1); + expect(testOutput).toMatchSnapshot(); + }); +}); diff --git a/packages/zosuss/__tests__/__unit__/__snapshots__/SshBaseHandler.unit.test.ts.snap b/packages/zosuss/__tests__/__unit__/__snapshots__/SshBaseHandler.unit.test.ts.snap new file mode 100644 index 0000000000..45544acebb --- /dev/null +++ b/packages/zosuss/__tests__/__unit__/__snapshots__/SshBaseHandler.unit.test.ts.snap @@ -0,0 +1,17 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`issue ssh handler tests should be able to get stdout 1`] = `"TEST OUTPUT"`; + +exports[`issue ssh handler tests should be able to get stdout 2`] = `"TEST OUTPUT"`; + +exports[`issue ssh handler tests should be able to get stdout with private key and key passphrase 1`] = `"TEST OUTPUT"`; + +exports[`issue ssh handler tests should be able to get stdout with privateKey 1`] = `"TEST OUTPUT"`; + +exports[`issue ssh handler tests should fail if user fails to enter incorrect key passphrase in 3 attempts 1`] = `"Maximum retry attempts reached. Authentication failed."`; + +exports[`issue ssh handler tests should prompt for user and keyPassphrase if neither is stored 1`] = `"test"`; + +exports[`issue ssh handler tests should prompt user for keyPassphrase if none is stored and privateKey requires one 1`] = `"TEST OUTPUT"`; + +exports[`issue ssh handler tests should reprompt user for keyPassphrase up to 3 times if stored passphrase failed 1`] = `"TEST OUTPUT"`; diff --git a/packages/zosuss/src/SshBaseHandler.ts b/packages/zosuss/src/SshBaseHandler.ts index c9435419d4..42d0ade227 100644 --- a/packages/zosuss/src/SshBaseHandler.ts +++ b/packages/zosuss/src/SshBaseHandler.ts @@ -91,7 +91,7 @@ export abstract class SshBaseHandler implements ICommandHandler { try { await this.processCmd(commandParameters); } catch (e) { - commandParameters.response.console.log("Initial key passphrase authentication failed!" + "\n"); + this.console.log("Initial key passphrase authentication failed!" + "\n"); if ( e.message.includes("but no passphrase given") || e.message.includes("bad passphrase?") @@ -144,7 +144,7 @@ export abstract class SshBaseHandler implements ICommandHandler { await this.processCmd(commandParameters); success = true; } catch (retryError) { - commandParameters.response.console.log( + this.console.log( "\n" + `Key passphrase authentication failed! (${ attempt + 1 From d02ba3191f3c63da2c6ec56c2e4266f8e36d5173 Mon Sep 17 00:00:00 2001 From: jace-roell Date: Fri, 2 Aug 2024 10:53:07 -0400 Subject: [PATCH 07/24] remove unused snapshot Signed-off-by: jace-roell --- .../issue/ssh/__snapshots__/Ssh.handler.unit.test.ts.snap | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/cli/__tests__/zosuss/__unit__/issue/ssh/__snapshots__/Ssh.handler.unit.test.ts.snap b/packages/cli/__tests__/zosuss/__unit__/issue/ssh/__snapshots__/Ssh.handler.unit.test.ts.snap index f0d2c34f0e..e9f13da78c 100644 --- a/packages/cli/__tests__/zosuss/__unit__/issue/ssh/__snapshots__/Ssh.handler.unit.test.ts.snap +++ b/packages/cli/__tests__/zosuss/__unit__/issue/ssh/__snapshots__/Ssh.handler.unit.test.ts.snap @@ -14,8 +14,6 @@ exports[`issue ssh handler tests should fail if user fails to enter incorrect ke exports[`issue ssh handler tests should prompt for user and keyPassphrase if neither is stored 1`] = `"test"`; -exports[`issue ssh handler tests should prompt for user and keyPassphrase if neither is stored 2`] = `"test"`; - exports[`issue ssh handler tests should prompt user for keyPassphrase if none is stored and privateKey requires one 1`] = `"TEST OUTPUT"`; exports[`issue ssh handler tests should reprompt user for keyPassphrase up to 3 times if stored passphrase failed 1`] = `"TEST OUTPUT"`; From 4a695859398e1c698eb7da0ffcb5a5c434d09738 Mon Sep 17 00:00:00 2001 From: jace-roell Date: Mon, 5 Aug 2024 10:59:20 -0400 Subject: [PATCH 08/24] resolved syntax and changelog Signed-off-by: jace-roell --- packages/imperative/CHANGELOG.md | 5 ---- .../src/session/ConnectionPropsForSessCfg.ts | 10 ++++---- .../session/doc/IOverridePromptConnProps.ts | 4 +-- packages/zosuss/CHANGELOG.md | 2 +- packages/zosuss/src/SshBaseHandler.ts | 25 ++++++++----------- 5 files changed, 19 insertions(+), 27 deletions(-) diff --git a/packages/imperative/CHANGELOG.md b/packages/imperative/CHANGELOG.md index 548639899f..835f8bd7e4 100644 --- a/packages/imperative/CHANGELOG.md +++ b/packages/imperative/CHANGELOG.md @@ -2,11 +2,6 @@ All notable changes to the Imperative package will be documented in this file. -## Recent Changes - -- BugFix: Resolved bug that resulted in user not being prompted for a keyPassphrase if in the secure array of ssh profile. [#1770](https://github.com/zowe/zowe-cli/issues/1770) -- Enhancement: SshBaseHandler will now prompt user up to 3 times to enter the correct keyPassphrase in the case that the stored value is incorrect or no value is stored. [#1770](https://github.com/zowe/zowe-cli/issues/1770) - ## `8.0.0-next.202407262216` - Update: See `5.26.1` for details diff --git a/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts b/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts index fe0949ba81..a27474ac46 100644 --- a/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts +++ b/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts @@ -113,8 +113,8 @@ export class ConnectionPropsForSessCfg { ); // This function will provide all the needed properties in one array - let promptForValues: (keyof ISession)[] = []; - const doNotPromptForValues: (keyof ISession)[] = []; + let promptForValues: (keyof SessCfgType & string)[] = []; + const doNotPromptForValues: (keyof SessCfgType & string)[] = []; /* Add the override properties to the session object. */ @@ -127,7 +127,7 @@ export class ConnectionPropsForSessCfg { if (cmdArgs[argName] != null) { (sessCfgToUse as any)[override.propertyName] = cmdArgs[argName]; } for (const prop of override.propertiesOverridden) { // Make sure we do not prompt for the overridden property. - if (!doNotPromptForValues.includes(prop as any)) { doNotPromptForValues.push(prop as any); } + if (!doNotPromptForValues.includes(prop)) { doNotPromptForValues.push(prop); } if (prop in sessCfgToUse) { (sessCfgToUse as any)[prop] = undefined; } } } @@ -172,7 +172,7 @@ export class ConnectionPropsForSessCfg { this.loadSecureSessCfgProps(connOptsToUse.parms, promptForValues); if (connOptsToUse.getValuesBack == null && connOptsToUse.doPrompting) { - connOptsToUse.getValuesBack = this.getValuesBack(connOptsToUse as any); + connOptsToUse.getValuesBack = this.getValuesBack(connOptsToUse); } if (connOptsToUse.getValuesBack != null) { @@ -380,7 +380,7 @@ export class ConnectionPropsForSessCfg { * @param connOpts Options for adding connection properties * @returns Name-value pairs of connection properties */ - private static getValuesBack(connOpts: IOptionsForAddConnProps): (properties: string[]) => Promise<{ [key: string]: any }> { + private static getValuesBack(connOpts: IOptionsForAddConnProps): (properties: string[]) => Promise<{ [key: string]: any }> { return async (promptForValues: string[]) => { /* The check for console.log in the following 'if' statement is only needed for tests * which do not create a mock for the connOpts.parms.response.console.log property. diff --git a/packages/imperative/src/rest/src/session/doc/IOverridePromptConnProps.ts b/packages/imperative/src/rest/src/session/doc/IOverridePromptConnProps.ts index 819017b927..08dc392cab 100644 --- a/packages/imperative/src/rest/src/session/doc/IOverridePromptConnProps.ts +++ b/packages/imperative/src/rest/src/session/doc/IOverridePromptConnProps.ts @@ -34,11 +34,11 @@ export interface IOverridePromptConnProps * Prompting logic is only in place for host, port, user, and password, but cert, certKey, tokenType, and tokenValue may also need * to be overridden. */ - propertiesOverridden: (keyof SessCfgType)[]; + propertiesOverridden: (keyof SessCfgType & string)[]; /** * Allows for passing for additional properties to prompt for. * Utilized in the case of a incorrect/not stored key passphrase. */ - propsToPromptFor?: (keyof SessCfgType)[]; + propsToPromptFor?: (keyof SessCfgType & string)[]; } \ No newline at end of file diff --git a/packages/zosuss/CHANGELOG.md b/packages/zosuss/CHANGELOG.md index 7b4b6452a5..edccac0043 100644 --- a/packages/zosuss/CHANGELOG.md +++ b/packages/zosuss/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to the Zowe z/OS USS SDK package will be documented in this ## Recent Changes - BugFix: Resolved bug that resulted in user not being prompted for a keyPassphrase if in the secure array of ssh profile. [#1770](https://github.com/zowe/zowe-cli/issues/1770) -- Enhancement: SshBaseHandler will now prompt user up to 3 times to enter the correct keyPassphrase in the case that the stored value is incorrect or no value is stored. [#1770](https://github.com/zowe/zowe-cli/issues/1770) +- Enhancement: SshBaseHandler.ts command processor will now prompt user up to 3 times to enter the correct keyPassphrase in the case that the stored value is incorrect or no value is stored. [#1770](https://github.com/zowe/zowe-cli/issues/1770) ## `8.0.0-next.202403132009` diff --git a/packages/zosuss/src/SshBaseHandler.ts b/packages/zosuss/src/SshBaseHandler.ts index 42d0ade227..875d047acc 100644 --- a/packages/zosuss/src/SshBaseHandler.ts +++ b/packages/zosuss/src/SshBaseHandler.ts @@ -1,13 +1,13 @@ /* - * This program and the accompanying materials are made available under the terms of the - * Eclipse Public License v2.0 which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Copyright Contributors to the Zowe Project. - * - */ +* This program and the accompanying materials are made available under the terms of the +* Eclipse Public License v2.0 which accompanies this distribution, and is available at +* https://www.eclipse.org/legal/epl-v20.html +* +* SPDX-License-Identifier: EPL-2.0 +* +* Copyright Contributors to the Zowe Project. +* +*/ import { // AbstractSession, @@ -120,9 +120,7 @@ export abstract class SshBaseHandler implements ICommandHandler { let saveKP: boolean = true; const result = utils.parseKey( fs.readFileSync( - sshSessCfgWithCreds[ - "privateKey" - ] + sshSessCfgWithCreds.privateKey ), givenValue.keyPassphrase ); @@ -147,11 +145,10 @@ export abstract class SshBaseHandler implements ICommandHandler { this.console.log( "\n" + `Key passphrase authentication failed! (${ - attempt + 1 + ++attempt }/${maxAttempts})` + "\n" ); - attempt++; if (attempt >= maxAttempts) { throw new Error( "Maximum retry attempts reached. Authentication failed." From 1b6f2f1e2abf8f452fae160be6209852816a877e Mon Sep 17 00:00:00 2001 From: jace-roell Date: Mon, 5 Aug 2024 11:07:17 -0400 Subject: [PATCH 09/24] fix changelog Signed-off-by: jace-roell --- packages/imperative/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/imperative/CHANGELOG.md b/packages/imperative/CHANGELOG.md index 835f8bd7e4..2b618c200b 100644 --- a/packages/imperative/CHANGELOG.md +++ b/packages/imperative/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to the Imperative package will be documented in this file. +## Recent Changes + +- BugFix: Resolved bug that resulted in user not being prompted for a keyPassphrase if in the secure array of ssh profile. [#1770](https://github.com/zowe/zowe-cli/issues/1770) + ## `8.0.0-next.202407262216` - Update: See `5.26.1` for details From b1476a9c37ffc3bb44bcd742bf6e71bbee6d2907 Mon Sep 17 00:00:00 2001 From: jace-roell Date: Mon, 5 Aug 2024 11:19:30 -0400 Subject: [PATCH 10/24] fix isGivenValueValid typing Signed-off-by: jace-roell --- packages/zosuss/src/SshBaseHandler.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/zosuss/src/SshBaseHandler.ts b/packages/zosuss/src/SshBaseHandler.ts index 875d047acc..20ff5aecdf 100644 --- a/packages/zosuss/src/SshBaseHandler.ts +++ b/packages/zosuss/src/SshBaseHandler.ts @@ -114,15 +114,13 @@ export abstract class SshBaseHandler implements ICommandHandler { propsToPromptFor: [ { name: "keyPassphrase", - isGivenValueValid: (givenValue: { - [key: string]: any; - }) => { + isGivenValueValid: (givenValue: string) => { let saveKP: boolean = true; const result = utils.parseKey( fs.readFileSync( sshSessCfgWithCreds.privateKey ), - givenValue.keyPassphrase + givenValue ); if (result instanceof Error) saveKP = From d9a840e866ce7f9a5a597e9be264160f14fe89ad Mon Sep 17 00:00:00 2001 From: jace-roell Date: Mon, 5 Aug 2024 11:30:57 -0400 Subject: [PATCH 11/24] fix definition Signed-off-by: jace-roell --- .../src/rest/src/session/doc/IOptionsForAddConnProps.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts b/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts index de99e558ee..15803261b5 100644 --- a/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts +++ b/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts @@ -61,7 +61,7 @@ export interface IOptionsForAddConnProps name: keyof SessCfgType, secure?: boolean, description?: string, - isGivenValueValid?: (givenValue: {[key: string]: any}) => boolean + isGivenValueValid?: (givenValue: string) => boolean }[]; /** From 246fe534b9979a6bd4695c1949d6baec31c7f8ed Mon Sep 17 00:00:00 2001 From: jace-roell Date: Mon, 5 Aug 2024 11:37:21 -0400 Subject: [PATCH 12/24] fixed typing on answers for prompts Signed-off-by: jace-roell --- .../src/rest/src/session/ConnectionPropsForSessCfg.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts b/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts index a27474ac46..11bf012b83 100644 --- a/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts +++ b/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts @@ -184,7 +184,7 @@ export class ConnectionPropsForSessCfg { connOpts.propsToPromptFor.forEach(obj => { if(obj.isGivenValueValid != null) { - if(!obj.isGivenValueValid(answers)) promptForValues = promptForValues.filter(item => obj.name !== item); + if(!obj.isGivenValueValid(answers.keyPassphrase)) promptForValues = promptForValues.filter(item => obj.name !== item); } }); } From fd2eeed4728f21991a931374f91cc4032e24b9ce Mon Sep 17 00:00:00 2001 From: jace-roell Date: Mon, 5 Aug 2024 11:52:02 -0400 Subject: [PATCH 13/24] generalized propsToPrmoptFor to not only utilize keyPassphrase Signed-off-by: jace-roell --- .../src/rest/src/session/ConnectionPropsForSessCfg.ts | 2 +- .../src/rest/src/session/doc/IOptionsForAddConnProps.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts b/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts index 11bf012b83..b0410e57be 100644 --- a/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts +++ b/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts @@ -184,7 +184,7 @@ export class ConnectionPropsForSessCfg { connOpts.propsToPromptFor.forEach(obj => { if(obj.isGivenValueValid != null) { - if(!obj.isGivenValueValid(answers.keyPassphrase)) promptForValues = promptForValues.filter(item => obj.name !== item); + if(!obj.isGivenValueValid(answers[obj.name])) promptForValues = promptForValues.filter(item => obj.name !== item); } }); } diff --git a/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts b/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts index 15803261b5..2ccedb1641 100644 --- a/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts +++ b/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts @@ -58,7 +58,7 @@ export interface IOptionsForAddConnProps */ propsToPromptFor?: { - name: keyof SessCfgType, + name: keyof SessCfgType & string, secure?: boolean, description?: string, isGivenValueValid?: (givenValue: string) => boolean From 5a071f34ca786f5de5033ebffb7fe5adcfa415f5 Mon Sep 17 00:00:00 2001 From: jace-roell Date: Tue, 6 Aug 2024 09:21:45 -0400 Subject: [PATCH 14/24] added ConnectionPropForSessCfg test Signed-off-by: jace-roell --- .../ConnectionPropsForSessCfg.unit.test.ts | 1072 +++++++++++------ .../src/session/ConnectionPropsForSessCfg.ts | 2 +- .../__unit__/SshBaseHandler.unit.test.ts | 11 + .../SshBaseHandler.unit.test.ts.snap | 2 + 4 files changed, 694 insertions(+), 393 deletions(-) diff --git a/packages/imperative/src/rest/__tests__/session/ConnectionPropsForSessCfg.unit.test.ts b/packages/imperative/src/rest/__tests__/session/ConnectionPropsForSessCfg.unit.test.ts index c0a045a32a..4b719643f9 100644 --- a/packages/imperative/src/rest/__tests__/session/ConnectionPropsForSessCfg.unit.test.ts +++ b/packages/imperative/src/rest/__tests__/session/ConnectionPropsForSessCfg.unit.test.ts @@ -1,13 +1,13 @@ /* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ jest.mock("../../../logger/src/LoggerUtils"); @@ -24,24 +24,50 @@ import { IOverridePromptConnProps } from "../../src/session/doc/IOverridePromptC import { IOptionsForAddConnProps } from "../../src/session/doc/IOptionsForAddConnProps"; import { ImperativeConfig } from "../../../utilities"; import { ConfigUtils } from "../../../config/src/ConfigUtils"; - - -const certFilePath = join(__dirname, "..", "..", "..", "..", "__tests__", "__integration__", "cmd", - "__tests__", "integration", "cli", "auth", "__resources__", "fakeCert.cert"); -const certKeyFilePath = join(__dirname, "..", "..", "..", "..", "__tests__", "__integration__", "cmd", - "__tests__", "integration", "cli", "auth", "__resources__", "fakeKey.key"); +import { ISshSession } from "../../../../../zosuss/lib/doc/ISshSession"; +const certFilePath = join( + __dirname, + "..", + "..", + "..", + "..", + "__tests__", + "__integration__", + "cmd", + "__tests__", + "integration", + "cli", + "auth", + "__resources__", + "fakeCert.cert" +); +const certKeyFilePath = join( + __dirname, + "..", + "..", + "..", + "..", + "__tests__", + "__integration__", + "cmd", + "__tests__", + "integration", + "cli", + "auth", + "__resources__", + "fakeKey.key" +); interface extendedSession extends ISession { - someKey?: string + someKey?: string; } describe("ConnectionPropsForSessCfg tests", () => { - afterEach(() => { jest.clearAllMocks(); }); - it("authenticate with user and pass", async() => { + it("authenticate with user and pass", async () => { const initialSessCfg = { rejectUnauthorized: true, }; @@ -51,11 +77,13 @@ describe("ConnectionPropsForSessCfg tests", () => { host: "SomeHost", port: 11, user: "FakeUser", - password: "FakePassword" + password: "FakePassword", }; - const sessCfgWithConnProps = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args - ); + const sessCfgWithConnProps = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args + ); expect(sessCfgWithConnProps.hostname).toBe("SomeHost"); expect(sessCfgWithConnProps.port).toBe(11); expect(sessCfgWithConnProps.user).toBe("FakeUser"); @@ -67,58 +95,68 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.certKey).toBeUndefined(); }); - it("authenticate with user, pass, and tokenType to get token", async() => { + it("authenticate with user, pass, and tokenType to get token", async () => { const initialSessCfg = { hostname: "SomeHost", port: 11, - rejectUnauthorized: true + rejectUnauthorized: true, }; const args = { $0: "zowe", _: [""], user: "FakeUser", password: "FakePassword", - tokenType: SessConstants.TOKEN_TYPE_JWT + tokenType: SessConstants.TOKEN_TYPE_JWT, }; - const sessCfgWithConnProps = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args, {requestToken: true} - ); + const sessCfgWithConnProps = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args, + { requestToken: true } + ); expect(sessCfgWithConnProps.hostname).toBe("SomeHost"); expect(sessCfgWithConnProps.user).toBe("FakeUser"); expect(sessCfgWithConnProps.password).toBe("FakePassword"); expect(sessCfgWithConnProps.type).toBe(SessConstants.AUTH_TYPE_TOKEN); - expect(sessCfgWithConnProps.tokenType).toBe(SessConstants.TOKEN_TYPE_JWT); + expect(sessCfgWithConnProps.tokenType).toBe( + SessConstants.TOKEN_TYPE_JWT + ); expect(sessCfgWithConnProps.tokenValue).toBeUndefined(); expect(sessCfgWithConnProps.cert).toBeUndefined(); expect(sessCfgWithConnProps.certKey).toBeUndefined(); }); - it("authenticate with user, pass, and *NO* tokenType to get token", async() => { + it("authenticate with user, pass, and *NO* tokenType to get token", async () => { const initialSessCfg = { hostname: "SomeHost", port: 11, - rejectUnauthorized: true + rejectUnauthorized: true, }; const args = { $0: "zowe", _: [""], user: "FakeUser", - password: "FakePassword" + password: "FakePassword", }; - const sessCfgWithConnProps = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args, {requestToken: true} - ); + const sessCfgWithConnProps = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args, + { requestToken: true } + ); expect(sessCfgWithConnProps.hostname).toBe("SomeHost"); expect(sessCfgWithConnProps.user).toBe("FakeUser"); expect(sessCfgWithConnProps.password).toBe("FakePassword"); expect(sessCfgWithConnProps.type).toBe(SessConstants.AUTH_TYPE_TOKEN); - expect(sessCfgWithConnProps.tokenType).toBe(SessConstants.TOKEN_TYPE_JWT); + expect(sessCfgWithConnProps.tokenType).toBe( + SessConstants.TOKEN_TYPE_JWT + ); expect(sessCfgWithConnProps.tokenValue).toBeUndefined(); expect(sessCfgWithConnProps.cert).toBeUndefined(); expect(sessCfgWithConnProps.certKey).toBeUndefined(); }); - it("authenticate with token value", async() => { + it("authenticate with token value", async () => { const initialSessCfg = { hostname: "SomeHost", port: 11, @@ -129,9 +167,11 @@ describe("ConnectionPropsForSessCfg tests", () => { _: [""], tokenValue: "FakeToken", }; - const sessCfgWithConnProps = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args - ); + const sessCfgWithConnProps = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args + ); expect(sessCfgWithConnProps.hostname).toBe("SomeHost"); expect(sessCfgWithConnProps.tokenValue).toBe("FakeToken"); expect(sessCfgWithConnProps.type).toBe(SessConstants.AUTH_TYPE_BEARER); @@ -141,48 +181,56 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.certKey).toBeUndefined(); }); - it("authenticate with token value and token type", async() => { + it("authenticate with token value and token type", async () => { const initialSessCfg = { hostname: "SomeHost", port: 11, - rejectUnauthorized: true + rejectUnauthorized: true, }; const args = { $0: "zowe", _: [""], tokenValue: "FakeToken", - tokenType: SessConstants.TOKEN_TYPE_LTPA + tokenType: SessConstants.TOKEN_TYPE_LTPA, }; - const sessCfgWithConnProps = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args - ); + const sessCfgWithConnProps = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args + ); expect(sessCfgWithConnProps.hostname).toBe("SomeHost"); expect(sessCfgWithConnProps.tokenValue).toBe("FakeToken"); expect(sessCfgWithConnProps.type).toBe(SessConstants.AUTH_TYPE_TOKEN); - expect(sessCfgWithConnProps.tokenType).toBe(SessConstants.TOKEN_TYPE_LTPA); + expect(sessCfgWithConnProps.tokenType).toBe( + SessConstants.TOKEN_TYPE_LTPA + ); expect(sessCfgWithConnProps.user).toBeUndefined(); expect(sessCfgWithConnProps.password).toBeUndefined(); expect(sessCfgWithConnProps.cert).toBeUndefined(); expect(sessCfgWithConnProps.certKey).toBeUndefined(); }); - it("authenticate with certFile and certKeyFile", async() => { + it("authenticate with certFile and certKeyFile", async () => { const initialSessCfg = { hostname: "SomeHost", port: 11, - rejectUnauthorized: true + rejectUnauthorized: true, }; const args = { $0: "zowe", _: [""], certFile: certFilePath, - certKeyFile: certKeyFilePath + certKeyFile: certKeyFilePath, }; - const sessCfgWithConnProps = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args - ); + const sessCfgWithConnProps = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args + ); expect(sessCfgWithConnProps.hostname).toBe("SomeHost"); - expect(sessCfgWithConnProps.type).toBe(SessConstants.AUTH_TYPE_CERT_PEM); + expect(sessCfgWithConnProps.type).toBe( + SessConstants.AUTH_TYPE_CERT_PEM + ); expect(sessCfgWithConnProps.cert).toBe(certFilePath); expect(sessCfgWithConnProps.certKey).toBe(certKeyFilePath); expect(sessCfgWithConnProps.user).toBeUndefined(); @@ -191,11 +239,11 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.tokenValue).toBeUndefined(); }); - it("ignore token and cert if unsupported auth types and authenticate with user and pass", async() => { + it("ignore token and cert if unsupported auth types and authenticate with user and pass", async () => { const initialSessCfg = { hostname: "SomeHost", port: 11, - rejectUnauthorized: true + rejectUnauthorized: true, }; const args = { $0: "zowe", @@ -203,15 +251,18 @@ describe("ConnectionPropsForSessCfg tests", () => { cert: "fakeCert", certKey: "fakeCertKey", tokenType: SessConstants.TOKEN_TYPE_JWT, - tokenValue: "fakeToken" + tokenValue: "fakeToken", }; const fakePromptFn = jest.fn().mockReturnValue({ - "user": "FakeUser", - "password": "FakePassword" + user: "FakeUser", + password: "FakePassword", }); - const sessCfgWithConnProps = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args, {getValuesBack: fakePromptFn, supportedAuthTypes: ["basic"]} - ); + const sessCfgWithConnProps = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args, + { getValuesBack: fakePromptFn, supportedAuthTypes: ["basic"] } + ); expect(fakePromptFn).toHaveBeenCalledWith(["user", "password"]); expect(sessCfgWithConnProps.hostname).toBe("SomeHost"); expect(sessCfgWithConnProps.user).toBe("FakeUser"); @@ -219,11 +270,11 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.type).toBe(SessConstants.AUTH_TYPE_BASIC); }); - it("not set tokenValue if user and pass are defined", async() => { + it("not set tokenValue if user and pass are defined", async () => { const initialSessCfg = { hostname: "SomeHost", port: 11, - rejectUnauthorized: true + rejectUnauthorized: true, }; const args = { $0: "zowe", @@ -231,11 +282,13 @@ describe("ConnectionPropsForSessCfg tests", () => { user: "FakeUser", password: "FakePassword", tokenType: SessConstants.TOKEN_TYPE_JWT, - tokenValue: "FakeToken" + tokenValue: "FakeToken", }; - const sessCfgWithConnProps = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args - ); + const sessCfgWithConnProps = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args + ); expect(sessCfgWithConnProps.hostname).toBe("SomeHost"); expect(sessCfgWithConnProps.user).toBe("FakeUser"); expect(sessCfgWithConnProps.password).toBe("FakePassword"); @@ -246,20 +299,23 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.certKey).toBeUndefined(); }); - it("not prompt when asked not to prompt", async() => { + it("not prompt when asked not to prompt", async () => { const initialSessCfg = { hostname: "SomeHost", port: 11, - rejectUnauthorized: true + rejectUnauthorized: true, }; const args = { $0: "zowe", - _: [""] + _: [""], }; - const sessCfgWithConnProps: ISession = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args, {doPrompting: false} - ); + const sessCfgWithConnProps: ISession = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args, + { doPrompting: false } + ); expect(sessCfgWithConnProps.type).toBe(SessConstants.AUTH_TYPE_BASIC); expect(sessCfgWithConnProps.user).toBeUndefined(); expect(sessCfgWithConnProps.password).toBeUndefined(); @@ -269,32 +325,37 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.certKey).toBeUndefined(); }); - it("override with a different command line name", async() => { + it("override with a different command line name", async () => { const passFromPrompt = "somePass"; const initialSessCfg: extendedSession = { hostname: "SomeHost", port: 11, user: "FakeUser", password: "somePass", - rejectUnauthorized: true + rejectUnauthorized: true, }; const args = { $0: "zowe", _: [""], - someKeyOther: "somekeyvalue" - }; - const overrides: IOverridePromptConnProps[] = [{ - propertyName: "someKey", - argumentName: "someKeyOther", - propertiesOverridden: [ - "password", - "tokenType", - "tokenValue", - "cert", - "certKey" - ] - }]; - const mockClientPrompt = jest.spyOn(ConnectionPropsForSessCfg as any, "clientPrompt"); + someKeyOther: "somekeyvalue", + }; + const overrides: IOverridePromptConnProps[] = [ + { + propertyName: "someKey", + argumentName: "someKeyOther", + propertiesOverridden: [ + "password", + "tokenType", + "tokenValue", + "cert", + "certKey", + ], + }, + ]; + const mockClientPrompt = jest.spyOn( + ConnectionPropsForSessCfg as any, + "clientPrompt" + ); // command handler prompt method (CLI versus SDK-based prompting) const commandHandlerPrompt = jest.fn(() => { return Promise.resolve(passFromPrompt); @@ -303,13 +364,20 @@ describe("ConnectionPropsForSessCfg tests", () => { const parms = { response: { console: { - prompt: commandHandlerPrompt - } - } + prompt: commandHandlerPrompt, + }, + }, }; - const sessCfgWithConnProps: extendedSession = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args, {doPrompting: true, propertyOverrides: overrides, parms: (parms as any)} - ); + const sessCfgWithConnProps: extendedSession = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args, + { + doPrompting: true, + propertyOverrides: overrides, + parms: parms as any, + } + ); expect(sessCfgWithConnProps.type).toBe(SessConstants.AUTH_TYPE_BASIC); expect(commandHandlerPrompt).not.toHaveBeenCalled(); // we are only testing that we call an already tested prompt method if in CLI mode expect(mockClientPrompt).not.toHaveBeenCalled(); @@ -322,31 +390,36 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.certKey).toBeUndefined(); }); - it("override a session value when an override is specified on the command line", async() => { + it("override a session value when an override is specified on the command line", async () => { const passFromPrompt = "somePass"; const initialSessCfg: extendedSession = { hostname: "SomeHost", port: 11, user: "FakeUser", password: "somePass", - rejectUnauthorized: true + rejectUnauthorized: true, }; const args = { $0: "zowe", _: [""], - someKey: "somekeyvalue" - }; - const overrides: IOverridePromptConnProps[] = [{ - propertyName: "someKey", - propertiesOverridden: [ - "password", - "tokenType", - "tokenValue", - "cert", - "certKey" - ] - }]; - const mockClientPrompt = jest.spyOn(ConnectionPropsForSessCfg as any, "clientPrompt"); + someKey: "somekeyvalue", + }; + const overrides: IOverridePromptConnProps[] = [ + { + propertyName: "someKey", + propertiesOverridden: [ + "password", + "tokenType", + "tokenValue", + "cert", + "certKey", + ], + }, + ]; + const mockClientPrompt = jest.spyOn( + ConnectionPropsForSessCfg as any, + "clientPrompt" + ); // command handler prompt method (CLI versus SDK-based prompting) const commandHandlerPrompt = jest.fn(() => { return Promise.resolve(passFromPrompt); @@ -355,13 +428,20 @@ describe("ConnectionPropsForSessCfg tests", () => { const parms = { response: { console: { - prompt: commandHandlerPrompt - } - } + prompt: commandHandlerPrompt, + }, + }, }; - const sessCfgWithConnProps: extendedSession = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args, {doPrompting: true, propertyOverrides: overrides, parms: (parms as any)} - ); + const sessCfgWithConnProps: extendedSession = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args, + { + doPrompting: true, + propertyOverrides: overrides, + parms: parms as any, + } + ); expect(sessCfgWithConnProps.type).toBe(SessConstants.AUTH_TYPE_BASIC); expect(commandHandlerPrompt).not.toHaveBeenCalled(); // we are only testing that we call an already tested prompt method if in CLI mode expect(mockClientPrompt).not.toHaveBeenCalled(); @@ -374,7 +454,7 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.certKey).toBeUndefined(); }); - it("override a session value when an override is specified on the session", async() => { + it("override a session value when an override is specified on the session", async () => { const passFromPrompt = "somePass"; const initialSessCfg: extendedSession = { hostname: "SomeHost", @@ -382,23 +462,28 @@ describe("ConnectionPropsForSessCfg tests", () => { user: "FakeUser", password: "somePass", someKey: "somekeyvalue", - rejectUnauthorized: true + rejectUnauthorized: true, }; const args = { $0: "zowe", - _: [""] - }; - const overrides: IOverridePromptConnProps[] = [{ - propertyName: "someKey", - propertiesOverridden: [ - "password", - "tokenType", - "tokenValue", - "cert", - "certKey" - ] - }]; - const mockClientPrompt = jest.spyOn(ConnectionPropsForSessCfg as any, "clientPrompt"); + _: [""], + }; + const overrides: IOverridePromptConnProps[] = [ + { + propertyName: "someKey", + propertiesOverridden: [ + "password", + "tokenType", + "tokenValue", + "cert", + "certKey", + ], + }, + ]; + const mockClientPrompt = jest.spyOn( + ConnectionPropsForSessCfg as any, + "clientPrompt" + ); // command handler prompt method (CLI versus SDK-based prompting) const commandHandlerPrompt = jest.fn(() => { return Promise.resolve(passFromPrompt); @@ -407,13 +492,20 @@ describe("ConnectionPropsForSessCfg tests", () => { const parms = { response: { console: { - prompt: commandHandlerPrompt - } - } + prompt: commandHandlerPrompt, + }, + }, }; - const sessCfgWithConnProps: extendedSession = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args, {doPrompting: true, propertyOverrides: overrides, parms: (parms as any)} - ); + const sessCfgWithConnProps: extendedSession = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args, + { + doPrompting: true, + propertyOverrides: overrides, + parms: parms as any, + } + ); expect(sessCfgWithConnProps.type).toBe(SessConstants.AUTH_TYPE_BASIC); expect(commandHandlerPrompt).not.toHaveBeenCalled(); // we are only testing that we call an already tested prompt method if in CLI mode expect(mockClientPrompt).not.toHaveBeenCalled(); @@ -426,30 +518,35 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.certKey).toBeUndefined(); }); - it("not prompt when an override is specified on the command line", async() => { + it("not prompt when an override is specified on the command line", async () => { const passFromPrompt = "somePass"; const initialSessCfg: extendedSession = { hostname: "SomeHost", port: 11, user: "FakeUser", - rejectUnauthorized: true + rejectUnauthorized: true, }; const args = { $0: "zowe", _: [""], - someKey: "somekeyvalue" - }; - const overrides: IOverridePromptConnProps[] = [{ - propertyName: "someKey", - propertiesOverridden: [ - "password", - "tokenType", - "tokenValue", - "cert", - "certKey" - ] - }]; - const mockClientPrompt = jest.spyOn(ConnectionPropsForSessCfg as any, "clientPrompt"); + someKey: "somekeyvalue", + }; + const overrides: IOverridePromptConnProps[] = [ + { + propertyName: "someKey", + propertiesOverridden: [ + "password", + "tokenType", + "tokenValue", + "cert", + "certKey", + ], + }, + ]; + const mockClientPrompt = jest.spyOn( + ConnectionPropsForSessCfg as any, + "clientPrompt" + ); // command handler prompt method (CLI versus SDK-based prompting) const commandHandlerPrompt = jest.fn(() => { return Promise.resolve(passFromPrompt); @@ -458,13 +555,20 @@ describe("ConnectionPropsForSessCfg tests", () => { const parms = { response: { console: { - prompt: commandHandlerPrompt - } - } + prompt: commandHandlerPrompt, + }, + }, }; - const sessCfgWithConnProps: extendedSession = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args, {doPrompting: true, propertyOverrides: overrides, parms: (parms as any)} - ); + const sessCfgWithConnProps: extendedSession = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args, + { + doPrompting: true, + propertyOverrides: overrides, + parms: parms as any, + } + ); expect(sessCfgWithConnProps.type).toBe(SessConstants.AUTH_TYPE_BASIC); expect(commandHandlerPrompt).not.toHaveBeenCalled(); // we are only testing that we call an already tested prompt method if in CLI mode expect(mockClientPrompt).not.toHaveBeenCalled(); @@ -477,30 +581,35 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.certKey).toBeUndefined(); }); - it("not prompt when an override is specified on the session", async() => { + it("not prompt when an override is specified on the session", async () => { const passFromPrompt = "somePass"; const initialSessCfg: extendedSession = { hostname: "SomeHost", port: 11, user: "FakeUser", rejectUnauthorized: true, - someKey: "somekeyvalue" + someKey: "somekeyvalue", }; const args = { $0: "zowe", - _: [""] - }; - const overrides: IOverridePromptConnProps[] = [{ - propertyName: "someKey", - propertiesOverridden: [ - "password", - "tokenType", - "tokenValue", - "cert", - "certKey" - ] - }]; - const mockClientPrompt = jest.spyOn(ConnectionPropsForSessCfg as any, "clientPrompt"); + _: [""], + }; + const overrides: IOverridePromptConnProps[] = [ + { + propertyName: "someKey", + propertiesOverridden: [ + "password", + "tokenType", + "tokenValue", + "cert", + "certKey", + ], + }, + ]; + const mockClientPrompt = jest.spyOn( + ConnectionPropsForSessCfg as any, + "clientPrompt" + ); // command handler prompt method (CLI versus SDK-based prompting) const commandHandlerPrompt = jest.fn(() => { return Promise.resolve(passFromPrompt); @@ -509,13 +618,20 @@ describe("ConnectionPropsForSessCfg tests", () => { const parms = { response: { console: { - prompt: commandHandlerPrompt - } - } + prompt: commandHandlerPrompt, + }, + }, }; - const sessCfgWithConnProps: extendedSession = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args, {doPrompting: true, propertyOverrides: overrides, parms: (parms as any)} - ); + const sessCfgWithConnProps: extendedSession = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args, + { + doPrompting: true, + propertyOverrides: overrides, + parms: parms as any, + } + ); expect(sessCfgWithConnProps.type).toBe(SessConstants.AUTH_TYPE_BASIC); expect(commandHandlerPrompt).not.toHaveBeenCalled(); // we are only testing that we call an already tested prompt method if in CLI mode expect(mockClientPrompt).not.toHaveBeenCalled(); @@ -528,29 +644,34 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.certKey).toBeUndefined(); }); - it("should prompt when an override is specified but is not present", async() => { + it("should prompt when an override is specified but is not present", async () => { const passFromPrompt = "somePass"; const initialSessCfg: extendedSession = { hostname: "SomeHost", port: 11, user: "FakeUser", - rejectUnauthorized: true + rejectUnauthorized: true, }; const args = { $0: "zowe", - _: [""] - }; - const overrides: IOverridePromptConnProps[] = [{ - propertyName: "someKey", - propertiesOverridden: [ - "password", - "tokenType", - "tokenValue", - "cert", - "certKey" - ] - }]; - const mockClientPrompt = jest.spyOn(ConnectionPropsForSessCfg as any, "clientPrompt"); + _: [""], + }; + const overrides: IOverridePromptConnProps[] = [ + { + propertyName: "someKey", + propertiesOverridden: [ + "password", + "tokenType", + "tokenValue", + "cert", + "certKey", + ], + }, + ]; + const mockClientPrompt = jest.spyOn( + ConnectionPropsForSessCfg as any, + "clientPrompt" + ); // command handler prompt method (CLI versus SDK-based prompting) const commandHandlerPrompt = jest.fn(() => { return Promise.resolve(passFromPrompt); @@ -559,13 +680,20 @@ describe("ConnectionPropsForSessCfg tests", () => { const parms = { response: { console: { - prompt: commandHandlerPrompt - } - } + prompt: commandHandlerPrompt, + }, + }, }; - const sessCfgWithConnProps: extendedSession = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args, {doPrompting: true, propertyOverrides: overrides, parms: (parms as any)} - ); + const sessCfgWithConnProps: extendedSession = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args, + { + doPrompting: true, + propertyOverrides: overrides, + parms: parms as any, + } + ); expect(sessCfgWithConnProps.type).toBe(SessConstants.AUTH_TYPE_BASIC); expect(commandHandlerPrompt).toHaveBeenCalled(); // we are only testing that we call an already tested prompt method if in CLI mode expect((mockClientPrompt.mock.calls[0][1] as any).parms).toBe(parms); @@ -578,31 +706,36 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.certKey).toBeUndefined(); }); - it("not prompt when an override is specified and should prioritize the argument value", async() => { + it("not prompt when an override is specified and should prioritize the argument value", async () => { const passFromPrompt = "somePass"; const initialSessCfg: extendedSession = { hostname: "SomeHost", port: 11, user: "FakeUser", rejectUnauthorized: true, - someKey: "somekeyvalue" + someKey: "somekeyvalue", }; const args = { $0: "zowe", _: [""], - someKey: "someotherkeyvalue" - }; - const overrides: IOverridePromptConnProps[] = [{ - propertyName: "someKey", - propertiesOverridden: [ - "password", - "tokenType", - "tokenValue", - "cert", - "certKey" - ] - }]; - const mockClientPrompt = jest.spyOn(ConnectionPropsForSessCfg as any, "clientPrompt"); + someKey: "someotherkeyvalue", + }; + const overrides: IOverridePromptConnProps[] = [ + { + propertyName: "someKey", + propertiesOverridden: [ + "password", + "tokenType", + "tokenValue", + "cert", + "certKey", + ], + }, + ]; + const mockClientPrompt = jest.spyOn( + ConnectionPropsForSessCfg as any, + "clientPrompt" + ); // command handler prompt method (CLI versus SDK-based prompting) const commandHandlerPrompt = jest.fn(() => { return Promise.resolve(passFromPrompt); @@ -611,13 +744,20 @@ describe("ConnectionPropsForSessCfg tests", () => { const parms = { response: { console: { - prompt: commandHandlerPrompt - } - } + prompt: commandHandlerPrompt, + }, + }, }; - const sessCfgWithConnProps: extendedSession = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args, {doPrompting: true, propertyOverrides: overrides, parms: (parms as any)} - ); + const sessCfgWithConnProps: extendedSession = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args, + { + doPrompting: true, + propertyOverrides: overrides, + parms: parms as any, + } + ); expect(sessCfgWithConnProps.type).toBe(SessConstants.AUTH_TYPE_BASIC); expect(commandHandlerPrompt).not.toHaveBeenCalled(); // we are only testing that we call an already tested prompt method if in CLI mode expect(mockClientPrompt).not.toHaveBeenCalled(); @@ -630,21 +770,24 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.certKey).toBeUndefined(); }); - it("get user name from prompt from daemon client", async() => { + it("get user name from prompt from daemon client", async () => { const userFromPrompt = "FakeUser"; const passFromArgs = "FakePassword"; - const mockClientPrompt = jest.spyOn(ConnectionPropsForSessCfg as any, "clientPrompt"); + const mockClientPrompt = jest.spyOn( + ConnectionPropsForSessCfg as any, + "clientPrompt" + ); const initialSessCfg = { hostname: "SomeHost", port: 11, - rejectUnauthorized: true + rejectUnauthorized: true, }; const args = { $0: "zowe", _: [""], - password: passFromArgs + password: passFromArgs, }; // command handler prompt method (CLI versus SDK-based prompting) @@ -656,22 +799,25 @@ describe("ConnectionPropsForSessCfg tests", () => { const parms = { response: { console: { - prompt: commandHandlerPrompt - } - } + prompt: commandHandlerPrompt, + }, + }, }; - const sessCfgWithConnProps: ISession = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args, { - parms: parms as any // treat this as a CLI-based prompt - } - ); + const sessCfgWithConnProps: ISession = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args, + { + parms: parms as any, // treat this as a CLI-based prompt + } + ); expect(commandHandlerPrompt).toHaveBeenCalled(); // we are only testing that we call an already tested prompt method if in CLI mode - expect((mockClientPrompt.mock.calls[0][1] as any).parms).toBe(parms); // toBe is important here, parms object must be same as original + expect((mockClientPrompt.mock.calls[0][1] as any).parms).toBe(parms); // toBe is important here, parms object must be same as original }); - it("get user name from prompt", async() => { + it("get user name from prompt", async () => { const userFromPrompt = "FakeUser"; const passFromArgs = "FakePassword"; @@ -685,17 +831,19 @@ describe("ConnectionPropsForSessCfg tests", () => { const initialSessCfg = { hostname: "SomeHost", port: 11, - rejectUnauthorized: true + rejectUnauthorized: true, }; const args = { $0: "zowe", _: [""], - password: passFromArgs + password: passFromArgs, }; - const sessCfgWithConnProps: ISession = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args - ); + const sessCfgWithConnProps: ISession = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args + ); CliUtils.sleep = sleepReal; CliUtils.readPrompt = readPromptReal; @@ -708,7 +856,7 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.certKey).toBeUndefined(); }); - it("get password from prompt", async() => { + it("get password from prompt", async () => { const userFromArgs = "FakeUser"; const passFromPrompt = "FakePassword"; @@ -722,17 +870,19 @@ describe("ConnectionPropsForSessCfg tests", () => { const initialSessCfg = { hostname: "SomeHost", port: 11, - rejectUnauthorized: true + rejectUnauthorized: true, }; const args = { $0: "zowe", _: [""], - user: userFromArgs + user: userFromArgs, }; - const sessCfgWithConnProps: ISession = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args - ); + const sessCfgWithConnProps: ISession = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args + ); CliUtils.sleep = sleepReal; CliUtils.readPrompt = readPromptReal; @@ -745,7 +895,7 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.certKey).toBeUndefined(); }); - it("get host name from prompt", async() => { + it("get host name from prompt", async () => { const hostFromPrompt = "FakeHost"; const portFromArgs = 11; const userFromArgs = "FakeUser"; @@ -766,12 +916,14 @@ describe("ConnectionPropsForSessCfg tests", () => { _: [""], port: portFromArgs, user: userFromArgs, - password: passFromArgs + password: passFromArgs, }; - const sessCfgWithConnProps: ISession = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args - ); + const sessCfgWithConnProps: ISession = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args + ); CliUtils.sleep = sleepReal; CliUtils.readPrompt = readPromptReal; @@ -785,7 +937,7 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.certKey).toBeUndefined(); }); - it("get port from prompt - string", async() => { + it("get port from prompt - string", async () => { const hostFromArgs = "FakeHost"; const portFromPrompt = "11"; const userFromArgs = "FakeUser"; @@ -799,19 +951,21 @@ describe("ConnectionPropsForSessCfg tests", () => { }); const initialSessCfg = { - rejectUnauthorized: true + rejectUnauthorized: true, }; const args = { $0: "zowe", _: [""], host: hostFromArgs, user: userFromArgs, - password: passFromArgs + password: passFromArgs, }; - const sessCfgWithConnProps: ISession = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args - ); + const sessCfgWithConnProps: ISession = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args + ); CliUtils.sleep = sleepReal; CliUtils.readPrompt = readPromptReal; @@ -824,7 +978,7 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.tokenValue).toBeUndefined(); }); - it("get port from prompt - number", async() => { + it("get port from prompt - number", async () => { const hostFromArgs = "FakeHost"; const portFromPrompt = 11; const userFromArgs = "FakeUser"; @@ -836,24 +990,29 @@ describe("ConnectionPropsForSessCfg tests", () => { CliUtils.readPrompt = jest.fn(() => { return Promise.resolve(portFromPrompt.toString()); }); - jest.spyOn(ConnectionPropsForSessCfg as any, "loadSchemaForSessCfgProps").mockReturnValueOnce({ - port: { type: "number" } + jest.spyOn( + ConnectionPropsForSessCfg as any, + "loadSchemaForSessCfgProps" + ).mockReturnValueOnce({ + port: { type: "number" }, }); const initialSessCfg = { - rejectUnauthorized: true + rejectUnauthorized: true, }; const args = { $0: "zowe", _: [""], host: hostFromArgs, user: userFromArgs, - password: passFromArgs + password: passFromArgs, }; - const sessCfgWithConnProps: ISession = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args - ); + const sessCfgWithConnProps: ISession = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args + ); CliUtils.sleep = sleepReal; CliUtils.readPrompt = readPromptReal; @@ -866,7 +1025,7 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.tokenValue).toBeUndefined(); }); - it("get port from prompt - zero", async() => { + it("get port from prompt - zero", async () => { const hostFromArgs = "FakeHost"; const portFromArgs = 0; const portFromPrompt = 11; @@ -879,12 +1038,15 @@ describe("ConnectionPropsForSessCfg tests", () => { CliUtils.readPrompt = jest.fn(() => { return Promise.resolve(portFromPrompt.toString()); }); - jest.spyOn(ConnectionPropsForSessCfg as any, "loadSchemaForSessCfgProps").mockReturnValueOnce({ - port: { type: "number" } + jest.spyOn( + ConnectionPropsForSessCfg as any, + "loadSchemaForSessCfgProps" + ).mockReturnValueOnce({ + port: { type: "number" }, }); const initialSessCfg = { - rejectUnauthorized: true + rejectUnauthorized: true, }; const args = { $0: "zowe", @@ -892,12 +1054,14 @@ describe("ConnectionPropsForSessCfg tests", () => { host: hostFromArgs, port: portFromArgs, user: userFromArgs, - password: passFromArgs + password: passFromArgs, }; - const sessCfgWithConnProps: ISession = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args - ); + const sessCfgWithConnProps: ISession = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args + ); CliUtils.sleep = sleepReal; CliUtils.readPrompt = readPromptReal; @@ -910,7 +1074,7 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.tokenValue).toBeUndefined(); }); - it("get host name from prompt with custom service description", async() => { + it("get host name from prompt with custom service description", async () => { const hostFromPrompt = "FakeHost"; const portFromArgs = 11; const userFromArgs = "FakeUser"; @@ -933,12 +1097,15 @@ describe("ConnectionPropsForSessCfg tests", () => { _: [""], port: portFromArgs, user: userFromArgs, - password: passFromArgs + password: passFromArgs, }; - const sessCfgWithConnProps: ISession = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args, { serviceDescription: "my cool service" } - ); + const sessCfgWithConnProps: ISession = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args, + { serviceDescription: "my cool service" } + ); CliUtils.sleep = sleepReal; CliUtils.readPrompt = readPromptReal; @@ -951,7 +1118,7 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.tokenValue).toBeUndefined(); }); - it("get port from prompt with custom service description", async() => { + it("get port from prompt with custom service description", async () => { const hostFromArgs = "FakeHost"; const portFromPrompt = 11; const userFromArgs = "FakeUser"; @@ -965,24 +1132,30 @@ describe("ConnectionPropsForSessCfg tests", () => { questionText = text; return Promise.resolve(portFromPrompt.toString()); }); - jest.spyOn(ConnectionPropsForSessCfg as any, "loadSchemaForSessCfgProps").mockReturnValueOnce({ - port: { type: "number" } + jest.spyOn( + ConnectionPropsForSessCfg as any, + "loadSchemaForSessCfgProps" + ).mockReturnValueOnce({ + port: { type: "number" }, }); const initialSessCfg = { - rejectUnauthorized: true + rejectUnauthorized: true, }; const args = { $0: "zowe", _: [""], host: hostFromArgs, user: userFromArgs, - password: passFromArgs + password: passFromArgs, }; - const sessCfgWithConnProps: ISession = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args, { serviceDescription: "my cool service" } - ); + const sessCfgWithConnProps: ISession = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args, + { serviceDescription: "my cool service" } + ); CliUtils.sleep = sleepReal; CliUtils.readPrompt = readPromptReal; @@ -998,7 +1171,7 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.certKey).toBeUndefined(); }); - it("get host name from prompt with hidden text - service profile", async() => { + it("get host name from prompt with hidden text - service profile", async () => { const hostFromPrompt = "FakeHost"; const portFromArgs = 11; const userFromArgs = "FakeUser"; @@ -1014,7 +1187,7 @@ describe("ConnectionPropsForSessCfg tests", () => { _: [""], port: portFromArgs, user: userFromArgs, - password: passFromArgs + password: passFromArgs, }; // command handler prompt method (CLI versus SDK-based prompting) @@ -1029,28 +1202,34 @@ describe("ConnectionPropsForSessCfg tests", () => { arguments: {}, response: { console: { - prompt: commandHandlerPrompt - } - } + prompt: commandHandlerPrompt, + }, + }, }; - jest.spyOn(ConfigAutoStore, "findActiveProfile").mockReturnValueOnce(["fruit", "mango"]); + jest.spyOn(ConfigAutoStore, "findActiveProfile").mockReturnValueOnce([ + "fruit", + "mango", + ]); await setupConfigToLoad({ profiles: { mango: { type: "fruit", properties: {}, - secure: ["host"] - } + secure: ["host"], + }, }, - defaults: { fruit: "mango" } + defaults: { fruit: "mango" }, }); - const sessCfgWithConnProps: ISession = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args, { - parms: parms as any // treat this as a CLI-based prompt - } - ); + const sessCfgWithConnProps: ISession = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args, + { + parms: parms as any, // treat this as a CLI-based prompt + } + ); expect(questionText).toContain("(will be hidden)"); expect(promptOpts.hideText).toBe(true); @@ -1062,7 +1241,7 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.tokenValue).toBeUndefined(); }); - it("get host name from prompt with hidden text - base profile", async() => { + it("get host name from prompt with hidden text - base profile", async () => { const hostFromPrompt = "FakeHost"; const portFromArgs = 11; const userFromArgs = "FakeUser"; @@ -1078,7 +1257,7 @@ describe("ConnectionPropsForSessCfg tests", () => { _: [""], port: portFromArgs, user: userFromArgs, - password: passFromArgs + password: passFromArgs, }; // command handler prompt method (CLI versus SDK-based prompting) @@ -1093,32 +1272,38 @@ describe("ConnectionPropsForSessCfg tests", () => { arguments: {}, response: { console: { - prompt: commandHandlerPrompt - } - } + prompt: commandHandlerPrompt, + }, + }, }; - jest.spyOn(ConfigAutoStore, "findActiveProfile").mockReturnValueOnce(["fruit", "mango"]); + jest.spyOn(ConfigAutoStore, "findActiveProfile").mockReturnValueOnce([ + "fruit", + "mango", + ]); await setupConfigToLoad({ profiles: { mango: { type: "fruit", - properties: {} + properties: {}, }, fruit: { type: "base", properties: {}, - secure: ["host"] - } + secure: ["host"], + }, }, - defaults: { fruit: "mango", base: "fruit" } + defaults: { fruit: "mango", base: "fruit" }, }); - const sessCfgWithConnProps: ISession = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args, { - parms: parms as any // treat this as a CLI-based prompt - } - ); + const sessCfgWithConnProps: ISession = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args, + { + parms: parms as any, // treat this as a CLI-based prompt + } + ); expect(questionText).toContain("(will be hidden)"); expect(promptOpts.hideText).toBe(true); @@ -1130,7 +1315,7 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.tokenValue).toBeUndefined(); }); - it("throws an error if user doesn't enter port as a number", async() => { + it("throws an error if user doesn't enter port as a number", async () => { const hostFromArgs = "FakeHost"; const portFromPrompt = "abcd"; const userFromArgs = "FakeUser"; @@ -1142,24 +1327,30 @@ describe("ConnectionPropsForSessCfg tests", () => { CliUtils.readPrompt = jest.fn(() => { return Promise.resolve(portFromPrompt); }); - jest.spyOn(ConnectionPropsForSessCfg as any, "loadSchemaForSessCfgProps").mockReturnValueOnce({ - port: { type: "number" } + jest.spyOn( + ConnectionPropsForSessCfg as any, + "loadSchemaForSessCfgProps" + ).mockReturnValueOnce({ + port: { type: "number" }, }); const initialSessCfg = { - rejectUnauthorized: true + rejectUnauthorized: true, }; const args = { $0: "zowe", _: [""], host: hostFromArgs, user: userFromArgs, - password: passFromArgs + password: passFromArgs, }; let theError; try { - await ConnectionPropsForSessCfg.addPropsOrPrompt(initialSessCfg, args); + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args + ); } catch (err) { theError = err; } @@ -1169,7 +1360,7 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(theError.message).toBe("Specified port was not a number."); }); - it("timeout waiting for user name", async() => { + it("timeout waiting for user name", async () => { const sleepReal = CliUtils.sleep; CliUtils.sleep = jest.fn(); const readPromptReal = CliUtils.readPrompt; @@ -1178,20 +1369,22 @@ describe("ConnectionPropsForSessCfg tests", () => { const initialSessCfg = { hostname: "SomeHost", port: 11, - rejectUnauthorized: true + rejectUnauthorized: true, }; const args = { $0: "zowe", _: [""], - password: "FakePassword" + password: "FakePassword", }; let sessCfgWithConnProps: ISession; let caughtError; try { - sessCfgWithConnProps = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args - ); + sessCfgWithConnProps = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args + ); } catch (thrownError) { caughtError = thrownError; } @@ -1201,7 +1394,7 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(caughtError.message).toBe("Timed out waiting for user."); }); - it("timeout waiting for password", async() => { + it("timeout waiting for password", async () => { const sleepReal = CliUtils.sleep; CliUtils.sleep = jest.fn(); const readPromptReal = CliUtils.readPrompt; @@ -1210,20 +1403,22 @@ describe("ConnectionPropsForSessCfg tests", () => { const initialSessCfg = { hostname: "SomeHost", port: 11, - rejectUnauthorized: true + rejectUnauthorized: true, }; const args = { $0: "zowe", _: [""], - user: "FakeUser" + user: "FakeUser", }; let sessCfgWithConnProps: ISession; let caughtError; try { - sessCfgWithConnProps = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args - ); + sessCfgWithConnProps = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args + ); } catch (thrownError) { caughtError = thrownError; } @@ -1233,7 +1428,7 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(caughtError.message).toBe("Timed out waiting for password."); }); - it("timeout waiting for host name", async() => { + it("timeout waiting for host name", async () => { const sleepReal = CliUtils.sleep; CliUtils.sleep = jest.fn(); const readPromptReal = CliUtils.readPrompt; @@ -1247,15 +1442,17 @@ describe("ConnectionPropsForSessCfg tests", () => { _: [""], port: 11, user: "FakeUser", - password: "FakePassword" + password: "FakePassword", }; let sessCfgWithConnProps: ISession; let caughtError; try { - sessCfgWithConnProps = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args - ); + sessCfgWithConnProps = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args + ); } catch (thrownError) { caughtError = thrownError; } @@ -1265,7 +1462,7 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(caughtError.message).toBe("Timed out waiting for hostname."); }); - it("timeout waiting for port number", async() => { + it("timeout waiting for port number", async () => { const sleepReal = CliUtils.sleep; CliUtils.sleep = jest.fn(); const readPromptReal = CliUtils.readPrompt; @@ -1279,15 +1476,17 @@ describe("ConnectionPropsForSessCfg tests", () => { _: [""], host: "SomeHost", user: "FakeUser", - password: "FakePassword" + password: "FakePassword", }; let sessCfgWithConnProps: ISession; let caughtError; try { - sessCfgWithConnProps = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args - ); + sessCfgWithConnProps = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args + ); } catch (thrownError) { caughtError = thrownError; } @@ -1299,7 +1498,8 @@ describe("ConnectionPropsForSessCfg tests", () => { it("should not log secure properties of session config", async () => { const mockLoggerDebug = jest.fn(); - const getImperativeLoggerSpy = jest.spyOn(Logger, "getImperativeLogger") + const getImperativeLoggerSpy = jest + .spyOn(Logger, "getImperativeLogger") .mockReturnValueOnce({ debug: mockLoggerDebug } as any); (ConnectionPropsForSessCfg as any).logSessCfg({ host: "SomeHost", @@ -1307,7 +1507,7 @@ describe("ConnectionPropsForSessCfg tests", () => { user: "FakeUser", password: "FakePassword", tokenType: SessConstants.TOKEN_TYPE_JWT, - tokenValue: "FakeToken" + tokenValue: "FakeToken", }); getImperativeLoggerSpy.mockRestore(); expect(mockLoggerDebug).toHaveBeenCalledTimes(1); @@ -1318,7 +1518,7 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(logOutput).not.toContain("FakeToken"); }); - it("SSO CallBack with getValuesBack", async() => { + it("SSO CallBack with getValuesBack", async () => { const initialSessCfg = { rejectUnauthorized: true, }; @@ -1327,28 +1527,28 @@ describe("ConnectionPropsForSessCfg tests", () => { port: 11, user: "FakeUser", password: "FakePassword", - rejectUnauthorized: false + rejectUnauthorized: false, }; const args = { $0: "zowe", - _: [""] + _: [""], }; const fakeFunction = jest.fn((neededProps) => { for (const value of neededProps) { switch (value) { - case "hostname" : + case "hostname": neededProps[value] = fakeFunctionSessCfg.hostname; break; - case "port" : + case "port": neededProps[value] = fakeFunctionSessCfg.port; break; - case "user" : + case "user": neededProps[value] = fakeFunctionSessCfg.user; break; - case "password" : + case "password": neededProps[value] = fakeFunctionSessCfg.password; break; - case "rejectUnauthorized" : + case "rejectUnauthorized": neededProps[value] = initialSessCfg.rejectUnauthorized; break; default: @@ -1357,9 +1557,12 @@ describe("ConnectionPropsForSessCfg tests", () => { } return neededProps; }); - const sessCfgWithConnProps = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args, {getValuesBack: fakeFunction} - ); + const sessCfgWithConnProps = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args, + { getValuesBack: fakeFunction } + ); expect(sessCfgWithConnProps.hostname).toBe("SomeHost"); expect(sessCfgWithConnProps.port).toBe(11); expect(sessCfgWithConnProps.user).toBe("FakeUser"); @@ -1371,7 +1574,7 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.certKey).toBeUndefined(); }); - it("SSO CallBack with getValuesBack and partial session config", async() => { + it("SSO CallBack with getValuesBack and partial session config", async () => { const initialSessCfg = { password: "FakePassword", rejectUnauthorized: true, @@ -1388,19 +1591,19 @@ describe("ConnectionPropsForSessCfg tests", () => { const fakeFunction = jest.fn((neededProps) => { for (const value of neededProps) { switch (value) { - case "hostname" : + case "hostname": neededProps[value] = fakeFunctionSessCfg.hostname; break; - case "port" : + case "port": neededProps[value] = fakeFunctionSessCfg.port; break; - case "user" : + case "user": neededProps[value] = args.user; break; - case "password" : + case "password": neededProps[value] = initialSessCfg.password; break; - case "rejectUnauthorized" : + case "rejectUnauthorized": neededProps[value] = initialSessCfg.rejectUnauthorized; break; default: @@ -1409,9 +1612,12 @@ describe("ConnectionPropsForSessCfg tests", () => { } return neededProps; }); - const sessCfgWithConnProps = await ConnectionPropsForSessCfg.addPropsOrPrompt( - initialSessCfg, args, {getValuesBack: fakeFunction} - ); + const sessCfgWithConnProps = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args, + { getValuesBack: fakeFunction } + ); expect(sessCfgWithConnProps.hostname).toBe("SomeHost"); expect(sessCfgWithConnProps.port).toBe(11); expect(sessCfgWithConnProps.user).toBe("FakeUser"); @@ -1422,20 +1628,83 @@ describe("ConnectionPropsForSessCfg tests", () => { expect(sessCfgWithConnProps.cert).toBeUndefined(); expect(sessCfgWithConnProps.certKey).toBeUndefined(); }); + it("should set default values for elements of propsToPromptFor()", async () => { + jest.spyOn(ConfigAutoStore, "findActiveProfile").mockReturnValueOnce([ + "fruit", + "mango", + ]); + await setupConfigToLoad({ + profiles: { + mango: { + type: "fruit", + properties: {}, + secure: ["host"], + }, + }, + defaults: { fruit: "mango" }, + }); + const overrides: IOverridePromptConnProps[] = [ + { + propertyName: "someKey", + argumentName: "someKeyOther", + propertiesOverridden: [ + "password", + "tokenType", + "tokenValue", + "cert", + "certKey", + ], + }, + ]; + const passFromPrompt = "somePass"; + const initialSessCfg: extendedSession = { + hostname: "SomeHost", + port: 20, + user: "FakeUser", + rejectUnauthorized: true, + }; + const args = { + $0: "zowe", + _: [""], + someKey: "somekeyvalue", + }; + const commandHandlerPrompt = jest.fn(() => { + return Promise.resolve(passFromPrompt); + }); + const parms = { + response: { + console: { + prompt: commandHandlerPrompt, + }, + }, + }; + const sessCfgWithConnProps: extendedSession = + await ConnectionPropsForSessCfg.addPropsOrPrompt( + initialSessCfg, + args, + { + doPrompting: true, + propertyOverrides: overrides, + propsToPromptFor: [{name: "keyPassphrase",isGivenValueValid: string => true}], + parms: parms as any, + } + ); + expect(ConnectionPropsForSessCfg.secureSessCfgProps).toContain("keyPassphrase"); + }); describe("getValuesBack private function", () => { // pretend that console.log works, but put data into a variable let consoleMsgs = ""; - const connOpts:IOptionsForAddConnProps = { + const connOpts: IOptionsForAddConnProps = { parms: { response: { console: { log: jest.fn((logArgs) => { consoleMsgs += "\n" + logArgs; - }) - } - } - } + }), + }, + }, + }, } as any; let getValuesCallBack: any; @@ -1443,12 +1712,13 @@ describe("ConnectionPropsForSessCfg tests", () => { beforeEach(() => { // establish a callback function with our fake console.log - getValuesCallBack = ConnectionPropsForSessCfg["getValuesBack"](connOpts); + getValuesCallBack = + ConnectionPropsForSessCfg["getValuesBack"](connOpts); // pretend that clientPrompt returns an answer - clientPromptSpy = jest.spyOn(ConnectionPropsForSessCfg as any, "clientPrompt").mockResolvedValue( - Promise.resolve("Some fake answer") - ); + clientPromptSpy = jest + .spyOn(ConnectionPropsForSessCfg as any, "clientPrompt") + .mockResolvedValue(Promise.resolve("Some fake answer")); // clear log messages from last test consoleMsgs = ""; }); @@ -1464,17 +1734,23 @@ describe("ConnectionPropsForSessCfg tests", () => { configurable: true, get: jest.fn(() => { return { - exists: false + exists: false, }; - }) + }), }); // call the function that we want to test await getValuesCallBack(["hostname"]); - expect(consoleMsgs).toContain("No Zowe client configuration exists."); - expect(consoleMsgs).toContain("Therefore, you will be asked for the"); - expect(consoleMsgs).toContain("connection properties that are required to complete your command."); + expect(consoleMsgs).toContain( + "No Zowe client configuration exists." + ); + expect(consoleMsgs).toContain( + "Therefore, you will be asked for the" + ); + expect(consoleMsgs).toContain( + "connection properties that are required to complete your command." + ); }); it("should state that V1 profiles are not supported", async () => { @@ -1483,9 +1759,9 @@ describe("ConnectionPropsForSessCfg tests", () => { configurable: true, get: jest.fn(() => { return { - exists: false + exists: false, }; - }) + }), }); /* Pretend that we only have V1 profiles. @@ -1495,15 +1771,21 @@ describe("ConnectionPropsForSessCfg tests", () => { configurable: true, get: jest.fn(() => { return true; - }) + }), }); // call the function that we want to test await getValuesCallBack(["hostname"]); - expect(consoleMsgs).toContain("Only V1 profiles exist. V1 profiles are no longer supported. You should convert"); - expect(consoleMsgs).toContain("your V1 profiles to a newer Zowe client configuration. Therefore, you will be"); - expect(consoleMsgs).toContain("asked for the connection properties that are required to complete your command."); + expect(consoleMsgs).toContain( + "Only V1 profiles exist. V1 profiles are no longer supported. You should convert" + ); + expect(consoleMsgs).toContain( + "your V1 profiles to a newer Zowe client configuration. Therefore, you will be" + ); + expect(consoleMsgs).toContain( + "asked for the connection properties that are required to complete your command." + ); }); it("should state that connection properties are missing from config", async () => { @@ -1512,9 +1794,9 @@ describe("ConnectionPropsForSessCfg tests", () => { configurable: true, get: jest.fn(() => { return { - exists: true + exists: true, }; - }) + }), }); /* Pretend that we do not have any V1 profiles. @@ -1524,15 +1806,21 @@ describe("ConnectionPropsForSessCfg tests", () => { configurable: true, get: jest.fn(() => { return false; - }) + }), }); // call the function that we want to test await getValuesCallBack(["hostname"]); - expect(consoleMsgs).toContain("Some required connection properties have not been specified in your Zowe client"); - expect(consoleMsgs).toContain("configuration. Therefore, you will be asked for the connection properties that"); - expect(consoleMsgs).toContain("are required to complete your command."); + expect(consoleMsgs).toContain( + "Some required connection properties have not been specified in your Zowe client" + ); + expect(consoleMsgs).toContain( + "configuration. Therefore, you will be asked for the connection properties that" + ); + expect(consoleMsgs).toContain( + "are required to complete your command." + ); }); }); }); diff --git a/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts b/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts index b0410e57be..7f6637e127 100644 --- a/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts +++ b/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts @@ -360,7 +360,7 @@ export class ConnectionPropsForSessCfg { * NOTE(Kelosky): redundant from LoggerUtils.SECURE_PROMPT_OPTIONS - leaving * for future date to consolidate */ - private static secureSessCfgProps: Set = new Set(["user", "password", "tokenValue", "passphrase"]); + public static secureSessCfgProps: Set = new Set(["user", "password", "tokenValue", "passphrase"]); /** * List of prompt messages that is used when the CLI prompts for session diff --git a/packages/zosuss/__tests__/__unit__/SshBaseHandler.unit.test.ts b/packages/zosuss/__tests__/__unit__/SshBaseHandler.unit.test.ts index 5e9365250a..216929eb37 100644 --- a/packages/zosuss/__tests__/__unit__/SshBaseHandler.unit.test.ts +++ b/packages/zosuss/__tests__/__unit__/SshBaseHandler.unit.test.ts @@ -228,4 +228,15 @@ describe("issue ssh handler tests", () => { expect(Shell.executeSsh).toHaveBeenCalledTimes(1); expect(testOutput).toMatchSnapshot(); }); + it("should be able to get stdout with privateKey", async () => { + Shell.executeSsh = jest.fn(async (session, command, stdoutHandler) => { + stdoutHandler(testOutput); + }); + const handler = new myHandler(); + const params = Object.assign({}, ...[DEFAULT_PARAMETERS_PRIVATE_KEY]); + params.arguments.command = "pwd"; + await handler.process(params); + expect(Shell.executeSsh).toHaveBeenCalledTimes(1); + expect(testOutput).toMatchSnapshot(); + }); }); diff --git a/packages/zosuss/__tests__/__unit__/__snapshots__/SshBaseHandler.unit.test.ts.snap b/packages/zosuss/__tests__/__unit__/__snapshots__/SshBaseHandler.unit.test.ts.snap index 45544acebb..7dbc37d7af 100644 --- a/packages/zosuss/__tests__/__unit__/__snapshots__/SshBaseHandler.unit.test.ts.snap +++ b/packages/zosuss/__tests__/__unit__/__snapshots__/SshBaseHandler.unit.test.ts.snap @@ -8,6 +8,8 @@ exports[`issue ssh handler tests should be able to get stdout with private key a exports[`issue ssh handler tests should be able to get stdout with privateKey 1`] = `"TEST OUTPUT"`; +exports[`issue ssh handler tests should be able to get stdout with privateKey 2`] = `"TEST OUTPUT"`; + exports[`issue ssh handler tests should fail if user fails to enter incorrect key passphrase in 3 attempts 1`] = `"Maximum retry attempts reached. Authentication failed."`; exports[`issue ssh handler tests should prompt for user and keyPassphrase if neither is stored 1`] = `"test"`; From 217e5ac2f389528c0c845fa4aea8c55149122998 Mon Sep 17 00:00:00 2001 From: jace-roell Date: Tue, 6 Aug 2024 09:24:42 -0400 Subject: [PATCH 15/24] propsToPromptFor() description Signed-off-by: jace-roell --- .../src/rest/src/session/doc/IOptionsForAddConnProps.ts | 6 +++--- .../src/rest/src/session/doc/IOverridePromptConnProps.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts b/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts index 2ccedb1641..32f6b92670 100644 --- a/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts +++ b/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts @@ -52,9 +52,9 @@ export interface IOptionsForAddConnProps */ propertyOverrides?: IOverridePromptConnProps[]; - /** - * Allows for passing for additional properties to prompt for. - * Utilized in the case of a incorrect/not stored key passphrase. s + /** + * Allows passing additional properties for which to prompt. + * Used in cases of an incorrect or missing key passphrase. */ propsToPromptFor?: { diff --git a/packages/imperative/src/rest/src/session/doc/IOverridePromptConnProps.ts b/packages/imperative/src/rest/src/session/doc/IOverridePromptConnProps.ts index 08dc392cab..868ba5e32b 100644 --- a/packages/imperative/src/rest/src/session/doc/IOverridePromptConnProps.ts +++ b/packages/imperative/src/rest/src/session/doc/IOverridePromptConnProps.ts @@ -37,8 +37,8 @@ export interface IOverridePromptConnProps propertiesOverridden: (keyof SessCfgType & string)[]; /** - * Allows for passing for additional properties to prompt for. - * Utilized in the case of a incorrect/not stored key passphrase. + * Allows passing additional properties for which to prompt. + * Used in cases of an incorrect or missing key passphrase. */ propsToPromptFor?: (keyof SessCfgType & string)[]; } \ No newline at end of file From 563788f2ad946a2b6ec90917d53533fca4a2f16b Mon Sep 17 00:00:00 2001 From: jace-roell Date: Tue, 6 Aug 2024 09:29:43 -0400 Subject: [PATCH 16/24] fixed linting errors Signed-off-by: jace-roell --- .../ConnectionPropsForSessCfg.unit.test.ts | 20 +++++++++---------- .../__unit__/SshBaseHandler.unit.test.ts | 11 ---------- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/packages/imperative/src/rest/__tests__/session/ConnectionPropsForSessCfg.unit.test.ts b/packages/imperative/src/rest/__tests__/session/ConnectionPropsForSessCfg.unit.test.ts index 4b719643f9..b3aa49c921 100644 --- a/packages/imperative/src/rest/__tests__/session/ConnectionPropsForSessCfg.unit.test.ts +++ b/packages/imperative/src/rest/__tests__/session/ConnectionPropsForSessCfg.unit.test.ts @@ -1,13 +1,13 @@ /* - * This program and the accompanying materials are made available under the terms of the - * Eclipse Public License v2.0 which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Copyright Contributors to the Zowe Project. - * - */ +* This program and the accompanying materials are made available under the terms of the +* Eclipse Public License v2.0 which accompanies this distribution, and is available at +* https://www.eclipse.org/legal/epl-v20.html +* +* SPDX-License-Identifier: EPL-2.0 +* +* Copyright Contributors to the Zowe Project. +* +*/ jest.mock("../../../logger/src/LoggerUtils"); @@ -1679,7 +1679,7 @@ describe("ConnectionPropsForSessCfg tests", () => { }, }, }; - const sessCfgWithConnProps: extendedSession = + const sessCfgWithConnProps: ISshSession = await ConnectionPropsForSessCfg.addPropsOrPrompt( initialSessCfg, args, diff --git a/packages/zosuss/__tests__/__unit__/SshBaseHandler.unit.test.ts b/packages/zosuss/__tests__/__unit__/SshBaseHandler.unit.test.ts index 216929eb37..5e9365250a 100644 --- a/packages/zosuss/__tests__/__unit__/SshBaseHandler.unit.test.ts +++ b/packages/zosuss/__tests__/__unit__/SshBaseHandler.unit.test.ts @@ -228,15 +228,4 @@ describe("issue ssh handler tests", () => { expect(Shell.executeSsh).toHaveBeenCalledTimes(1); expect(testOutput).toMatchSnapshot(); }); - it("should be able to get stdout with privateKey", async () => { - Shell.executeSsh = jest.fn(async (session, command, stdoutHandler) => { - stdoutHandler(testOutput); - }); - const handler = new myHandler(); - const params = Object.assign({}, ...[DEFAULT_PARAMETERS_PRIVATE_KEY]); - params.arguments.command = "pwd"; - await handler.process(params); - expect(Shell.executeSsh).toHaveBeenCalledTimes(1); - expect(testOutput).toMatchSnapshot(); - }); }); From e9c094163b7ba6f39bfbc4daea38c84f1c1071e7 Mon Sep 17 00:00:00 2001 From: jace-roell Date: Tue, 6 Aug 2024 09:44:06 -0400 Subject: [PATCH 17/24] remove snapshot Signed-off-by: jace-roell --- .../__unit__/__snapshots__/SshBaseHandler.unit.test.ts.snap | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/zosuss/__tests__/__unit__/__snapshots__/SshBaseHandler.unit.test.ts.snap b/packages/zosuss/__tests__/__unit__/__snapshots__/SshBaseHandler.unit.test.ts.snap index 7dbc37d7af..45544acebb 100644 --- a/packages/zosuss/__tests__/__unit__/__snapshots__/SshBaseHandler.unit.test.ts.snap +++ b/packages/zosuss/__tests__/__unit__/__snapshots__/SshBaseHandler.unit.test.ts.snap @@ -8,8 +8,6 @@ exports[`issue ssh handler tests should be able to get stdout with private key a exports[`issue ssh handler tests should be able to get stdout with privateKey 1`] = `"TEST OUTPUT"`; -exports[`issue ssh handler tests should be able to get stdout with privateKey 2`] = `"TEST OUTPUT"`; - exports[`issue ssh handler tests should fail if user fails to enter incorrect key passphrase in 3 attempts 1`] = `"Maximum retry attempts reached. Authentication failed."`; exports[`issue ssh handler tests should prompt for user and keyPassphrase if neither is stored 1`] = `"test"`; From 89f2533db392c223c0bfc137f84a61434cfc1512 Mon Sep 17 00:00:00 2001 From: jace-roell Date: Tue, 6 Aug 2024 09:54:28 -0400 Subject: [PATCH 18/24] secureSessCfgProps back to private Signed-off-by: jace-roell --- .../__tests__/session/ConnectionPropsForSessCfg.unit.test.ts | 2 +- .../src/rest/src/session/ConnectionPropsForSessCfg.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/imperative/src/rest/__tests__/session/ConnectionPropsForSessCfg.unit.test.ts b/packages/imperative/src/rest/__tests__/session/ConnectionPropsForSessCfg.unit.test.ts index b3aa49c921..8ab50f1537 100644 --- a/packages/imperative/src/rest/__tests__/session/ConnectionPropsForSessCfg.unit.test.ts +++ b/packages/imperative/src/rest/__tests__/session/ConnectionPropsForSessCfg.unit.test.ts @@ -1690,7 +1690,7 @@ describe("ConnectionPropsForSessCfg tests", () => { parms: parms as any, } ); - expect(ConnectionPropsForSessCfg.secureSessCfgProps).toContain("keyPassphrase"); + expect((ConnectionPropsForSessCfg as any).secureSessCfgProps).toContain("keyPassphrase"); }); describe("getValuesBack private function", () => { // pretend that console.log works, but put data into a variable diff --git a/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts b/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts index 7f6637e127..b0410e57be 100644 --- a/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts +++ b/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts @@ -360,7 +360,7 @@ export class ConnectionPropsForSessCfg { * NOTE(Kelosky): redundant from LoggerUtils.SECURE_PROMPT_OPTIONS - leaving * for future date to consolidate */ - public static secureSessCfgProps: Set = new Set(["user", "password", "tokenValue", "passphrase"]); + private static secureSessCfgProps: Set = new Set(["user", "password", "tokenValue", "passphrase"]); /** * List of prompt messages that is used when the CLI prompts for session From 5c0fdfd44a98e6766d1905214dcd5f4e62d52ac2 Mon Sep 17 00:00:00 2001 From: jace-roell Date: Wed, 7 Aug 2024 09:07:15 -0400 Subject: [PATCH 19/24] implemented IPropsToPromptFor.ts and fixed typing for setTypeForTokenRequest Signed-off-by: jace-roell --- .../src/rest/src/session/ConnectionPropsForSessCfg.ts | 8 ++++---- .../rest/src/session/doc/IOptionsForAddConnProps.ts | 10 ++-------- .../src/rest/src/session/doc/IPropsToPromptFor.ts | 8 ++++++++ 3 files changed, 14 insertions(+), 12 deletions(-) create mode 100644 packages/imperative/src/rest/src/session/doc/IPropsToPromptFor.ts diff --git a/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts b/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts index b0410e57be..d690a7c7af 100644 --- a/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts +++ b/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts @@ -329,7 +329,7 @@ export class ConnectionPropsForSessCfg { impLogger.debug("Using basic authentication"); sessCfg.type = SessConstants.AUTH_TYPE_BASIC; } - ConnectionPropsForSessCfg.setTypeForTokenRequest(sessCfg, connOpts as any, cmdArgs.tokenType); + ConnectionPropsForSessCfg.setTypeForTokenRequest(sessCfg, connOpts, cmdArgs.tokenType); ConnectionPropsForSessCfg.logSessCfg(sessCfg); } @@ -468,9 +468,9 @@ export class ConnectionPropsForSessCfg { * @param tokenType * The type of token that we expect to receive. */ - private static setTypeForTokenRequest( - sessCfg: any, - options: IOptionsForAddConnProps, + private static setTypeForTokenRequest( + sessCfg: SessCfgType, + options: IOptionsForAddConnProps, tokenType: SessConstants.TOKEN_TYPE_CHOICES ) { const impLogger = Logger.getImperativeLogger(); diff --git a/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts b/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts index 32f6b92670..5cece9c5d3 100644 --- a/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts +++ b/packages/imperative/src/rest/src/session/doc/IOptionsForAddConnProps.ts @@ -13,7 +13,7 @@ import { ISession, SessConstants } from "../../.."; import { IHandlerParameters } from "../../../../cmd"; import { AUTH_TYPE_CHOICES } from "../SessConstants"; import { IOverridePromptConnProps } from "./IOverridePromptConnProps"; - +import { IPropsToPromptFor } from "../doc/IPropsToPromptFor"; /** * Interface for options supplied to ConnectionPropsForSessCfg.addPropsOrPrompt() * @export @@ -56,13 +56,7 @@ export interface IOptionsForAddConnProps * Allows passing additional properties for which to prompt. * Used in cases of an incorrect or missing key passphrase. */ - propsToPromptFor?: - { - name: keyof SessCfgType & string, - secure?: boolean, - description?: string, - isGivenValueValid?: (givenValue: string) => boolean - }[]; + propsToPromptFor?: IPropsToPromptFor[]; /** * Specifies the functionality that external applications will use for prompting. diff --git a/packages/imperative/src/rest/src/session/doc/IPropsToPromptFor.ts b/packages/imperative/src/rest/src/session/doc/IPropsToPromptFor.ts new file mode 100644 index 0000000000..bbc3c9dcd0 --- /dev/null +++ b/packages/imperative/src/rest/src/session/doc/IPropsToPromptFor.ts @@ -0,0 +1,8 @@ +import { ISession } from "../../.."; + +export interface IPropsToPromptFor { + name: keyof SessCfgType & string, + secure?: boolean, + description?: string, + isGivenValueValid?: (givenValue: string) => boolean +} \ No newline at end of file From feac0a8089eb5b43f6f4ef285dc54cc6f36f3895 Mon Sep 17 00:00:00 2001 From: jace-roell Date: Wed, 7 Aug 2024 09:46:28 -0400 Subject: [PATCH 20/24] explicitly import ISession and add license header Signed-off-by: jace-roell --- .../src/rest/src/session/doc/IPropsToPromptFor.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/imperative/src/rest/src/session/doc/IPropsToPromptFor.ts b/packages/imperative/src/rest/src/session/doc/IPropsToPromptFor.ts index bbc3c9dcd0..5cc72b86b3 100644 --- a/packages/imperative/src/rest/src/session/doc/IPropsToPromptFor.ts +++ b/packages/imperative/src/rest/src/session/doc/IPropsToPromptFor.ts @@ -1,4 +1,15 @@ -import { ISession } from "../../.."; +/* +* This program and the accompanying materials are made available under the terms of the +* Eclipse Public License v2.0 which accompanies this distribution, and is available at +* https://www.eclipse.org/legal/epl-v20.html +* +* SPDX-License-Identifier: EPL-2.0 +* +* Copyright Contributors to the Zowe Project. +* +*/ + +import { ISession } from './ISession'; export interface IPropsToPromptFor { name: keyof SessCfgType & string, From bbfa3cfd20ef4e78724890271cee23773541f686 Mon Sep 17 00:00:00 2001 From: jace-roell Date: Thu, 8 Aug 2024 08:39:10 -0400 Subject: [PATCH 21/24] changelog and linting Signed-off-by: jace-roell --- packages/imperative/CHANGELOG.md | 2 +- .../src/rest/src/session/ConnectionPropsForSessCfg.ts | 3 ++- packages/zosuss/CHANGELOG.md | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/imperative/CHANGELOG.md b/packages/imperative/CHANGELOG.md index 2b618c200b..a7929be524 100644 --- a/packages/imperative/CHANGELOG.md +++ b/packages/imperative/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to the Imperative package will be documented in this file. ## Recent Changes -- BugFix: Resolved bug that resulted in user not being prompted for a keyPassphrase if in the secure array of ssh profile. [#1770](https://github.com/zowe/zowe-cli/issues/1770) +- BugFix: Resolved bug that resulted in user not being prompted for a key passphrase if it is located in the secure creditial array of the ssh profile. [#1770](https://github.com/zowe/zowe-cli/issues/1770) ## `8.0.0-next.202407262216` diff --git a/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts b/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts index d690a7c7af..4362e8026d 100644 --- a/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts +++ b/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts @@ -380,7 +380,8 @@ export class ConnectionPropsForSessCfg { * @param connOpts Options for adding connection properties * @returns Name-value pairs of connection properties */ - private static getValuesBack(connOpts: IOptionsForAddConnProps): (properties: string[]) => Promise<{ [key: string]: any }> { + private static getValuesBack(connOpts: IOptionsForAddConnProps): + (properties: string[]) => Promise<{ [key: string]: any }> { return async (promptForValues: string[]) => { /* The check for console.log in the following 'if' statement is only needed for tests * which do not create a mock for the connOpts.parms.response.console.log property. diff --git a/packages/zosuss/CHANGELOG.md b/packages/zosuss/CHANGELOG.md index edccac0043..8df00d96d3 100644 --- a/packages/zosuss/CHANGELOG.md +++ b/packages/zosuss/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to the Zowe z/OS USS SDK package will be documented in this ## Recent Changes -- BugFix: Resolved bug that resulted in user not being prompted for a keyPassphrase if in the secure array of ssh profile. [#1770](https://github.com/zowe/zowe-cli/issues/1770) +- BugFix: Resolved bug that resulted in user not being prompted for a key passphrase if it is located in the secure creditial array of the ssh profile. [#1770](https://github.com/zowe/zowe-cli/issues/1770) - Enhancement: SshBaseHandler.ts command processor will now prompt user up to 3 times to enter the correct keyPassphrase in the case that the stored value is incorrect or no value is stored. [#1770](https://github.com/zowe/zowe-cli/issues/1770) ## `8.0.0-next.202403132009` From 5b9988ad79c019d208d5073c6c55170e15fcd447 Mon Sep 17 00:00:00 2001 From: jace-roell Date: Fri, 9 Aug 2024 11:55:27 -0400 Subject: [PATCH 22/24] added support for case when the local private key is fake and should display the proper error messages Signed-off-by: jace-roell --- packages/zosuss/src/SshBaseHandler.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/zosuss/src/SshBaseHandler.ts b/packages/zosuss/src/SshBaseHandler.ts index 20ff5aecdf..d3927573e4 100644 --- a/packages/zosuss/src/SshBaseHandler.ts +++ b/packages/zosuss/src/SshBaseHandler.ts @@ -91,11 +91,11 @@ export abstract class SshBaseHandler implements ICommandHandler { try { await this.processCmd(commandParameters); } catch (e) { - this.console.log("Initial key passphrase authentication failed!" + "\n"); if ( e.message.includes("but no passphrase given") || e.message.includes("bad passphrase?") ) { + this.console.log("Initial key passphrase authentication failed!" + "\n"); const maxAttempts = 3; let attempt = 0; let success = false; @@ -155,6 +155,10 @@ export abstract class SshBaseHandler implements ICommandHandler { } } } + else + { + throw e; + } } } From ff16d359ce9aaff4bff9782c7588fe107719a78b Mon Sep 17 00:00:00 2001 From: jace-roell Date: Fri, 9 Aug 2024 12:14:53 -0400 Subject: [PATCH 23/24] changelog Signed-off-by: jace-roell --- packages/imperative/CHANGELOG.md | 2 +- packages/zosuss/CHANGELOG.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/imperative/CHANGELOG.md b/packages/imperative/CHANGELOG.md index a7929be524..e5709c514e 100644 --- a/packages/imperative/CHANGELOG.md +++ b/packages/imperative/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to the Imperative package will be documented in this file. ## Recent Changes -- BugFix: Resolved bug that resulted in user not being prompted for a key passphrase if it is located in the secure creditial array of the ssh profile. [#1770](https://github.com/zowe/zowe-cli/issues/1770) +- BugFix: Resolved bug that resulted in user not being prompted for a key passphrase if it is located in the secure credential array of the ssh profile. [#1770](https://github.com/zowe/zowe-cli/issues/1770) ## `8.0.0-next.202407262216` diff --git a/packages/zosuss/CHANGELOG.md b/packages/zosuss/CHANGELOG.md index 8df00d96d3..3828fcd3fb 100644 --- a/packages/zosuss/CHANGELOG.md +++ b/packages/zosuss/CHANGELOG.md @@ -4,8 +4,8 @@ All notable changes to the Zowe z/OS USS SDK package will be documented in this ## Recent Changes -- BugFix: Resolved bug that resulted in user not being prompted for a key passphrase if it is located in the secure creditial array of the ssh profile. [#1770](https://github.com/zowe/zowe-cli/issues/1770) -- Enhancement: SshBaseHandler.ts command processor will now prompt user up to 3 times to enter the correct keyPassphrase in the case that the stored value is incorrect or no value is stored. [#1770](https://github.com/zowe/zowe-cli/issues/1770) +- BugFix: Resolved bug that resulted in user not being prompted for a key passphrase if it is located in the secure credential array of the ssh profile. [#1770](https://github.com/zowe/zowe-cli/issues/1770) +- Enhancement: `SshBaseHandler` command processor will now prompt user up to 3 times to enter the correct keyPassphrase in the case that the stored value is incorrect or no value is stored. [#1770](https://github.com/zowe/zowe-cli/issues/1770) ## `8.0.0-next.202403132009` From 61fb47588a7d8b3cdc0c4e40ebe866a894c2adbe Mon Sep 17 00:00:00 2001 From: zowe-robot Date: Fri, 9 Aug 2024 20:29:27 +0000 Subject: [PATCH 24/24] Bump version to 8.0.0-next.202408092029 [ci skip] Signed-off-by: zowe-robot --- .../__packages__/cli-test-utils/package.json | 4 +- lerna.json | 2 +- npm-shrinkwrap.json | 122 +++++++++--------- packages/cli/package.json | 28 ++-- packages/core/package.json | 6 +- packages/imperative/CHANGELOG.md | 2 +- packages/imperative/package.json | 4 +- packages/provisioning/package.json | 8 +- packages/secrets/package.json | 2 +- packages/workflows/package.json | 10 +- packages/zosconsole/package.json | 8 +- packages/zosfiles/package.json | 10 +- packages/zosjobs/package.json | 10 +- packages/zoslogs/package.json | 8 +- packages/zosmf/package.json | 8 +- packages/zostso/package.json | 10 +- packages/zosuss/CHANGELOG.md | 2 +- packages/zosuss/package.json | 6 +- 18 files changed, 125 insertions(+), 125 deletions(-) diff --git a/__tests__/__packages__/cli-test-utils/package.json b/__tests__/__packages__/cli-test-utils/package.json index 541ebfc4ec..d85ceafac8 100644 --- a/__tests__/__packages__/cli-test-utils/package.json +++ b/__tests__/__packages__/cli-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@zowe/cli-test-utils", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "description": "Test utilities package for Zowe CLI plug-ins", "author": "Zowe", "license": "EPL-2.0", @@ -43,7 +43,7 @@ "devDependencies": { "@types/js-yaml": "^4.0.9", "@types/uuid": "^10.0.0", - "@zowe/imperative": "8.0.0-next.202407311544" + "@zowe/imperative": "8.0.0-next.202408092029" }, "peerDependencies": { "@zowe/imperative": "^8.0.0-next" diff --git a/lerna.json b/lerna.json index d6b2fa252c..2d1b36804d 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "command": { "publish": { "ignoreChanges": [ diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index e139b22c6a..a81c408ef9 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -52,7 +52,7 @@ }, "__tests__/__packages__/cli-test-utils": { "name": "@zowe/cli-test-utils", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "license": "EPL-2.0", "dependencies": { "find-up": "^5.0.0", @@ -63,7 +63,7 @@ "devDependencies": { "@types/js-yaml": "^4.0.9", "@types/uuid": "^10.0.0", - "@zowe/imperative": "8.0.0-next.202407311544" + "@zowe/imperative": "8.0.0-next.202408092029" }, "peerDependencies": { "@zowe/imperative": "^8.0.0-next" @@ -16335,21 +16335,21 @@ }, "packages/cli": { "name": "@zowe/cli", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "hasInstallScript": true, "license": "EPL-2.0", "dependencies": { - "@zowe/core-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/imperative": "8.0.0-next.202407311544", - "@zowe/provisioning-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/zos-console-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/zos-files-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/zos-jobs-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/zos-logs-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/zos-tso-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/zos-uss-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/zos-workflows-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/zosmf-for-zowe-sdk": "8.0.0-next.202407311544", + "@zowe/core-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/imperative": "8.0.0-next.202408092029", + "@zowe/provisioning-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/zos-console-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/zos-files-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/zos-jobs-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/zos-logs-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/zos-tso-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/zos-uss-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/zos-workflows-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/zosmf-for-zowe-sdk": "8.0.0-next.202408092029", "find-process": "1.4.7", "lodash": "4.17.21", "minimatch": "9.0.5", @@ -16362,7 +16362,7 @@ "@types/diff": "^5.0.9", "@types/lodash": "^4.17.6", "@types/tar": "^6.1.11", - "@zowe/cli-test-utils": "8.0.0-next.202407311544", + "@zowe/cli-test-utils": "8.0.0-next.202408092029", "comment-json": "^4.2.3", "strip-ansi": "^6.0.1", "which": "^4.0.0" @@ -16371,7 +16371,7 @@ "node": ">=18.12.0" }, "optionalDependencies": { - "@zowe/secrets-for-zowe-sdk": "8.0.0-next.202407311544" + "@zowe/secrets-for-zowe-sdk": "8.0.0-next.202408092029" } }, "packages/cli/node_modules/brace-expansion": { @@ -16418,15 +16418,15 @@ }, "packages/core": { "name": "@zowe/core-for-zowe-sdk", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "license": "EPL-2.0", "dependencies": { "comment-json": "~4.2.3", "string-width": "^4.2.3" }, "devDependencies": { - "@zowe/cli-test-utils": "8.0.0-next.202407311544", - "@zowe/imperative": "8.0.0-next.202407311544" + "@zowe/cli-test-utils": "8.0.0-next.202408092029", + "@zowe/imperative": "8.0.0-next.202408092029" }, "engines": { "node": ">=18.12.0" @@ -16437,7 +16437,7 @@ }, "packages/imperative": { "name": "@zowe/imperative", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "license": "EPL-2.0", "dependencies": { "@types/yargs": "^17.0.32", @@ -16490,7 +16490,7 @@ "@types/pacote": "^11.1.8", "@types/progress": "^2.0.7", "@types/stack-trace": "^0.0.33", - "@zowe/secrets-for-zowe-sdk": "8.0.0-next.202407311544", + "@zowe/secrets-for-zowe-sdk": "8.0.0-next.202408092029", "concurrently": "^8.0.0", "cowsay": "^1.6.0", "deep-diff": "^1.0.0", @@ -16639,16 +16639,16 @@ }, "packages/provisioning": { "name": "@zowe/provisioning-for-zowe-sdk", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "license": "EPL-2.0", "dependencies": { "js-yaml": "^4.1.0" }, "devDependencies": { "@types/js-yaml": "^4.0.9", - "@zowe/cli-test-utils": "8.0.0-next.202407311544", - "@zowe/core-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/imperative": "8.0.0-next.202407311544" + "@zowe/cli-test-utils": "8.0.0-next.202408092029", + "@zowe/core-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/imperative": "8.0.0-next.202408092029" }, "engines": { "node": ">=18.12.0" @@ -16660,7 +16660,7 @@ }, "packages/secrets": { "name": "@zowe/secrets-for-zowe-sdk", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "hasInstallScript": true, "license": "EPL-2.0", "devDependencies": { @@ -16673,15 +16673,15 @@ }, "packages/workflows": { "name": "@zowe/zos-workflows-for-zowe-sdk", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "license": "EPL-2.0", "dependencies": { - "@zowe/zos-files-for-zowe-sdk": "8.0.0-next.202407311544" + "@zowe/zos-files-for-zowe-sdk": "8.0.0-next.202408092029" }, "devDependencies": { - "@zowe/cli-test-utils": "8.0.0-next.202407311544", - "@zowe/core-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/imperative": "8.0.0-next.202407311544" + "@zowe/cli-test-utils": "8.0.0-next.202408092029", + "@zowe/core-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/imperative": "8.0.0-next.202408092029" }, "engines": { "node": ">=18.12.0" @@ -16693,12 +16693,12 @@ }, "packages/zosconsole": { "name": "@zowe/zos-console-for-zowe-sdk", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "license": "EPL-2.0", "devDependencies": { - "@zowe/cli-test-utils": "8.0.0-next.202407311544", - "@zowe/core-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/imperative": "8.0.0-next.202407311544" + "@zowe/cli-test-utils": "8.0.0-next.202408092029", + "@zowe/core-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/imperative": "8.0.0-next.202408092029" }, "engines": { "node": ">=18.12.0" @@ -16710,16 +16710,16 @@ }, "packages/zosfiles": { "name": "@zowe/zos-files-for-zowe-sdk", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "license": "EPL-2.0", "dependencies": { "minimatch": "^9.0.5" }, "devDependencies": { - "@zowe/cli-test-utils": "8.0.0-next.202407311544", - "@zowe/core-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/imperative": "8.0.0-next.202407311544", - "@zowe/zos-uss-for-zowe-sdk": "8.0.0-next.202407311544" + "@zowe/cli-test-utils": "8.0.0-next.202408092029", + "@zowe/core-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/imperative": "8.0.0-next.202408092029", + "@zowe/zos-uss-for-zowe-sdk": "8.0.0-next.202408092029" }, "engines": { "node": ">=18.12.0" @@ -16751,15 +16751,15 @@ }, "packages/zosjobs": { "name": "@zowe/zos-jobs-for-zowe-sdk", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "license": "EPL-2.0", "dependencies": { - "@zowe/zos-files-for-zowe-sdk": "8.0.0-next.202407311544" + "@zowe/zos-files-for-zowe-sdk": "8.0.0-next.202408092029" }, "devDependencies": { - "@zowe/cli-test-utils": "8.0.0-next.202407311544", - "@zowe/core-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/imperative": "8.0.0-next.202407311544" + "@zowe/cli-test-utils": "8.0.0-next.202408092029", + "@zowe/core-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/imperative": "8.0.0-next.202408092029" }, "engines": { "node": ">=18.12.0" @@ -16771,12 +16771,12 @@ }, "packages/zoslogs": { "name": "@zowe/zos-logs-for-zowe-sdk", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "license": "EPL-2.0", "devDependencies": { - "@zowe/cli-test-utils": "8.0.0-next.202407311544", - "@zowe/core-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/imperative": "8.0.0-next.202407311544" + "@zowe/cli-test-utils": "8.0.0-next.202408092029", + "@zowe/core-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/imperative": "8.0.0-next.202408092029" }, "engines": { "node": ">=18.12.0" @@ -16788,12 +16788,12 @@ }, "packages/zosmf": { "name": "@zowe/zosmf-for-zowe-sdk", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "license": "EPL-2.0", "devDependencies": { - "@zowe/cli-test-utils": "8.0.0-next.202407311544", - "@zowe/core-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/imperative": "8.0.0-next.202407311544" + "@zowe/cli-test-utils": "8.0.0-next.202408092029", + "@zowe/core-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/imperative": "8.0.0-next.202408092029" }, "engines": { "node": ">=18.12.0" @@ -16805,15 +16805,15 @@ }, "packages/zostso": { "name": "@zowe/zos-tso-for-zowe-sdk", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "license": "EPL-2.0", "dependencies": { - "@zowe/zosmf-for-zowe-sdk": "8.0.0-next.202407311544" + "@zowe/zosmf-for-zowe-sdk": "8.0.0-next.202408092029" }, "devDependencies": { - "@zowe/cli-test-utils": "8.0.0-next.202407311544", - "@zowe/core-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/imperative": "8.0.0-next.202407311544" + "@zowe/cli-test-utils": "8.0.0-next.202408092029", + "@zowe/core-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/imperative": "8.0.0-next.202408092029" }, "engines": { "node": ">=18.12.0" @@ -16825,15 +16825,15 @@ }, "packages/zosuss": { "name": "@zowe/zos-uss-for-zowe-sdk", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "license": "EPL-2.0", "dependencies": { "ssh2": "^1.15.0" }, "devDependencies": { "@types/ssh2": "^1.11.19", - "@zowe/cli-test-utils": "8.0.0-next.202407311544", - "@zowe/imperative": "8.0.0-next.202407311544" + "@zowe/cli-test-utils": "8.0.0-next.202408092029", + "@zowe/imperative": "8.0.0-next.202408092029" }, "engines": { "node": ">=18.12.0" diff --git a/packages/cli/package.json b/packages/cli/package.json index 5b2323d8c2..0d5eb2354a 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@zowe/cli", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "zoweVersion": "v3.0.0-prerelease", "description": "Zowe CLI is a command line interface (CLI) that provides a simple and streamlined way to interact with IBM z/OS.", "author": "Zowe", @@ -58,17 +58,17 @@ "preshrinkwrap": "node ../../scripts/rewriteShrinkwrap.js" }, "dependencies": { - "@zowe/core-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/imperative": "8.0.0-next.202407311544", - "@zowe/provisioning-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/zos-console-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/zos-files-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/zos-jobs-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/zos-logs-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/zos-tso-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/zos-uss-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/zos-workflows-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/zosmf-for-zowe-sdk": "8.0.0-next.202407311544", + "@zowe/core-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/imperative": "8.0.0-next.202408092029", + "@zowe/provisioning-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/zos-console-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/zos-files-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/zos-jobs-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/zos-logs-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/zos-tso-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/zos-uss-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/zos-workflows-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/zosmf-for-zowe-sdk": "8.0.0-next.202408092029", "find-process": "1.4.7", "lodash": "4.17.21", "minimatch": "9.0.5", @@ -78,13 +78,13 @@ "@types/diff": "^5.0.9", "@types/lodash": "^4.17.6", "@types/tar": "^6.1.11", - "@zowe/cli-test-utils": "8.0.0-next.202407311544", + "@zowe/cli-test-utils": "8.0.0-next.202408092029", "comment-json": "^4.2.3", "strip-ansi": "^6.0.1", "which": "^4.0.0" }, "optionalDependencies": { - "@zowe/secrets-for-zowe-sdk": "8.0.0-next.202407311544" + "@zowe/secrets-for-zowe-sdk": "8.0.0-next.202408092029" }, "engines": { "node": ">=18.12.0" diff --git a/packages/core/package.json b/packages/core/package.json index c122589664..2f36d7d8ee 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@zowe/core-for-zowe-sdk", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "description": "Core libraries shared by Zowe SDK packages", "author": "Zowe", "license": "EPL-2.0", @@ -49,8 +49,8 @@ "string-width": "^4.2.3" }, "devDependencies": { - "@zowe/cli-test-utils": "8.0.0-next.202407311544", - "@zowe/imperative": "8.0.0-next.202407311544" + "@zowe/cli-test-utils": "8.0.0-next.202408092029", + "@zowe/imperative": "8.0.0-next.202408092029" }, "peerDependencies": { "@zowe/imperative": "^8.0.0-next" diff --git a/packages/imperative/CHANGELOG.md b/packages/imperative/CHANGELOG.md index e5709c514e..19921e7637 100644 --- a/packages/imperative/CHANGELOG.md +++ b/packages/imperative/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to the Imperative package will be documented in this file. -## Recent Changes +## `8.0.0-next.202408092029` - BugFix: Resolved bug that resulted in user not being prompted for a key passphrase if it is located in the secure credential array of the ssh profile. [#1770](https://github.com/zowe/zowe-cli/issues/1770) diff --git a/packages/imperative/package.json b/packages/imperative/package.json index f0b6be5f6b..1491d43a54 100644 --- a/packages/imperative/package.json +++ b/packages/imperative/package.json @@ -1,6 +1,6 @@ { "name": "@zowe/imperative", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "description": "framework for building configurable CLIs", "author": "Zowe", "license": "EPL-2.0", @@ -93,7 +93,7 @@ "@types/pacote": "^11.1.8", "@types/progress": "^2.0.7", "@types/stack-trace": "^0.0.33", - "@zowe/secrets-for-zowe-sdk": "8.0.0-next.202407311544", + "@zowe/secrets-for-zowe-sdk": "8.0.0-next.202408092029", "concurrently": "^8.0.0", "cowsay": "^1.6.0", "deep-diff": "^1.0.0", diff --git a/packages/provisioning/package.json b/packages/provisioning/package.json index c259e00fb5..381e3dbb12 100644 --- a/packages/provisioning/package.json +++ b/packages/provisioning/package.json @@ -1,6 +1,6 @@ { "name": "@zowe/provisioning-for-zowe-sdk", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "description": "Zowe SDK to interact with the z/OS provisioning APIs", "author": "Zowe", "license": "EPL-2.0", @@ -49,9 +49,9 @@ }, "devDependencies": { "@types/js-yaml": "^4.0.9", - "@zowe/cli-test-utils": "8.0.0-next.202407311544", - "@zowe/core-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/imperative": "8.0.0-next.202407311544" + "@zowe/cli-test-utils": "8.0.0-next.202408092029", + "@zowe/core-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/imperative": "8.0.0-next.202408092029" }, "peerDependencies": { "@zowe/core-for-zowe-sdk": "^8.0.0-next", diff --git a/packages/secrets/package.json b/packages/secrets/package.json index 3655e662c1..90321d7a76 100644 --- a/packages/secrets/package.json +++ b/packages/secrets/package.json @@ -3,7 +3,7 @@ "description": "Credential management facilities for Imperative, Zowe CLI, and extenders.", "repository": "https://github.com/zowe/zowe-cli.git", "author": "Zowe", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "homepage": "https://github.com/zowe/zowe-cli/tree/master/packages/secrets#readme", "bugs": { "url": "https://github.com/zowe/zowe-cli/issues" diff --git a/packages/workflows/package.json b/packages/workflows/package.json index ea0ab4bbe7..6f603e12d7 100644 --- a/packages/workflows/package.json +++ b/packages/workflows/package.json @@ -1,6 +1,6 @@ { "name": "@zowe/zos-workflows-for-zowe-sdk", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "description": "Zowe SDK to interact with the z/OS workflows APIs", "author": "Zowe", "license": "EPL-2.0", @@ -45,12 +45,12 @@ "prepack": "node ../../scripts/prepareLicenses.js" }, "dependencies": { - "@zowe/zos-files-for-zowe-sdk": "8.0.0-next.202407311544" + "@zowe/zos-files-for-zowe-sdk": "8.0.0-next.202408092029" }, "devDependencies": { - "@zowe/cli-test-utils": "8.0.0-next.202407311544", - "@zowe/core-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/imperative": "8.0.0-next.202407311544" + "@zowe/cli-test-utils": "8.0.0-next.202408092029", + "@zowe/core-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/imperative": "8.0.0-next.202408092029" }, "peerDependencies": { "@zowe/core-for-zowe-sdk": "^8.0.0-next", diff --git a/packages/zosconsole/package.json b/packages/zosconsole/package.json index 17bc86d02a..001b448a6e 100644 --- a/packages/zosconsole/package.json +++ b/packages/zosconsole/package.json @@ -1,6 +1,6 @@ { "name": "@zowe/zos-console-for-zowe-sdk", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "description": "Zowe SDK to interact with the z/OS console", "author": "Zowe", "license": "EPL-2.0", @@ -45,9 +45,9 @@ "prepack": "node ../../scripts/prepareLicenses.js" }, "devDependencies": { - "@zowe/cli-test-utils": "8.0.0-next.202407311544", - "@zowe/core-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/imperative": "8.0.0-next.202407311544" + "@zowe/cli-test-utils": "8.0.0-next.202408092029", + "@zowe/core-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/imperative": "8.0.0-next.202408092029" }, "peerDependencies": { "@zowe/core-for-zowe-sdk": "^8.0.0-next", diff --git a/packages/zosfiles/package.json b/packages/zosfiles/package.json index 4df09eb712..2b4add10e9 100644 --- a/packages/zosfiles/package.json +++ b/packages/zosfiles/package.json @@ -1,6 +1,6 @@ { "name": "@zowe/zos-files-for-zowe-sdk", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "description": "Zowe SDK to interact with files and data sets on z/OS", "author": "Zowe", "license": "EPL-2.0", @@ -49,10 +49,10 @@ "minimatch": "^9.0.5" }, "devDependencies": { - "@zowe/cli-test-utils": "8.0.0-next.202407311544", - "@zowe/core-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/imperative": "8.0.0-next.202407311544", - "@zowe/zos-uss-for-zowe-sdk": "8.0.0-next.202407311544" + "@zowe/cli-test-utils": "8.0.0-next.202408092029", + "@zowe/core-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/imperative": "8.0.0-next.202408092029", + "@zowe/zos-uss-for-zowe-sdk": "8.0.0-next.202408092029" }, "peerDependencies": { "@zowe/core-for-zowe-sdk": "^8.0.0-next", diff --git a/packages/zosjobs/package.json b/packages/zosjobs/package.json index 0105f547ec..e449393471 100644 --- a/packages/zosjobs/package.json +++ b/packages/zosjobs/package.json @@ -1,6 +1,6 @@ { "name": "@zowe/zos-jobs-for-zowe-sdk", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "description": "Zowe SDK to interact with jobs on z/OS", "author": "Zowe", "license": "EPL-2.0", @@ -46,12 +46,12 @@ "prepack": "node ../../scripts/prepareLicenses.js" }, "dependencies": { - "@zowe/zos-files-for-zowe-sdk": "8.0.0-next.202407311544" + "@zowe/zos-files-for-zowe-sdk": "8.0.0-next.202408092029" }, "devDependencies": { - "@zowe/cli-test-utils": "8.0.0-next.202407311544", - "@zowe/core-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/imperative": "8.0.0-next.202407311544" + "@zowe/cli-test-utils": "8.0.0-next.202408092029", + "@zowe/core-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/imperative": "8.0.0-next.202408092029" }, "peerDependencies": { "@zowe/core-for-zowe-sdk": "^8.0.0-next", diff --git a/packages/zoslogs/package.json b/packages/zoslogs/package.json index 675efc3bb6..33faeca953 100644 --- a/packages/zoslogs/package.json +++ b/packages/zoslogs/package.json @@ -1,6 +1,6 @@ { "name": "@zowe/zos-logs-for-zowe-sdk", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "description": "Zowe SDK to interact with the z/OS logs", "author": "Zowe", "license": "EPL-2.0", @@ -45,9 +45,9 @@ "prepack": "node ../../scripts/prepareLicenses.js" }, "devDependencies": { - "@zowe/cli-test-utils": "8.0.0-next.202407311544", - "@zowe/core-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/imperative": "8.0.0-next.202407311544" + "@zowe/cli-test-utils": "8.0.0-next.202408092029", + "@zowe/core-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/imperative": "8.0.0-next.202408092029" }, "peerDependencies": { "@zowe/core-for-zowe-sdk": "^8.0.0-next", diff --git a/packages/zosmf/package.json b/packages/zosmf/package.json index 3f1fd7ec62..737393ad3f 100644 --- a/packages/zosmf/package.json +++ b/packages/zosmf/package.json @@ -1,6 +1,6 @@ { "name": "@zowe/zosmf-for-zowe-sdk", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "description": "Zowe SDK to interact with the z/OS Management Facility", "author": "Zowe", "license": "EPL-2.0", @@ -44,9 +44,9 @@ "prepack": "node ../../scripts/prepareLicenses.js" }, "devDependencies": { - "@zowe/cli-test-utils": "8.0.0-next.202407311544", - "@zowe/core-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/imperative": "8.0.0-next.202407311544" + "@zowe/cli-test-utils": "8.0.0-next.202408092029", + "@zowe/core-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/imperative": "8.0.0-next.202408092029" }, "peerDependencies": { "@zowe/core-for-zowe-sdk": "^8.0.0-next", diff --git a/packages/zostso/package.json b/packages/zostso/package.json index 0b97565aea..1ed0a5d19c 100644 --- a/packages/zostso/package.json +++ b/packages/zostso/package.json @@ -1,6 +1,6 @@ { "name": "@zowe/zos-tso-for-zowe-sdk", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "description": "Zowe SDK to interact with TSO on z/OS", "author": "Zowe", "license": "EPL-2.0", @@ -45,12 +45,12 @@ "prepack": "node ../../scripts/prepareLicenses.js" }, "dependencies": { - "@zowe/zosmf-for-zowe-sdk": "8.0.0-next.202407311544" + "@zowe/zosmf-for-zowe-sdk": "8.0.0-next.202408092029" }, "devDependencies": { - "@zowe/cli-test-utils": "8.0.0-next.202407311544", - "@zowe/core-for-zowe-sdk": "8.0.0-next.202407311544", - "@zowe/imperative": "8.0.0-next.202407311544" + "@zowe/cli-test-utils": "8.0.0-next.202408092029", + "@zowe/core-for-zowe-sdk": "8.0.0-next.202408092029", + "@zowe/imperative": "8.0.0-next.202408092029" }, "peerDependencies": { "@zowe/core-for-zowe-sdk": "^8.0.0-next", diff --git a/packages/zosuss/CHANGELOG.md b/packages/zosuss/CHANGELOG.md index 3828fcd3fb..95824880aa 100644 --- a/packages/zosuss/CHANGELOG.md +++ b/packages/zosuss/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to the Zowe z/OS USS SDK package will be documented in this file. -## Recent Changes +## `8.0.0-next.202408092029` - BugFix: Resolved bug that resulted in user not being prompted for a key passphrase if it is located in the secure credential array of the ssh profile. [#1770](https://github.com/zowe/zowe-cli/issues/1770) - Enhancement: `SshBaseHandler` command processor will now prompt user up to 3 times to enter the correct keyPassphrase in the case that the stored value is incorrect or no value is stored. [#1770](https://github.com/zowe/zowe-cli/issues/1770) diff --git a/packages/zosuss/package.json b/packages/zosuss/package.json index 12fbe8ebc6..6244f65510 100644 --- a/packages/zosuss/package.json +++ b/packages/zosuss/package.json @@ -1,6 +1,6 @@ { "name": "@zowe/zos-uss-for-zowe-sdk", - "version": "8.0.0-next.202407311544", + "version": "8.0.0-next.202408092029", "description": "Zowe SDK to interact with USS on z/OS", "author": "Zowe", "license": "EPL-2.0", @@ -49,8 +49,8 @@ }, "devDependencies": { "@types/ssh2": "^1.11.19", - "@zowe/cli-test-utils": "8.0.0-next.202407311544", - "@zowe/imperative": "8.0.0-next.202407311544" + "@zowe/cli-test-utils": "8.0.0-next.202408092029", + "@zowe/imperative": "8.0.0-next.202408092029" }, "peerDependencies": { "@zowe/imperative": "^8.0.0-next"