@ibm-cloud/cd-tools 1.5.2 → 1.6.0
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/cmd/copy-toolchain.js +9 -12
- package/cmd/export-secrets.js +323 -0
- package/cmd/index.js +2 -2
- package/cmd/utils/logger.js +18 -12
- package/cmd/utils/requests.js +125 -39
- package/cmd/utils/terraform.js +24 -4
- package/cmd/utils/utils.js +67 -3
- package/cmd/utils/validate.js +10 -6
- package/create-s2s-script.js +13 -9
- package/index.js +11 -4
- package/package.json +1 -1
- package/test/README.md +2 -2
- package/test/config/local.template.json +1 -1
- package/test/copy-toolchain/functionalities.test.js +0 -2
- package/test/copy-toolchain/input-validation.test.js +2 -4
- package/test/copy-toolchain/tf-import.test.js +0 -3
- package/test/copy-toolchain/tool-validation.test.js +1 -3
- package/cmd/check-secrets.js +0 -111
|
@@ -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';
|
|
@@ -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: /
|
|
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: /
|
|
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',
|
|
@@ -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
|
|
|
@@ -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';
|
|
@@ -87,7 +85,7 @@ describe('copy-toolchain: Test tool validation', function () {
|
|
|
87
85
|
timeout: 30000
|
|
88
86
|
},
|
|
89
87
|
assertionFunc: (output) => {
|
|
90
|
-
expect(output).to.match(/Warning! The following GRIT integration\(s\)
|
|
88
|
+
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
89
|
expect(output).to.match(/hostedgit/);
|
|
92
90
|
expect(output).to.match(/Warning! The following tools contain secrets that cannot be migrated/);
|
|
93
91
|
expect(output).to.match(/githubconsolidated[\s\S]*?api_token/);
|
package/cmd/check-secrets.js
DELETED
|
@@ -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;
|