@ibm-cloud/cd-tools 1.5.3 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/test/README.md CHANGED
@@ -36,6 +36,6 @@ You can customize the behavior of the tests by defining configuration properties
36
36
  | `TEST_TEMP_DIR` | `string` | `test/.tmp` | The directory to store temporary files generated by test cases |
37
37
  | `TEST_LOG_DIR` | `string` | `test/.test-logs` | The directory to store test run log files |
38
38
  | `IBMCLOUD_API_KEY` | `string` | `null` | The IBM Cloud API Key used to run the tests |
39
- | `LOG_DUMP` | `boolean` | `false` | When set to `true`, individual test case's process's log file generation is enabled |
39
+ | `LOG_DUMP` | `boolean` | `false` | When set to `true`, individual test case's process's log file generation is enabled, and logs are written to `TEST_TEMP_DIR` |
40
40
  | `DISABLE_SPINNER` | `boolean` | `true` | When set to `true`, visual spinner is disabled across all test cases' processes |
41
- | `VERBOSE_MODE` | `boolean` | `false` | When set to `true`, each test case's log output increases |
41
+ | `VERBOSE_MODE` | `boolean` | `false` | When set to `true`, each test case's log output increases |
@@ -3,7 +3,7 @@
3
3
  "TEST_TEMP_DIR": "test/.tmp",
4
4
  "TEST_LOG_DIR": "test/.logs",
5
5
  "IBMCLOUD_API_KEY": "<YOUR IBMCLOUD API KEY>",
6
- "LOG_DUMP": true,
6
+ "LOG_DUMP": false,
7
7
  "DISABLE_SPINNER": true,
8
8
  "VERBOSE_MODE": false
9
9
  }
@@ -11,8 +11,6 @@ import path from 'node:path';
11
11
  import nconf from 'nconf';
12
12
  import fs from 'node:fs';
13
13
 
14
- import * as chai from 'chai';
15
- chai.config.truncateThreshold = 0;
16
14
  import { expect, assert } from 'chai';
17
15
 
18
16
  import { assertPtyOutput, assertExecError, areFilesInDir, deleteCreatedToolchains, parseTcIdAndRegion } from '../utils/testUtils.js';
@@ -39,10 +37,19 @@ describe('copy-toolchain: Test functionalities', function () {
39
37
  const testCases = [
40
38
  {
41
39
  name: 'Terraform Version Verification',
42
- cmd: [CLI_PATH, COMMAND, '-c', TEST_TOOLCHAINS['empty'].crn, '-r', TARGET_REGIONS[0]],
40
+ cmd: [CLI_PATH, COMMAND, '-c', TEST_TOOLCHAINS['empty'].crn, '-r', TEST_TOOLCHAINS['empty'].region],
43
41
  expected: /✔ Terraform Version:/,
44
42
  options: {
45
- exitCondition: '(Recommended) Add a tag to the cloned toolchain (Ctrl-C to abort):',
43
+ exitCondition: `(Recommended) Edit the cloned toolchain's name [default: ${TEST_TOOLCHAINS['empty'].name}] (Ctrl-C to abort):`,
44
+ timeout: 10000
45
+ }
46
+ },
47
+ {
48
+ name: 'CLI Version Verification',
49
+ cmd: [CLI_PATH, COMMAND, '-c', TEST_TOOLCHAINS['empty'].crn, '-r', TEST_TOOLCHAINS['empty'].region],
50
+ expected: /✔ cd-tools Version:/,
51
+ options: {
52
+ exitCondition: `(Recommended) Edit the cloned toolchain's name [default: ${TEST_TOOLCHAINS['empty'].name}] (Ctrl-C to abort):`,
46
53
  timeout: 10000
47
54
  }
48
55
  },
@@ -58,10 +65,10 @@ describe('copy-toolchain: Test functionalities', function () {
58
65
  },
59
66
  {
60
67
  name: 'Log file is created successfully',
61
- cmd: [CLI_PATH, COMMAND, '-c', TEST_TOOLCHAINS['empty'].crn, '-r', TARGET_REGIONS[0]],
68
+ cmd: [CLI_PATH, COMMAND, '-c', TEST_TOOLCHAINS['empty'].crn, '-r', TEST_TOOLCHAINS['empty'].region],
62
69
  expected: null,
63
70
  options: {
64
- exitCondition: '(Recommended) Add a tag to the cloned toolchain (Ctrl-C to abort):',
71
+ exitCondition: `(Recommended) Edit the cloned toolchain's name [default: ${TEST_TOOLCHAINS['empty'].name}] (Ctrl-C to abort):`,
65
72
  timeout: 10000,
66
73
  cwd: TEMP_DIR + '/' + 'log-file-is-created-successfully'
67
74
  },
@@ -83,15 +90,6 @@ describe('copy-toolchain: Test functionalities', function () {
83
90
  assert.isTrue(toolchainData.id === toolchainId, 'Was toolchain created successfully without any confirmations?');
84
91
  }
85
92
  },
86
- {
87
- name: 'Prompt User when toolchain name already exists in resource group',
88
- cmd: [CLI_PATH, COMMAND, '-c', TEST_TOOLCHAINS['empty'].crn, '-r', TARGET_REGIONS[0]],
89
- expected: new RegExp(`Warning! A toolchain named \'${TEST_TOOLCHAINS['empty'].name}\' already exists in:[\\s\\S]*?Resource Group:[\\s\\S]*?${R2R_CLI_RG_ID}`),
90
- options: {
91
- exitCondition: '(Recommended) Add a tag to the cloned toolchain (Ctrl-C to abort):',
92
- timeout: 10000
93
- }
94
- },
95
93
  {
96
94
  name: 'Prompt User when toolchain name already exists in region',
97
95
  cmd: [CLI_PATH, COMMAND, '-c', TEST_TOOLCHAINS['empty'].crn, '-r', TEST_TOOLCHAINS['empty'].region, '-g', DEFAULT_RG_ID],
@@ -11,9 +11,7 @@ import path from 'node:path';
11
11
  import nconf from 'nconf';
12
12
  import fs from 'node:fs';
13
13
 
14
- import * as chai from 'chai';
15
14
  import { expect } from 'chai';
16
- chai.config.truncateThreshold = 0;
17
15
 
18
16
  import mocks from '../data/mocks.js';
19
17
  import { assertExecError, assertPtyOutput } from '../utils/testUtils.js';
@@ -81,12 +79,12 @@ describe('copy-toolchain: Test user input handling', function () {
81
79
  {
82
80
  name: 'Invalid Resource Group name is provided',
83
81
  cmd: [CLI_PATH, COMMAND, '-c', validCrn, '-r', TARGET_REGIONS[0], '-g', mocks.invalidRgName],
84
- expected: /The resource group with provided ID or name was not found or is not accessible/,
82
+ expected: /No matching resource groups were found for the provided id\(s\) or name\(s\)/,
85
83
  },
86
84
  {
87
85
  name: 'Invalid Resource Group ID is provided',
88
86
  cmd: [CLI_PATH, COMMAND, '-c', validCrn, '-r', TARGET_REGIONS[0], '-g', mocks.invalidRgId],
89
- expected: /The resource group with provided ID or name was not found or is not accessible/,
87
+ expected: /No matching resource groups were found for the provided id\(s\) or name\(s\)/,
90
88
  },
91
89
  {
92
90
  name: 'Non-existent GRIT mapping file provided',
@@ -127,10 +125,13 @@ describe('copy-toolchain: Test user input handling', function () {
127
125
  const invalidUserInputCases = [
128
126
  {
129
127
  name: 'Invalid Toolchain tag is provided',
130
- cmd: [CLI_PATH, COMMAND, '-c', TEST_TOOLCHAINS['empty'].crn, '-r', TARGET_REGIONS[0]],
128
+ cmd: [CLI_PATH, COMMAND, '-c', TEST_TOOLCHAINS['empty'].crn, '-r', TEST_TOOLCHAINS['empty'].region],
131
129
  expected: /Provided tag is invalid/,
132
130
  options: {
133
- questionAnswerMap: { '(Recommended) Add a tag to the cloned toolchain (Ctrl-C to abort):': mocks.invalidTag },
131
+ questionAnswerMap: {
132
+ [`(Recommended) Edit the cloned toolchain's name [default: ${TEST_TOOLCHAINS['empty'].name}] (Ctrl-C to abort):`]: '',
133
+ '(Recommended) Add a tag to the cloned toolchain (Ctrl-C to abort):': mocks.invalidTag
134
+ },
134
135
  exitCondition: 'Validation failed',
135
136
  timeout: 10000
136
137
  }
@@ -10,9 +10,6 @@
10
10
  import path from 'node:path';
11
11
  import nconf from 'nconf';
12
12
 
13
- import * as chai from 'chai';
14
- chai.config.truncateThreshold = 0;
15
-
16
13
  import { assertTfResourcesInDir, assertPtyOutput } from '../utils/testUtils.js';
17
14
  import { TEST_TOOLCHAINS } from '../data/test-toolchains.js';
18
15
 
@@ -46,12 +43,12 @@ describe('copy-toolchain: Test import-terraform output', function () {
46
43
  ibm_cd_tekton_pipeline_trigger: 1,
47
44
  ibm_cd_tekton_pipeline_trigger_property: 1,
48
45
  ibm_cd_toolchain: 1,
46
+ ibm_cd_toolchain_tool_cos: 1,
49
47
  ibm_cd_toolchain_tool_custom: 1,
50
48
  ibm_cd_toolchain_tool_githubconsolidated: 1,
51
49
  ibm_cd_toolchain_tool_pipeline: 1,
52
50
  ibm_cd_toolchain_tool_secretsmanager: 1,
53
51
  ibm_cd_toolchain_tool_slack: 1,
54
- ibm_iam_authorization_policy: 1
55
52
  });
56
53
  }
57
54
  },
@@ -71,12 +68,12 @@ describe('copy-toolchain: Test import-terraform output', function () {
71
68
  ibm_cd_tekton_pipeline_trigger: 1,
72
69
  ibm_cd_tekton_pipeline_trigger_property: 1,
73
70
  ibm_cd_toolchain: 1,
71
+ ibm_cd_toolchain_tool_cos: 1,
74
72
  ibm_cd_toolchain_tool_custom: 1,
75
73
  ibm_cd_toolchain_tool_githubconsolidated: 1,
76
74
  ibm_cd_toolchain_tool_pipeline: 1,
77
75
  ibm_cd_toolchain_tool_secretsmanager: 1,
78
76
  ibm_cd_toolchain_tool_slack: 1,
79
- ibm_iam_authorization_policy: 1
80
77
  });
81
78
  }
82
79
  },
@@ -102,7 +99,6 @@ describe('copy-toolchain: Test import-terraform output', function () {
102
99
  ibm_cd_toolchain_tool_pipeline: 1,
103
100
  ibm_cd_toolchain_tool_secretsmanager: 1,
104
101
  ibm_cd_toolchain_tool_slack: 1,
105
- ibm_iam_authorization_policy: 1
106
102
  })
107
103
  }
108
104
  },
@@ -10,8 +10,6 @@
10
10
  import path from 'node:path';
11
11
  import nconf from 'nconf';
12
12
 
13
- import * as chai from 'chai';
14
- chai.config.truncateThreshold = 0;
15
13
  import { expect } from 'chai';
16
14
 
17
15
  import { assertPtyOutput, deleteCreatedToolchains } from '../utils/testUtils.js';
@@ -58,7 +56,6 @@ describe('copy-toolchain: Test tool validation', function () {
58
56
  },
59
57
  assertionFunc: (output) => {
60
58
  expect(output).to.match(/Warning! The following tools contain secrets that cannot be migrated/);
61
- expect(output).to.match(/cloudobjectstorage[\s\S]*?cos_api_key/);
62
59
  expect(output).to.match(/slack[\s\S]*?api_token/);
63
60
  expect(output).to.match(/pipeline[\s\S]*?properties.doi-ibmcloud-api-key/);
64
61
  }
@@ -87,7 +84,7 @@ describe('copy-toolchain: Test tool validation', function () {
87
84
  timeout: 30000
88
85
  },
89
86
  assertionFunc: (output) => {
90
- expect(output).to.match(/Warning! The following GRIT integration\(s\) are using auth_type "pat", please switch to auth_type "oauth" before proceeding/);
87
+ expect(output).to.match(/Warning! The following GRIT integration\(s\) with auth_type "pat" are unsupported during migration and will automatically be converted to auth_type "oauth"/);
91
88
  expect(output).to.match(/hostedgit/);
92
89
  expect(output).to.match(/Warning! The following tools contain secrets that cannot be migrated/);
93
90
  expect(output).to.match(/githubconsolidated[\s\S]*?api_token/);
@@ -1,111 +0,0 @@
1
- /**
2
- * Licensed Materials - Property of IBM
3
- * (c) Copyright IBM Corporation 2025. All Rights Reserved.
4
- *
5
- * Note to U.S. Government Users Restricted Rights:
6
- * Use, duplication or disclosure restricted by GSA ADP Schedule
7
- * Contract with IBM Corp.
8
- */
9
- 'use strict';
10
-
11
- import { exit } from 'node:process';
12
- import { Command } from 'commander';
13
- import { parseEnvVar, decomposeCrn, isSecretReference } from './utils/utils.js';
14
- import { logger, LOG_STAGES } from './utils/logger.js';
15
- import { getBearerToken, getToolchainTools, getPipelineData } from './utils/requests.js';
16
- import { SECRET_KEYS_MAP } from '../config.js';
17
-
18
- const command = new Command('check-secrets')
19
- .description('Checks if you have any stored secrets in your toolchain or pipelines')
20
- .requiredOption('-c, --toolchain-crn <crn>', 'The CRN of the source toolchain to check')
21
- .option('-a --apikey <api key>', 'IBM Cloud IAM API key with permissions to read the toolchain.')
22
- .showHelpAfterError()
23
- .hook('preAction', cmd => cmd.showHelpAfterError(false)) // only show help during validation
24
- .action(main);
25
-
26
- async function main(options) {
27
- const toolchainCrn = options.toolchainCrn;
28
- const apiKey = options.apikey || parseEnvVar('IBMCLOUD_API_KEY');
29
-
30
- if (!apiKey) {
31
- logger.error('Missing IBM Cloud IAM API key', LOG_STAGES.setup);
32
- exit(1);
33
- };
34
-
35
- logger.print(`Checking secrets for toolchain ${toolchainCrn}...`);
36
-
37
- const decomposedCrn = decomposeCrn(toolchainCrn);
38
-
39
- const token = await getBearerToken(apiKey);
40
- const toolchainId = decomposedCrn.serviceInstance;
41
- const region = decomposedCrn.location;
42
-
43
- const getToolsRes = await getToolchainTools(token, toolchainId, region);
44
-
45
- const toolResults = [];
46
- const pipelineResults = [];
47
-
48
- if (getToolsRes?.tools?.length > 0) {
49
- for (let i = 0; i < getToolsRes.tools.length; i++) {
50
- const tool = getToolsRes.tools[i];
51
-
52
- // Skip iff it's GitHub/GitLab/GRIT integration with OAuth
53
- if (['githubconsolidated', 'github_integrated', 'gitlab', 'hostedgit'].includes(tool.tool_type_id) && (tool.parameters?.auth_type === '' || tool.parameters?.auth_type === 'oauth'))
54
- continue;
55
-
56
- // Check tool integrations for any plain text secret values
57
- if (SECRET_KEYS_MAP[tool.tool_type_id]) {
58
- SECRET_KEYS_MAP[tool.tool_type_id].forEach((entry) => {
59
- const updateableSecretParam = entry.key;
60
- if (tool.parameters[updateableSecretParam] && !isSecretReference(tool.parameters[updateableSecretParam]) && tool.parameters[updateableSecretParam].length > 0) {
61
- toolResults.push({
62
- 'Tool ID': tool.id,
63
- 'Tool Type': tool.tool_type_id,
64
- 'Property Name': updateableSecretParam
65
- });
66
- };
67
- });
68
- };
69
-
70
- // For tekton pipelines, check for any plain text secret properties
71
- if (tool.tool_type_id === 'pipeline' && tool.parameters?.type === 'tekton') {
72
- const pipelineData = await getPipelineData(token, tool.id, region);
73
-
74
- pipelineData?.properties.forEach((prop) => {
75
- if (prop.type === 'secure' && !isSecretReference(prop.value) && prop.value.length > 0) {
76
- pipelineResults.push({
77
- 'Pipeline ID': pipelineData.id,
78
- 'Trigger Name': '-',
79
- 'Property Name': prop.name
80
- });
81
- };
82
- });
83
-
84
- pipelineData?.triggers.forEach((trigger) => {
85
- trigger.properties?.forEach((prop) => {
86
- if (prop.type === 'secure' && !isSecretReference(prop.value) && prop.value.length > 0) {
87
- pipelineResults.push({
88
- 'Pipeline ID': pipelineData.id,
89
- 'Trigger Name': trigger.name,
90
- 'Property Name': prop.name
91
- });
92
- };
93
- });
94
- });
95
- }
96
- };
97
- };
98
-
99
- if (toolResults.length > 0) {
100
- logger.print();
101
- logger.print('The following plain text properties were found in tool integrations bound to the toolchain:');
102
- logger.table(toolResults);
103
- };
104
- if (pipelineResults.length > 0) {
105
- logger.print();
106
- logger.print('The following plain text properties were found in Tekton pipeline(s) bound to the toolchain:');
107
- logger.table(pipelineResults);
108
- };
109
- };
110
-
111
- export default command;