Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

js-green-licenses

Package Overview
Dependencies
Maintainers
1
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

js-green-licenses - npm Package Compare versions

Comparing version 2.0.1 to 3.0.0

4

build/src/checker.d.ts

@@ -31,3 +31,3 @@ /// <reference types="node" />

private greenLicenseExpr;
private whitelistedLicenses;
private allowlistedLicenses;
constructor({ dev, verbose }?: LicenseCheckerOptions);

@@ -45,3 +45,3 @@ on(event: 'non-green-license', listener: (arg: NonGreenLicense) => void): this;

private correctLicenseName;
private isPackageWhitelisted;
private isPackageAllowlisted;
private isGreenLicense;

@@ -48,0 +48,0 @@ private getPackageJson;

@@ -30,3 +30,3 @@ "use strict";

var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);

@@ -39,3 +39,3 @@ return result;

Object.defineProperty(exports, "__esModule", { value: true });
exports.LicenseChecker = void 0;
exports.LicenseChecker = exports.GitHubRepository = void 0;
const events_1 = require("events");

@@ -49,2 +49,3 @@ const fs = __importStar(require("fs"));

const util_1 = require("util");
const semver_1 = __importDefault(require("semver"));
const config = __importStar(require("./config"));

@@ -120,3 +121,3 @@ const github_1 = require("./github");

// List of license names that are not SPDX-conforming IDs but are allowed.
this.whitelistedLicenses = [];
this.allowlistedLicenses = [];
this.opts = { dev, verbose };

@@ -147,3 +148,3 @@ }

this.greenLicenseExpr = `(${validGreenLicenses.join(' OR ')})`;
this.whitelistedLicenses = invalidGreenLicenses;
this.allowlistedLicenses = invalidGreenLicenses;
this.processedPackages.clear();

@@ -184,5 +185,5 @@ this.failedPackages.clear();

}
isPackageWhitelisted(packageName) {
return (!!this.config.packageWhitelist &&
this.config.packageWhitelist.some(p => p === packageName));
isPackageAllowlisted(packageName) {
return (!!this.config.packageAllowlist &&
this.config.packageAllowlist.some(p => p === packageName));
}

@@ -193,5 +194,5 @@ isGreenLicense(license) {

const correctedName = this.correctLicenseName(license);
// `license` is not a valid or correctable SPDX id. Check the whitelist.
// `license` is not a valid or correctable SPDX id. Check the allowlist.
if (!correctedName) {
return this.whitelistedLicenses.some(l => l === license);
return this.allowlistedLicenses.some(l => l === license);
}

@@ -256,10 +257,14 @@ try {

async checkPackageJson(json, packageName, localDirectory, ...parents) {
const pj = package_json_file_1.ensurePackageJson(json);
if (!packageName) {
packageName = pj.name;
packageName = (packageName || json.name || 'undefined');
const isAllowlisted = this.isPackageAllowlisted(packageName);
if (isAllowlisted) {
json.version = semver_1.default.valid(json.version) ? json.version : '0.0.0';
}
if (pj.name !== packageName) {
console.warn(`Package name mismatch. Expected ${packageName}, but got ${pj.name}`);
else {
package_json_file_1.ensurePackageJson(json);
}
const pkgVersion = pj.version;
if (json.name !== packageName) {
console.warn(`Package name mismatch. Expected ${packageName}, but got ${json.name}`);
}
const pkgVersion = json.version;
const packageAndVersion = `${packageName}@${pkgVersion}`;

@@ -269,11 +274,11 @@ if (this.processedPackages.has(packageAndVersion))

this.processedPackages.add(packageAndVersion);
if (this.isPackageWhitelisted(packageName)) {
console.log(`${packageName} is whitelisted.`);
if (this.isPackageAllowlisted(packageName)) {
console.log(`${packageName} is allowlisted.`);
}
else {
const license = this.getLicense(pj);
const license = this.getLicense(json);
if (!this.isGreenLicense(license)) {
this.emit('non-green-license', {
packageName,
version: pkgVersion,
version: pkgVersion || 'undefined',
licenseName: license,

@@ -284,5 +289,5 @@ parentPackages: parents,

}
await this.checkLicensesForDeps(pj.dependencies, localDirectory, ...parents, packageAndVersion);
await this.checkLicensesForDeps(json.dependencies, localDirectory, ...parents, packageAndVersion);
if (this.opts.dev) {
await this.checkLicensesForDeps(pj.devDependencies, localDirectory, ...parents, packageAndVersion);
await this.checkLicensesForDeps(json.devDependencies, localDirectory, ...parents, packageAndVersion);
}

@@ -289,0 +294,0 @@ }

@@ -16,56 +16,61 @@ #!/usr/bin/env node

// limitations under the License.
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const argparse_1 = require("argparse");
const meow_1 = __importDefault(require("meow"));
const checker_1 = require("./checker");
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { version } = require('../../package.json');
const argParser = new argparse_1.ArgumentParser({
version,
addHelp: true,
description: 'License checker for npm modules',
const cli = meow_1.default(`
Usage
$ jsgl [-h] [-v] [--local <directory>] [--pr <github PR>] [--dev] [--verbose] [<package or package@version>]
Positional arguments:
<package or package@version>
Package name to check license for. Can include
version spec after @. E.g. foo@^1.2.3. Otherwise
latest.
Options
--help Show this help message and exit.
--local <directory>, -l <directory>
Check a local directory instead of public npm.
--version, -v Show program's version number and exit.
--pr <pr_number> Check a github pull request. Must be <owner>/<repo>/pull/<id>
--dev Also check devDependencies.
--verbose Verbose error outputs.
`, {
flags: {
local: {
type: 'string',
alias: 'l',
},
pr: {
type: 'string',
},
dev: {
type: 'boolean',
},
verbose: {
type: 'boolean',
},
},
});
argParser.addArgument(['package'], {
help: 'Package name to check license for. ' +
'Can include version spec after @. E.g. foo@^1.2.3. Otherwise latest.',
metavar: '<package or package@version>',
type: 'string',
nargs: '?',
});
argParser.addArgument(['--local', '-l'], {
help: 'Check a local directory instead of public npm.',
metavar: '<directory>',
type: 'string',
nargs: 1,
});
argParser.addArgument(['--pr'], {
help: 'Check a github pull request. Must be <owner>/<repo>/pull/<id>',
metavar: '<github PR>',
type: 'string',
nargs: 1,
});
argParser.addArgument(['--dev'], {
help: 'Also check devDependencies.',
nargs: 0,
});
argParser.addArgument(['--verbose'], {
help: 'Verbose error outputs.',
nargs: 0,
});
const args = argParser.parseArgs();
async function main() {
var _a;
const checker = new checker_1.LicenseChecker({
dev: !!args.dev,
verbose: !!args.verbose,
dev: !!cli.flags.dev,
verbose: !!cli.flags.verbose,
});
checker.setDefaultHandlers({ setExitCode: true });
if (args.local) {
await checker.checkLocalDirectory(args.local[0]);
if (cli.flags.local) {
await checker.checkLocalDirectory(cli.flags.local);
}
else if (args.pr) {
const { repo, prId } = checker.prPathToGitHubRepoAndId(args.pr[0]);
else if (cli.flags.pr) {
console.log(cli.flags.pr);
const { repo, prId } = checker.prPathToGitHubRepoAndId(cli.flags.pr);
const { mergeCommitSha } = await repo.getPRCommits(prId);
await checker.checkGitHubPR(repo, mergeCommitSha);
}
else if (args.package) {
await checker.checkRemotePackage(args.package);
else if ((_a = cli.input) === null || _a === void 0 ? void 0 : _a.length) {
await checker.checkRemotePackage(cli.input[0]);
}

@@ -72,0 +77,0 @@ else {

import { GitHubRepository } from './github';
export interface Config {
greenLicenses?: string[];
packageWhitelist?: string[];
packageAllowlist?: string[];
}
export declare function getLocalConfig(directory: string): Promise<Config | null>;
export declare function getGitHubConfig(repo: GitHubRepository, commitSha: string): Promise<Config | null>;

@@ -30,3 +30,3 @@ "use strict";

var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);

@@ -52,3 +52,3 @@ return result;

return (isStringArray(config.greenLicenses) &&
isStringArray(config.packageWhitelist));
isStringArray(config.packageAllowlist));
}

@@ -55,0 +55,0 @@ function ensureConfig(obj) {

@@ -31,139 +31,136 @@ "use strict";

}
let GitHubRepository = /** @class */ (() => {
class GitHubRepository {
constructor(owner, repo) {
this.pathPrefix = path_1.posix.join('/repos', owner, repo);
class GitHubRepository {
constructor(owner, repo) {
this.pathPrefix = path_1.posix.join('/repos', owner, repo);
}
getAxiosConfig(authToken) {
return authToken ? { headers: { Authorization: `token ${authToken}` } } : {};
}
async apiGet(path, params) {
const url = new url_1.URL('https://api.github.com');
url.pathname = path_1.posix.join(this.pathPrefix, path);
if (params) {
Object.keys(params).forEach(key => {
url.searchParams.set(key, params[key]);
});
}
getAxiosConfig(authToken) {
return authToken ? { headers: { Authorization: `token ${authToken}` } } : {};
}
async apiGet(path, params) {
const url = new url_1.URL('https://api.github.com');
url.pathname = path_1.posix.join(this.pathPrefix, path);
if (params) {
Object.keys(params).forEach(key => {
url.searchParams.set(key, params[key]);
});
const resp = await gaxios_1.request({
method: 'GET',
url: url.href,
...this.getAxiosConfig(),
});
return resp.data;
}
async apiPost(path, body) {
const url = new url_1.URL('https://api.github.com');
url.pathname = path_1.posix.join(this.pathPrefix, path);
const resp = await gaxios_1.request({
method: 'POST',
url: url.href,
data: body,
...this.getAxiosConfig(),
});
return resp.data;
}
async getPRCommits(prId, attemptCount = 1) {
let answer = await this.apiGet(path_1.posix.join('pulls', prId.toString()));
answer = ensureSingleResponseData(answer);
if (answer.mergeable === null) {
if (attemptCount > GitHubRepository.MAX_PR_COMMIT_RETRIES) {
throw new Error(`Tried ${attemptCount} times but the mergeable field is not set. Giving up`);
}
const resp = await gaxios_1.request({
method: 'GET',
url: url.href,
...this.getAxiosConfig(),
console.log('The `mergeable` field is not set yet. Will retry later.');
return new Promise(resolve => {
setTimeout(async () => {
resolve(await this.getPRCommits(prId, attemptCount + 1));
}, 1000);
});
return resp.data;
}
async apiPost(path, body) {
const url = new url_1.URL('https://api.github.com');
url.pathname = path_1.posix.join(this.pathPrefix, path);
const resp = await gaxios_1.request({
method: 'POST',
url: url.href,
data: body,
...this.getAxiosConfig(),
});
return resp.data;
else if (!answer.mergeable) {
throw new Error('PR is not mergeable');
}
async getPRCommits(prId, attemptCount = 1) {
let answer = await this.apiGet(path_1.posix.join('pulls', prId.toString()));
answer = ensureSingleResponseData(answer);
if (answer.mergeable === null) {
if (attemptCount > GitHubRepository.MAX_PR_COMMIT_RETRIES) {
throw new Error(`Tried ${attemptCount} times but the mergeable field is not set. Giving up`);
}
console.log('The `mergeable` field is not set yet. Will retry later.');
return new Promise(resolve => {
setTimeout(async () => {
resolve(await this.getPRCommits(prId, attemptCount + 1));
}, 1000);
});
}
else if (!answer.mergeable) {
throw new Error('PR is not mergeable');
}
const mergeCommitSha = answer.merge_commit_sha;
if (!mergeCommitSha) {
throw new Error('Merge commit SHA is not found');
}
const headCommitSha = answer.head && answer.head.sha;
if (!headCommitSha) {
throw new Error('HEAD commit SHA is not found');
}
return { mergeCommitSha, headCommitSha };
const mergeCommitSha = answer.merge_commit_sha;
if (!mergeCommitSha) {
throw new Error('Merge commit SHA is not found');
}
async createPRReview(prId, commitSha, body) {
await this.apiPost(path_1.posix.join('pulls', prId.toString(), 'reviews'), {
commit_id: commitSha,
body,
event: 'COMMENT',
});
const headCommitSha = answer.head && answer.head.sha;
if (!headCommitSha) {
throw new Error('HEAD commit SHA is not found');
}
async setCommitStatus(commitSha, status, description, context) {
await this.apiPost(path_1.posix.join('statuses', commitSha), {
state: status,
description,
context,
return { mergeCommitSha, headCommitSha };
}
async createPRReview(prId, commitSha, body) {
await this.apiPost(path_1.posix.join('pulls', prId.toString(), 'reviews'), {
commit_id: commitSha,
body,
event: 'COMMENT',
});
}
async setCommitStatus(commitSha, status, description, context) {
await this.apiPost(path_1.posix.join('statuses', commitSha), {
state: status,
description,
context,
});
}
async getFileContent(commitSha, path) {
let answer;
try {
answer = await this.apiGet(path_1.posix.join('contents', path), {
ref: commitSha,
});
}
async getFileContent(commitSha, path) {
let answer;
try {
answer = await this.apiGet(path_1.posix.join('contents', path), {
ref: commitSha,
});
}
catch (_a) {
return null;
}
answer = ensureSingleResponseData(answer);
if (answer.content === undefined) {
throw new Error(`Content of ${path} not found`);
}
const content = Buffer.from(answer.content, 'base64').toString();
return content;
catch (_a) {
return null;
}
async getSinglePackageJson(dir, commitSha) {
const content = await this.getFileContent(commitSha, path_1.posix.join(dir, 'package.json'));
if (!content) {
return null;
}
const filePath = path_1.posix.join('/', dir, 'package.json');
return { filePath, content };
answer = ensureSingleResponseData(answer);
if (answer.content === undefined) {
throw new Error(`Content of ${path} not found`);
}
async getPackageJsonFiles(commitSha) {
const packageJsons = [];
// Find the top-level package.json first.
const pj = await this.getSinglePackageJson('', commitSha);
if (pj !== null) {
packageJsons.push(pj);
}
// Find `packages/<name>/package.json` files in case this is a monorepo.
let answer;
try {
answer = await this.apiGet('contents/packages', { ref: commitSha });
}
catch (_a) {
// Not a monorepo. Return just the top-level package.json.
return packageJsons;
}
if (!isSingleResponseData(answer)) {
// Response is an array, which means there's the `packages` directory and
// this is a monorepo. Find package.json from each directory under
// `packages`.
for (const entry of answer) {
if (entry.type === 'dir' && entry.name) {
const pj = await this.getSinglePackageJson(path_1.posix.join('packages', entry.name), commitSha);
if (pj !== null) {
packageJsons.push(pj);
}
const content = Buffer.from(answer.content, 'base64').toString();
return content;
}
async getSinglePackageJson(dir, commitSha) {
const content = await this.getFileContent(commitSha, path_1.posix.join(dir, 'package.json'));
if (!content) {
return null;
}
const filePath = path_1.posix.join('/', dir, 'package.json');
return { filePath, content };
}
async getPackageJsonFiles(commitSha) {
const packageJsons = [];
// Find the top-level package.json first.
const pj = await this.getSinglePackageJson('', commitSha);
if (pj !== null) {
packageJsons.push(pj);
}
// Find `packages/<name>/package.json` files in case this is a monorepo.
let answer;
try {
answer = await this.apiGet('contents/packages', { ref: commitSha });
}
catch (_a) {
// Not a monorepo. Return just the top-level package.json.
return packageJsons;
}
if (!isSingleResponseData(answer)) {
// Response is an array, which means there's the `packages` directory and
// this is a monorepo. Find package.json from each directory under
// `packages`.
for (const entry of answer) {
if (entry.type === 'dir' && entry.name) {
const pj = await this.getSinglePackageJson(path_1.posix.join('packages', entry.name), commitSha);
if (pj !== null) {
packageJsons.push(pj);
}
}
}
return packageJsons;
}
return packageJsons;
}
// How many times to retry PR commit retrieval until giving up.
GitHubRepository.MAX_PR_COMMIT_RETRIES = 10;
return GitHubRepository;
})();
}
exports.GitHubRepository = GitHubRepository;
// How many times to retry PR commit retrieval until giving up.
GitHubRepository.MAX_PR_COMMIT_RETRIES = 10;
//# sourceMappingURL=github.js.map

@@ -7,2 +7,20 @@ # Changelog

## [3.0.0](https://www.github.com/google/js-green-licenses/compare/v2.0.1...v3.0.0) (2021-01-22)
### ⚠ BREAKING CHANGES
* The `packageWhitelist` field has been renamed to `packageAllowlist`.
### Features
* added skipping of package.json check if package is whitelisted (resolves [#118](https://www.github.com/google/js-green-licenses/issues/118)) ([#136](https://www.github.com/google/js-green-licenses/issues/136)) ([0d95d18](https://www.github.com/google/js-green-licenses/commit/0d95d18eb146bb8a003e741789729cf88d7e759c))
* use allowlist for allowed licenses ([#153](https://www.github.com/google/js-green-licenses/issues/153)) ([d24827f](https://www.github.com/google/js-green-licenses/commit/d24827fa25d66020f876412f706a9dfbd8b56a98))
### Bug Fixes
* **deps:** update dependency gaxios to v4 ([#148](https://www.github.com/google/js-green-licenses/issues/148)) ([9b66f9c](https://www.github.com/google/js-green-licenses/commit/9b66f9cd1768c4a7f5dde454192a9dc0f0d10c8f))
* **deps:** use meow for argument parsing ([#156](https://www.github.com/google/js-green-licenses/issues/156)) ([ae07bc8](https://www.github.com/google/js-green-licenses/commit/ae07bc81f21a7be753424c4dfc3fed4c6ee69060))
### [2.0.1](https://www.github.com/google/js-green-licenses/compare/v2.0.0...v2.0.1) (2020-05-18)

@@ -9,0 +27,0 @@

{
"name": "js-green-licenses",
"version": "2.0.1",
"version": "3.0.0",
"description": "JavaScript package.json license checker",

@@ -41,6 +41,7 @@ "main": "build/src/checker.js",

"dependencies": {
"argparse": "^1.0.10",
"gaxios": "^3.0.0",
"gaxios": "^4.0.0",
"meow": "^9.0.0",
"npm-package-arg": "^8.0.0",
"package-json": "^6.0.0",
"semver": "^7.3.2",
"spdx-correct": "^3.0.0",

@@ -51,21 +52,20 @@ "spdx-satisfies": "^5.0.0",

"devDependencies": {
"@types/argparse": "^1.0.33",
"@types/mocha": "^7.0.0",
"@types/nock": "^10.0.0",
"@types/mocha": "^8.0.0",
"@types/node": "^10.0.1",
"@types/npm-package-arg": "^6.0.0",
"@types/proxyquire": "^1.3.28",
"@types/semver": "^7.2.0",
"@types/spdx-correct": "^2.0.0",
"@types/spdx-satisfies": "^0.1.0",
"@types/strip-json-comments": "0.0.30",
"c8": "^7.0.0",
"gts": "^2.0.0",
"c8": "^7.4.0",
"gts": "^3.0.0",
"inline-fixtures": "^1.1.0",
"make-dir": "^3.0.0",
"mocha": "^7.0.0",
"mocha": "^8.2.1",
"mock-fs": "^4.4.2",
"nock": "^12.0.0",
"nock": "^13.0.0",
"proxyquire": "^2.0.1",
"typescript": "~3.9.0"
"typescript": "~4.1.0"
}
}
# JavaScript package.json License Checker
[![NPM Version][npm-image]][npm-url]
[![npm Version][npm-image]][npm-url]
[![CI][actions-image]][actions-url]

@@ -57,4 +57,4 @@ [![Dependency Status][david-image]][david-url]

This tool checks licenses for 1) an already published NPM package, 2) a local
directory, or 3) a GitHub pull request. For checking an NPM package, you can
This tool checks licenses for 1) an already published npm package, 2) a local
directory, or 3) a GitHub pull request. For checking an npm package, you can
just pass the package name (optionally together with the version) as the

@@ -127,3 +127,3 @@ argument. To check a local directory, you should pass the `--local

You can also whitelist some NPM packages and they will be considered "green"
You can also allowlist some npm packages and they will be considered "green"
even when they have non-green licenses or no licenses. It's useful when

@@ -133,3 +133,3 @@ `jsgl` is unable to verify the validness of a certain package's license for

`package.json` but has a separate `LICENSE` file, `jsgl` can't verify that.
You can whitelist that package to make `jsgl` not complain about that
You can allowlist that package to make `jsgl` not complain about that
package.

@@ -147,3 +147,3 @@

],
"packageWhitelist": [
"packageAllowlist": [
/* packages considered ok */

@@ -160,3 +160,3 @@ "foo",

The `greenLicenses` section is for the custom license list and the
`packageWhitelist` section is for the package whitelist.
`packageAllowlist` section is for the package allowlist.

@@ -166,3 +166,3 @@ Note that comments are allowed in `js-green-licenses.json`.

The configuration file must be located in the top-level directory of a
repository for `--local` and `--pr`. When checking remote NPM packages,
repository for `--local` and `--pr`. When checking remote npm packages,
`jsgl` tries to locate the configuration file in the current local directory

@@ -244,3 +244,3 @@ from which `jsgl` is invoked.

`--pr` is passed. It retrieves and checks the `package.json` for the
remote NPM package and recursively checks its dependencies.
remote npm package and recursively checks its dependencies.

@@ -320,3 +320,3 @@ This method reads in the configuration from the `js-green-licenses.json`

[actions-url]: https://github.com/google/js-green-licenses/actions
[codecov-image]: https://codecov.io/gh/google/js-green-licenses/branch/master/graph/badge.svg
[codecov-image]: https://codecov.io/gh/google/js-green-licenses/branch/main/graph/badge.svg
[codecov-url]: https://codecov.io/gh/google/js-green-licenses

@@ -323,0 +323,0 @@ [david-image]: https://david-dm.org/google/js-green-licenses.svg

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc