Skip to content

Commit e96bb5b

Browse files
paul-marechalmarcdumais-work
authored andcommitted
secrets + cleanup
Avoid using `shell: true` as I had bad experiences with it on Windows. Instead sanitize arguments to hide secrets when prompting.
1 parent 86dbe79 commit e96bb5b

File tree

1 file changed

+61
-30
lines changed

1 file changed

+61
-30
lines changed

scripts/check_3pp_licenses.js

+61-30
Original file line numberDiff line numberDiff line change
@@ -18,37 +18,37 @@
1818
const cp = require('child_process');
1919
const fs = require('fs');
2020
const path = require('path');
21-
const { env, argv } = require('process');
2221
const readline = require('readline');
22+
const kSECRET = Symbol('secret');
23+
2324
// Submit any suspicious dependencies for review by the Eclipse Foundation, using dash-license "review" mode?
24-
const autoReviewMode = (process.argv.slice(2))[0] == "--review" ? true:false
25+
const autoReviewMode = process.argv.includes('--review');
26+
const project = process.argv.find(arg => /--project=(\S+)/.exec(arg)?.[1]) ?? 'ecd.theia';
2527

2628
const NO_COLOR = Boolean(process.env['NO_COLOR']);
2729
const dashLicensesJar = path.resolve(__dirname, 'download/dash-licenses.jar');
2830
const dashLicensesSummary = path.resolve(__dirname, '../dependency-check-summary.txt');
2931
const dashLicensesBaseline = path.resolve(__dirname, '../dependency-check-baseline.json');
3032
const dashLicensesUrl = 'https://repo.eclipse.org/service/local/artifact/maven/redirect?r=dash-licenses&g=org.eclipse.dash&a=org.eclipse.dash.licenses&v=LATEST';
31-
const project = "ecd.theia";
3233

3334
// A Eclipse Foundation Gitlab Personal Access Token, generated by an Eclipse committer,
34-
// is required to use dash-licenses in "review" mode. For more information see:
35+
// is required to use dash-licenses in "review" mode. For more information see:
3536
// https://github.com/eclipse/dash-licenses#automatic-ip-team-review-requests
36-
// e.g. Set the token like so (bash shell):
37+
// e.g. Set the token like so (bash shell):
3738
// $> export DASH_LICENSES_PAT="<PAT>"
38-
const gitlabTokenDefined = env.DASH_LICENSES_PAT ? true : false;
39-
40-
if (autoReviewMode && !gitlabTokenDefined) {
41-
console.error("Please setup an Eclipse Foundation Gitlab Personal Access Token to run the license check in 'review' mode");
42-
console.error("It should be set in an environment variable named 'DASH_LICENSES_PAT'");
43-
process.exit(1);
44-
}
39+
const personalAccessToken = secret(process.env.DASH_LICENSES_PAT);
4540

4641
main().catch(error => {
4742
console.error(error);
4843
process.exit(1);
4944
});
5045

5146
async function main() {
47+
if (autoReviewMode && !personalAccessToken) {
48+
error('Please setup an Eclipse Foundation Gitlab Personal Access Token to run the license check in "review" mode');
49+
error('It should be set in an environment variable named "DASH_LICENSES_PAT"');
50+
process.exit(1);
51+
}
5252
if (!fs.existsSync(dashLicensesJar)) {
5353
info('Fetching dash-licenses...');
5454
fs.mkdirSync(path.dirname(dashLicensesJar), { recursive: true });
@@ -65,20 +65,14 @@ async function main() {
6565
fs.renameSync(dashLicensesSummary, `${dashLicensesSummary}.old`);
6666
}
6767
info('Running dash-licenses...');
68-
var args = ['-jar', dashLicensesJar, 'yarn.lock', '-batch', '50', '-timeout', '240', '-summary', dashLicensesSummary]
69-
if (autoReviewMode && gitlabTokenDefined) {
70-
info('using "review" mode');
71-
args.push('-review', '-token', '$DASH_LICENSES_PAT', '-project', project);
68+
const args = ['-jar', dashLicensesJar, 'yarn.lock', '-batch', '50', '-timeout', '240', '-summary', dashLicensesSummary];
69+
if (autoReviewMode && personalAccessToken) {
70+
info(`Using "review" mode for project: ${project}`);
71+
args.push('-review', '-token', personalAccessToken, '-project', project);
7272
}
73-
74-
// note: "shell:true" is required so we can reference the
75-
// Gitlab Personal Access Token through an environment variable
76-
// at invocation of "dash-license". This is necessary to avoid
77-
// leaking the token's value
78-
const dashError = getErrorFromStatus(spawn(
79-
'java', args,
80-
{ stdio: ['ignore', 'ignore', 'inherit'], shell: true }
81-
));
73+
const dashError = getErrorFromStatus(spawn('java', args, {
74+
stdio: ['ignore', 'ignore', 'inherit']
75+
}));
8276
if (dashError) {
8377
warn(dashError);
8478
}
@@ -172,25 +166,62 @@ function readBaseline(baseline) {
172166
process.exit(1);
173167
}
174168

169+
/**
170+
* @param {any} value
171+
* @returns {object | undefined}
172+
*/
173+
function secret(value) {
174+
if (value) {
175+
return { [kSECRET]: value };
176+
}
177+
}
178+
179+
/**
180+
* @param {(string | object)[]} array
181+
* @returns {string[]}
182+
*/
183+
function withSecrets(array) {
184+
return array.map(element => element[kSECRET] ?? element);
185+
}
186+
187+
/**
188+
* @param {(string | object)[]} array
189+
* @returns {string[]}
190+
*/
191+
function withoutSecrets(array) {
192+
return array.map(element => element[kSECRET] ? '***' : element);
193+
}
194+
175195
/**
176196
* Spawn a process. Exits with code 1 on spawn error (e.g. file not found).
177197
* @param {string} bin
178-
* @param {string[]} args
198+
* @param {(string | object)[]} args
179199
* @param {import('child_process').SpawnSyncOptions} [opts]
180200
* @returns {import('child_process').SpawnSyncReturns}
181201
*/
182202
function spawn(bin, args, opts = {}) {
183203
opts = { stdio: 'inherit', ...opts };
204+
function abort(spawnError, spawnBin, spawnArgs) {
205+
if (spawnBin && spawnArgs) {
206+
error(`Command: ${prettyCommand({ bin: spawnBin, args: spawnArgs })}`);
207+
}
208+
error(spawnError.stack ?? spawnError.message);
209+
process.exit(1);
210+
}
184211
/** @type {any} */
185-
const status = cp.spawnSync(bin, args, opts);
212+
let status;
213+
try {
214+
status = cp.spawnSync(bin, withSecrets(args), opts);
215+
} catch (spawnError) {
216+
abort(spawnError, bin, withoutSecrets(args));
217+
}
186218
// Add useful fields to the returned status object:
187219
status.bin = bin;
188-
status.args = args;
220+
status.args = withoutSecrets(args);
189221
status.opts = opts;
190222
// Abort on spawn error:
191223
if (status.error) {
192-
console.error(status.error);
193-
process.exit(1);
224+
abort(status.error, status.bin, status.args);
194225
}
195226
return status;
196227
}

0 commit comments

Comments
 (0)