@rio-cloud/rio-license-checker 1.1.7 → 1.2.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/README.md +65 -30
- package/dist/index.mjs +136 -83
- package/package.json +8 -7
package/README.md
CHANGED
|
@@ -1,58 +1,93 @@
|
|
|
1
|
-
# rio-license-checker
|
|
1
|
+
# [@rio-cloud/rio-license-checker](https://www.npmjs.com/package/@rio-cloud/rio-license-checker)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Helps checking third-party libraries' licenses according to RIO guidelines.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Usage
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
* if a license is found that is not in the whitelist: fail with nonzero exit code
|
|
11
|
-
* if all licenses are compliant: upload a license report to the central RIO license S3 bucket (only if the `--upload` flag is set)
|
|
7
|
+
```shell
|
|
8
|
+
# general usage information
|
|
9
|
+
npx @rio-cloud/rio-license-checker help
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
# information on the default "run-check" command
|
|
12
|
+
npx @rio-cloud/rio-license-checker help run-check
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
# information on the "download-whitelist" command
|
|
15
|
+
npx @rio-cloud/rio-license-checker help download-whitelist
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
# information on the "upload-report" command
|
|
18
|
+
npx @rio-cloud/rio-license-checker help upload-report
|
|
19
|
+
```
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
The `run-check` command is the default command. The command name is optional:
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
```shell
|
|
24
|
+
npx @rio-cloud/rio-license-checker run-check -a rio-example -s example-service -t npm-frontend
|
|
25
|
+
# is the same as
|
|
26
|
+
npx @rio-cloud/rio-license-checker -a rio-example -s example-service -t npm-frontend
|
|
27
|
+
```
|
|
24
28
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
*
|
|
29
|
+
## Automatic mode (a.k.a. `run-check`)
|
|
30
|
+
|
|
31
|
+
1. Downloads the appropriate license whitelist that's curated by the RIO Security Guild from a central location.
|
|
32
|
+
2. Orchestrates a 3rd-party license checking tool to inspect your project's dependencies.
|
|
33
|
+
* If any dependency is found with non-compliant license information, this tool will exit with a non-zero code.
|
|
34
|
+
* If all dependencies are okay: generate a report file containing the list of dependencies, their versions, and their
|
|
35
|
+
respective license information.
|
|
36
|
+
3. Uploads the report to a central location (optional; this is only done when the `--upload` flag is set).
|
|
30
37
|
|
|
31
|
-
### gradle
|
|
38
|
+
### `gradle`
|
|
32
39
|
|
|
33
40
|
* The underlying license report tool is [hierynomus/license-gradle-plugin](https://github.com/hierynomus/license-gradle-plugin).
|
|
34
41
|
* You need to *include & configure the plugin in your `build.gradle.kts`*.
|
|
35
42
|
* The output of the plugin is compared with the whitelist programmatically (as we used to do in the `build.gradle.kts`).
|
|
36
43
|
* For subprojects, you need a separate invocation of the license checker, where the directory points to the subproject.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
44
|
+
* Currently, only subprojects directly below the root project are supported (limited by where the checker looks for
|
|
45
|
+
the gradle wrapper).
|
|
46
|
+
* When doing so, take care to specify a different service name to prevent overwriting the license report of the root
|
|
47
|
+
project.
|
|
48
|
+
* Please see below for examples.
|
|
40
49
|
|
|
41
|
-
```
|
|
50
|
+
```shell
|
|
42
51
|
npx @rio-cloud/rio-license-checker -a rio-example -s example-service -t gradle
|
|
43
52
|
npx @rio-cloud/rio-license-checker -a rio-example -s example-service_sub-project -t gradle -d ./sub-project
|
|
44
53
|
```
|
|
45
54
|
|
|
46
|
-
|
|
55
|
+
### `npm-frontend` and `npm-backend`
|
|
47
56
|
|
|
48
|
-
|
|
57
|
+
* The underlying license checker tool is [license-checker-rseidelsohn](https://www.npmjs.com/package/license-checker-rseidelsohn).
|
|
58
|
+
* The license checker generates a report and compares the licenses to the passed whitelist.
|
|
59
|
+
* The application's own package is automatically excluded from the report, as it (usually) does not have a license.
|
|
60
|
+
* For testability reasons, we cannot use the programmatic interface of the tool. Instead, we call it as a subprocess via
|
|
61
|
+
`zx`.
|
|
62
|
+
* You can exclude dependencies by creating a `oss-licenses-ignore-packages.txt` file in the project directory.
|
|
63
|
+
* Note that this will _statically_ inspect the dependencies as defined in your `package.json`. Especially for frontends,
|
|
64
|
+
this might not be accurate enough. Check out the "manual" type for `npm-frontend-bundled` below.
|
|
65
|
+
|
|
66
|
+
## `download-whitelist`
|
|
67
|
+
|
|
68
|
+
To just download the appropriate whitelist file as-is without any processing or running the check, you can use the
|
|
69
|
+
`download-whitelist` command:
|
|
49
70
|
|
|
50
71
|
```shell
|
|
51
|
-
npx @rio-cloud/rio-license-checker -
|
|
72
|
+
npx @rio-cloud/rio-license-checker download-whitelist -t npm-frontend-bundled
|
|
52
73
|
```
|
|
53
74
|
|
|
54
|
-
|
|
75
|
+
Note that this will only work when the current session has access to AWS.
|
|
76
|
+
|
|
77
|
+
Also note that this only supports the "npm-frontend-bundled" type at the moment, which will save the whitelist as
|
|
78
|
+
`frontend-license-whitelist.json` in the project directory.
|
|
79
|
+
|
|
80
|
+
This command supports a `directory` and `verbose` option, as well. Check out the usage docs for more info.
|
|
81
|
+
|
|
82
|
+
## `upload-report`
|
|
83
|
+
|
|
84
|
+
If your license check is handled by another tool during the build, you can use the `upload-report` command to upload the
|
|
85
|
+
report output from a given file.
|
|
55
86
|
|
|
56
87
|
```shell
|
|
57
|
-
npx @rio-cloud/rio-license-checker -a rio-example -s example-service -t npm-frontend
|
|
88
|
+
npx @rio-cloud/rio-license-checker upload-report -a rio-example -s example-service -t npm-frontend-bundled -r ./build/libraries.json
|
|
58
89
|
```
|
|
90
|
+
|
|
91
|
+
Note that this only supports the "npm-frontend-bundled" type at the moment.
|
|
92
|
+
|
|
93
|
+
This command supports a `verbose` option, as well. Check out the usage docs for more info.
|
package/dist/index.mjs
CHANGED
|
@@ -1,35 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
3
|
+
import { Command, CommanderError, Option } from "commander";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
6
|
import logger from "loglevel";
|
|
7
7
|
import { GetObjectCommand, PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
|
|
8
8
|
import { GetParameterCommand, SSMClient } from "@aws-sdk/client-ssm";
|
|
9
|
-
import { $, fs, path } from "zx";
|
|
9
|
+
import { $, fs as fs$1, path as path$1 } from "zx";
|
|
10
10
|
|
|
11
|
-
//#region src/
|
|
12
|
-
var LicenseCheckError = class extends Error {
|
|
13
|
-
constructor(message) {
|
|
14
|
-
super(message);
|
|
15
|
-
this.name = "LicenseCheckError";
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
var CliArgsError = class extends Error {
|
|
19
|
-
constructor(message) {
|
|
20
|
-
super(message);
|
|
21
|
-
this.name = "CliArgsError";
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
let LicenseCheckType = /* @__PURE__ */ function(LicenseCheckType$1) {
|
|
25
|
-
LicenseCheckType$1["NPM_BACKEND"] = "npm-backend";
|
|
26
|
-
LicenseCheckType$1["NPM_FRONTEND"] = "npm-frontend";
|
|
27
|
-
LicenseCheckType$1["GRADLE"] = "gradle";
|
|
28
|
-
return LicenseCheckType$1;
|
|
29
|
-
}({});
|
|
30
|
-
|
|
31
|
-
//#endregion
|
|
32
|
-
//#region src/license-bucket.ts
|
|
11
|
+
//#region src/s3/license-bucket.ts
|
|
33
12
|
let ossLicensesBucketName;
|
|
34
13
|
const OSS_LICENSES_BUCKET_NAME_SSM_PARAMETER = "/config/oss-licenses/bucket-name";
|
|
35
14
|
const getOssLicensesBucketName = async () => {
|
|
@@ -43,27 +22,29 @@ const getOssLicensesBucketName = async () => {
|
|
|
43
22
|
}
|
|
44
23
|
return ossLicensesBucketName;
|
|
45
24
|
};
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
default: throw new Error(`Unknown whitelist type: ${checkType}`);
|
|
52
|
-
}
|
|
25
|
+
const s3Keys = {
|
|
26
|
+
"npm-frontend": "whitelist-npm-frontend.txt",
|
|
27
|
+
"npm-backend": "whitelist-npm-backend.txt",
|
|
28
|
+
gradle: "whitelist-gradle.txt",
|
|
29
|
+
"npm-frontend-bundled": "whitelist-npm-frontend-bundled.json"
|
|
53
30
|
};
|
|
54
|
-
const
|
|
31
|
+
const downloadWhitelistFile = async (checkType) => {
|
|
55
32
|
const getWhitelistObject = new GetObjectCommand({
|
|
56
33
|
Bucket: await getOssLicensesBucketName(),
|
|
57
|
-
Key:
|
|
34
|
+
Key: s3Keys[checkType]
|
|
58
35
|
});
|
|
59
36
|
const whitelistResponse = await new S3Client().send(getWhitelistObject);
|
|
60
37
|
if (!whitelistResponse.Body) throw new Error("No whitelist found");
|
|
61
|
-
return
|
|
38
|
+
return whitelistResponse.Body.transformToString();
|
|
39
|
+
};
|
|
40
|
+
const downloadAutomaticWhitelist = async (checkType) => {
|
|
41
|
+
return (await downloadWhitelistFile(checkType)).split("\n").map(stripQuotes).filter(removeEmptyLines);
|
|
62
42
|
};
|
|
63
43
|
const stripQuotes = (line) => {
|
|
64
44
|
if (line.startsWith("\"") && line.endsWith("\"")) return line.slice(1, -1);
|
|
65
45
|
return line;
|
|
66
46
|
};
|
|
47
|
+
const removeEmptyLines = (line) => line.trim().length > 0;
|
|
67
48
|
const uploadLicenseReport = async (accountName, serviceName, type, report) => {
|
|
68
49
|
const s3Client = new S3Client();
|
|
69
50
|
const putObjectCommand = new PutObjectCommand({
|
|
@@ -75,7 +56,45 @@ const uploadLicenseReport = async (accountName, serviceName, type, report) => {
|
|
|
75
56
|
};
|
|
76
57
|
|
|
77
58
|
//#endregion
|
|
78
|
-
//#region src/
|
|
59
|
+
//#region src/cli/downloadWhitelistFileCommand.ts
|
|
60
|
+
const downloadWhitelistFileCommand = new Command("download-whitelist").description("Download the license whitelist (experimental)").addOption(new Option("-t, --type <type>", "Type of the license check. (only supports \"npm-frontend-bundled\" for now)").makeOptionMandatory(true).choices(["npm-frontend-bundled"])).option("-d, --directory <directory>", "Directory to save the downloaded whitelist file to", process.cwd()).option("-v, --verbose", "Enable debug logging", false).action(async ({ type, directory, verbose }) => {
|
|
61
|
+
logger.setLevel(verbose ? "debug" : "info");
|
|
62
|
+
const licenseWhitelistFileContent = await downloadWhitelistFile(type);
|
|
63
|
+
const prettyJson = JSON.stringify(JSON.parse(licenseWhitelistFileContent), null, 2);
|
|
64
|
+
logger.debug(`Licenses whitelist:\n----------------\n${prettyJson}\n----------------`);
|
|
65
|
+
const whitelistFilePath = await saveWhitelistFile(directory, type, licenseWhitelistFileContent);
|
|
66
|
+
logger.info(`Successfully downloaded whitelist file into ${whitelistFilePath}`);
|
|
67
|
+
});
|
|
68
|
+
const whitelistFilenames = { "npm-frontend-bundled": "frontend-license-whitelist.json" };
|
|
69
|
+
const saveWhitelistFile = async (directory, checkType, content) => {
|
|
70
|
+
const filename = whitelistFilenames[checkType];
|
|
71
|
+
const filePath = path.join(directory, filename);
|
|
72
|
+
await fs.promises.writeFile(filePath, content, "utf8");
|
|
73
|
+
return filePath;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/types.ts
|
|
78
|
+
var LicenseCheckError = class extends Error {
|
|
79
|
+
constructor(message) {
|
|
80
|
+
super(message);
|
|
81
|
+
this.name = "LicenseCheckError";
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
var CliArgsError = class extends Error {
|
|
85
|
+
constructor(message) {
|
|
86
|
+
super(message);
|
|
87
|
+
this.name = "CliArgsError";
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
const automaticWhitelists = [
|
|
91
|
+
"npm-backend",
|
|
92
|
+
"npm-frontend",
|
|
93
|
+
"gradle"
|
|
94
|
+
];
|
|
95
|
+
|
|
96
|
+
//#endregion
|
|
97
|
+
//#region src/integrations/license-checker-gradle.ts
|
|
79
98
|
const normalizeLicenseReport = (report) => {
|
|
80
99
|
const sortedLicences = report.licences.map((license) => ({
|
|
81
100
|
...license,
|
|
@@ -110,8 +129,8 @@ const callGradleLicenseChecker = async ({ directory, licenseWhitelist }) => {
|
|
|
110
129
|
quiet: true
|
|
111
130
|
})`./${gradleWrapper} downloadLicenses`;
|
|
112
131
|
if (result.exitCode !== 0) throw new LicenseCheckError(`NOTE: This script requires the license-gradle-plugin to be configured, so that the script ./gradlew downloadLicenses works.\nSee https://github.com/hierynomus/license-gradle-plugin for details.\n${result.stderr.trimEnd()}`);
|
|
113
|
-
const licensesByLicenseNameFile = path.join(directory, "build", "reports", "license", "license-dependency.json");
|
|
114
|
-
const licensesByLicenseName = normalizeLicenseReport(JSON.parse(await fs.readFile(licensesByLicenseNameFile, "utf8")));
|
|
132
|
+
const licensesByLicenseNameFile = path$1.join(directory, "build", "reports", "license", "license-dependency.json");
|
|
133
|
+
const licensesByLicenseName = normalizeLicenseReport(JSON.parse(await fs$1.readFile(licensesByLicenseNameFile, "utf8")));
|
|
115
134
|
if (licensesByLicenseName.licences.length === 0) throw new LicenseCheckError("List of licenses is empty. It is highly unlikely your project has no dependencies. Check the configuration of the license-gradle-plugin.");
|
|
116
135
|
const allowedLicenses = new Set(licenseWhitelist);
|
|
117
136
|
const notAllowedLicenses = /* @__PURE__ */ new Set();
|
|
@@ -123,14 +142,14 @@ const callGradleLicenseChecker = async ({ directory, licenseWhitelist }) => {
|
|
|
123
142
|
return JSON.stringify(licensesByLicenseName, null, 2);
|
|
124
143
|
};
|
|
125
144
|
const discoverGradleWrapper = async (directory) => {
|
|
126
|
-
const gradleWrapperFile = path.join(directory, "gradlew");
|
|
127
|
-
if (fs.existsSync(gradleWrapperFile)) return "gradlew";
|
|
128
|
-
if (fs.existsSync(path.join(directory, "..", "gradlew"))) return "../gradlew";
|
|
145
|
+
const gradleWrapperFile = path$1.join(directory, "gradlew");
|
|
146
|
+
if (fs$1.existsSync(gradleWrapperFile)) return "gradlew";
|
|
147
|
+
if (fs$1.existsSync(path$1.join(directory, "..", "gradlew"))) return "../gradlew";
|
|
129
148
|
throw new LicenseCheckError(`Could not find gradle wrapper in ${directory} or the parent directory. Please ensure that the gradle wrapper is present.`);
|
|
130
149
|
};
|
|
131
150
|
|
|
132
151
|
//#endregion
|
|
133
|
-
//#region src/license-checker-npm.ts
|
|
152
|
+
//#region src/integrations/license-checker-npm.ts
|
|
134
153
|
const resolveLicenseCheckerPath = () => {
|
|
135
154
|
return createRequire(import.meta.url).resolve("license-checker-rseidelsohn/bin/license-checker-rseidelsohn");
|
|
136
155
|
};
|
|
@@ -157,60 +176,93 @@ const callNpmLicenseChecker = async ({ directory, licenseWhitelist, excludePacka
|
|
|
157
176
|
};
|
|
158
177
|
|
|
159
178
|
//#endregion
|
|
160
|
-
//#region src/cli.ts
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
const
|
|
179
|
+
//#region src/cli/validations.ts
|
|
180
|
+
const validateAccountName = (accountName) => {
|
|
181
|
+
if (!accountName.match(/^[a-zA-Z0-9-_]+$/)) throw new CliArgsError("Account name must only contain alphanumeric characters, hyphens and underscores");
|
|
182
|
+
};
|
|
183
|
+
const validateServiceName = (serviceName) => {
|
|
184
|
+
if (!serviceName.match(/^[a-zA-Z0-9-_]+$/)) throw new CliArgsError("Service name must only contain alphanumeric characters, hyphens and underscores");
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
//#endregion
|
|
188
|
+
//#region src/cli/runCheckCommand.ts
|
|
189
|
+
const runCheckCommand = new Command("run-check").summary("(default) Run an automated license check and optionally upload the report to S3").description("This is the default command to be used for backend and \"traditional\" frontend projects.\n\nWill download the whitelist, then perform the check and upload the report in one single step.").addOption(new Option("-t, --type <type>", "Type of the license check").makeOptionMandatory(true).choices(automaticWhitelists)).option("-a, --account-name <account>", "Account / context name").option("-s, --service-name <service>", "Service name").option("-d, --directory <directory>", "Directory of the project to check licenses for", process.cwd()).option("-u, --upload", "Upload license report to S3", false).option("-v, --verbose", "Enable debug logging", false).action(async (options) => {
|
|
190
|
+
logger.setLevel(options.verbose ? "debug" : "info");
|
|
191
|
+
const contextName = options.accountName;
|
|
192
|
+
const serviceName = options.serviceName;
|
|
193
|
+
const checkType = options.type;
|
|
194
|
+
const upload = options.upload;
|
|
195
|
+
if (upload) {
|
|
196
|
+
if (!contextName) throw new CliArgsError("Account name must not be empty when --upload is specified");
|
|
197
|
+
validateAccountName(contextName);
|
|
198
|
+
if (!serviceName) throw new CliArgsError("Service name must not be empty when --upload is specified");
|
|
199
|
+
validateServiceName(serviceName);
|
|
200
|
+
}
|
|
201
|
+
const licenseWhitelist = await downloadAutomaticWhitelist(checkType);
|
|
176
202
|
logger.debug(`Licenses whitelist:\n----------------\n${licenseWhitelist.join("\n")}\n----------------`);
|
|
177
203
|
let result;
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
204
|
+
switch (checkType) {
|
|
205
|
+
case "npm-backend":
|
|
206
|
+
case "npm-frontend": {
|
|
207
|
+
if (!fs.existsSync(path.join(options.directory, "node_modules"))) throw new Error("No node_modules directory found. Please run \"npm ci\" before using the license checker.");
|
|
208
|
+
const excludeForApplicationPackage = getExcludeForApplicationPackage(options.directory);
|
|
209
|
+
const ignorePackages = readIgnorePackages(options.directory);
|
|
210
|
+
result = await callNpmLicenseChecker({
|
|
211
|
+
directory: options.directory,
|
|
212
|
+
licenseWhitelist,
|
|
213
|
+
excludePackages: [excludeForApplicationPackage, ...ignorePackages]
|
|
214
|
+
});
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
case "gradle":
|
|
218
|
+
result = await callGradleLicenseChecker({
|
|
219
|
+
directory: options.directory,
|
|
220
|
+
licenseWhitelist
|
|
221
|
+
});
|
|
222
|
+
break;
|
|
223
|
+
default: throw new Error(`Unknown license check type: ${options.type}`);
|
|
224
|
+
}
|
|
192
225
|
logger.debug(`License report:\n${result.trimEnd()}`);
|
|
193
226
|
if (upload) {
|
|
194
227
|
await uploadLicenseReport(contextName, serviceName, checkType, result);
|
|
195
228
|
logger.info(`Uploaded license report for ${contextName}/${serviceName}_${checkType}`);
|
|
196
229
|
}
|
|
197
|
-
};
|
|
198
|
-
const parseType = (value) => {
|
|
199
|
-
for (const type of Object.values(LicenseCheckType)) if (type === value) return type;
|
|
200
|
-
throw new Error(`Unknown whitelist type: ${value}`);
|
|
201
|
-
};
|
|
230
|
+
});
|
|
202
231
|
const getExcludeForApplicationPackage = (directory) => {
|
|
203
|
-
const packageJson = JSON.parse(fs
|
|
232
|
+
const packageJson = JSON.parse(fs.readFileSync(path.join(directory, "package.json"), "utf8"));
|
|
204
233
|
const serviceVersion = packageJson.version;
|
|
205
234
|
return `${packageJson.name}@${serviceVersion}`;
|
|
206
235
|
};
|
|
207
236
|
const readIgnorePackages = (directory) => {
|
|
208
|
-
const ignorePackagesFile = path
|
|
237
|
+
const ignorePackagesFile = path.join(directory, "oss-licenses-ignore-packages.txt");
|
|
209
238
|
let ignorePackages = [];
|
|
210
|
-
if (fs
|
|
239
|
+
if (fs.existsSync(ignorePackagesFile)) ignorePackages = fs.readFileSync(ignorePackagesFile, "utf8").split("\n").filter((line) => line.trim() !== "");
|
|
211
240
|
return ignorePackages;
|
|
212
241
|
};
|
|
213
242
|
|
|
243
|
+
//#endregion
|
|
244
|
+
//#region src/cli/uploadReportCommand.ts
|
|
245
|
+
const uploadReportCommand = new Command("upload-report").description("Upload a license report (placeholder)").addOption(new Option("-t, --type <type>", "Type of the license check. (only supports \"npm-frontend-bundled\" for now)").makeOptionMandatory(true).choices(["npm-frontend-bundled"])).addOption(new Option("-a, --account-name <account>", "Account / context name").makeOptionMandatory(true)).addOption(new Option("-s, --service-name <service>", "Service name").makeOptionMandatory(true)).addOption(new Option("-r, --report-file <file>", "Path to the license report file").makeOptionMandatory(true)).option("-v, --verbose", "Enable debug logging", false).action(async ({ type, accountName, serviceName, reportFile, verbose }) => {
|
|
246
|
+
logger.setLevel(verbose ? "debug" : "info");
|
|
247
|
+
validateAccountName(accountName);
|
|
248
|
+
validateServiceName(serviceName);
|
|
249
|
+
const reportFileContent = await fs.promises.readFile(reportFile, "utf8");
|
|
250
|
+
logger.debug(`Report file:\n${reportFileContent}\n`);
|
|
251
|
+
await uploadLicenseReport(accountName, serviceName, type, reportFileContent);
|
|
252
|
+
logger.info(`Uploaded license report for ${accountName}/${serviceName}_${type}`);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
//#endregion
|
|
256
|
+
//#region src/cli.ts
|
|
257
|
+
const wrapCommand = (command) => command.exitOverride((error) => {
|
|
258
|
+
throw error;
|
|
259
|
+
});
|
|
260
|
+
const cli = (args) => {
|
|
261
|
+
const program = new Command();
|
|
262
|
+
program.name("npx @rio-cloud/rio-license-checker").addCommand(wrapCommand(runCheckCommand), { isDefault: true }).addCommand(wrapCommand(downloadWhitelistFileCommand)).addCommand(wrapCommand(uploadReportCommand)).addHelpText("after", `\n"run-check" is the default command if you don't specify one.\nRun "npx @rio-cloud/rio-license-checker help run-check" for details.`);
|
|
263
|
+
return program.parseAsync(args);
|
|
264
|
+
};
|
|
265
|
+
|
|
214
266
|
//#endregion
|
|
215
267
|
//#region src/index.ts
|
|
216
268
|
try {
|
|
@@ -222,8 +274,9 @@ try {
|
|
|
222
274
|
} else if (error instanceof CliArgsError) {
|
|
223
275
|
console.error(error.message);
|
|
224
276
|
process.exit(3);
|
|
225
|
-
} else
|
|
226
|
-
|
|
277
|
+
} else if (error instanceof CommanderError) process.exit(error.exitCode);
|
|
278
|
+
else {
|
|
279
|
+
console.error("unknown error", error);
|
|
227
280
|
process.exit(1);
|
|
228
281
|
}
|
|
229
282
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rio-cloud/rio-license-checker",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -14,8 +14,9 @@
|
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
16
|
"build": "tsdown",
|
|
17
|
+
"dev": "tsdown --watch ./src",
|
|
17
18
|
"pretest": "tsc",
|
|
18
|
-
"test": "vitest run
|
|
19
|
+
"test": "vitest run",
|
|
19
20
|
"vulnerability-check": "npm audit --registry https://registry.npmjs.org --parseable --audit-level=moderate --omit=dev",
|
|
20
21
|
"bump": "commit-and-tag-version -a --no-verify",
|
|
21
22
|
"release": "npm run test && npm run bump",
|
|
@@ -30,15 +31,15 @@
|
|
|
30
31
|
"dist"
|
|
31
32
|
],
|
|
32
33
|
"dependencies": {
|
|
33
|
-
"@aws-sdk/client-s3": "3.
|
|
34
|
-
"@aws-sdk/client-ssm": "3.
|
|
34
|
+
"@aws-sdk/client-s3": "3.937.0",
|
|
35
|
+
"@aws-sdk/client-ssm": "3.936.0",
|
|
35
36
|
"commander": "14.0.2",
|
|
36
37
|
"license-checker-rseidelsohn": "4.4.2",
|
|
37
38
|
"loglevel": "1.9.2",
|
|
38
39
|
"zx": "8.8.5"
|
|
39
40
|
},
|
|
40
41
|
"devDependencies": {
|
|
41
|
-
"@biomejs/biome": "2.
|
|
42
|
+
"@biomejs/biome": "2.3.7",
|
|
42
43
|
"@rio-cloud/biome-config-claid": "1.0.0",
|
|
43
44
|
"@tsconfig/node22": "22.0.5",
|
|
44
45
|
"@types/jest": "30.0.0",
|
|
@@ -48,9 +49,9 @@
|
|
|
48
49
|
"aws-sdk-client-mock-jest": "4.1.0",
|
|
49
50
|
"chalk": "5.6.2",
|
|
50
51
|
"commit-and-tag-version": "12.6.0",
|
|
51
|
-
"tsdown": "0.16.
|
|
52
|
+
"tsdown": "0.16.6",
|
|
52
53
|
"typescript": "5.9.3",
|
|
53
|
-
"vitest": "
|
|
54
|
+
"vitest": "4.0.14"
|
|
54
55
|
},
|
|
55
56
|
"overrides": {
|
|
56
57
|
"form-data": ">=4.0.4",
|