@mirasen/license-gate 1.0.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/CHANGELOG.md +38 -0
- package/LICENSE +21 -0
- package/README.md +261 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.js +157 -0
- package/dist/commands/_shared.d.ts +17 -0
- package/dist/commands/_shared.js +33 -0
- package/dist/commands/check.d.ts +20 -0
- package/dist/commands/check.js +51 -0
- package/dist/commands/collect.d.ts +24 -0
- package/dist/commands/collect.js +31 -0
- package/dist/graph/load.d.ts +17 -0
- package/dist/graph/load.js +35 -0
- package/dist/graph/narrow.d.ts +24 -0
- package/dist/graph/narrow.js +114 -0
- package/dist/graph/record.d.ts +38 -0
- package/dist/graph/record.js +112 -0
- package/dist/graph/scope.d.ts +22 -0
- package/dist/graph/scope.js +88 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +23 -0
- package/dist/policy/allowed-hard.d.ts +17 -0
- package/dist/policy/allowed-hard.js +27 -0
- package/dist/policy/allowed-packages.d.ts +29 -0
- package/dist/policy/allowed-packages.js +137 -0
- package/dist/policy/evaluate.d.ts +30 -0
- package/dist/policy/evaluate.js +151 -0
- package/dist/policy/spdx-shape.d.ts +34 -0
- package/dist/policy/spdx-shape.js +76 -0
- package/dist/report/human.d.ts +12 -0
- package/dist/report/human.js +117 -0
- package/dist/report/json.d.ts +27 -0
- package/dist/report/json.js +53 -0
- package/dist/types.d.ts +151 -0
- package/dist/types.js +19 -0
- package/package.json +89 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal types for @mirasen/license-gate.
|
|
3
|
+
*
|
|
4
|
+
* Closed discriminated unions throughout. Reporters and command layers should
|
|
5
|
+
* exhaustively switch on `outcome` and `kind` so that adding a new variant is
|
|
6
|
+
* a compile-time signal across the codebase.
|
|
7
|
+
*/
|
|
8
|
+
/** Sentinel string used when a package's license cannot be determined from
|
|
9
|
+
* `package.json#license` (missing, empty, or non-string shape). */
|
|
10
|
+
export declare const LICENSE_COULD_NOT_DETERMINE = "could not determine";
|
|
11
|
+
export type LicenseCouldNotDetermine = typeof LICENSE_COULD_NOT_DETERMINE;
|
|
12
|
+
/** A flat record of one physically-installed package copy. `path` is the
|
|
13
|
+
* copy's location relative to the selected project root; two copies of the
|
|
14
|
+
* same `name@version` at different physical paths are still distinct
|
|
15
|
+
* records. */
|
|
16
|
+
export type InstalledPackageRecord = {
|
|
17
|
+
name: string;
|
|
18
|
+
version: string;
|
|
19
|
+
/** `${name}@${version}` — convenience composite. */
|
|
20
|
+
packageId: string;
|
|
21
|
+
/** Path of the installed copy relative to the selected project root,
|
|
22
|
+
* using POSIX-style `/` separators. The project root itself is exposed
|
|
23
|
+
* as `"."`. Internal graph/fs logic continues to use absolute paths;
|
|
24
|
+
* this field is the public, redaction-safe form. Physical placement of
|
|
25
|
+
* an installed copy (hoisted vs. workspace-local) is communicated
|
|
26
|
+
* entirely through this field. */
|
|
27
|
+
path: string;
|
|
28
|
+
/** Trimmed verbatim string from `package.json#license`, or the
|
|
29
|
+
* `LICENSE_COULD_NOT_DETERMINE` sentinel. Never normalised. */
|
|
30
|
+
license: string | LicenseCouldNotDetermine;
|
|
31
|
+
repository?: string;
|
|
32
|
+
publisher?: string;
|
|
33
|
+
email?: string;
|
|
34
|
+
};
|
|
35
|
+
/** A parsed `licenses/allowed-hard.txt`. Keys are the literal accepted license
|
|
36
|
+
* strings (after trim, dedup, and skipping blank/comment lines). */
|
|
37
|
+
export type AllowedHardList = ReadonlySet<string>;
|
|
38
|
+
/** A parsed rule from `licenses/allowed-packages.txt`. The original line text
|
|
39
|
+
* is preserved verbatim for inclusion in reports as `matchedPackageRule`. */
|
|
40
|
+
export type AllowedPackagesRule = {
|
|
41
|
+
kind: 'scope';
|
|
42
|
+
scope: string;
|
|
43
|
+
ruleText: string;
|
|
44
|
+
} | {
|
|
45
|
+
kind: 'package-version';
|
|
46
|
+
name: string;
|
|
47
|
+
version: string;
|
|
48
|
+
ruleText: string;
|
|
49
|
+
} | {
|
|
50
|
+
kind: 'scoped-package-version';
|
|
51
|
+
scope: string;
|
|
52
|
+
name: string;
|
|
53
|
+
version: string;
|
|
54
|
+
ruleText: string;
|
|
55
|
+
} | {
|
|
56
|
+
kind: 'package-name';
|
|
57
|
+
name: string;
|
|
58
|
+
ruleText: string;
|
|
59
|
+
} | {
|
|
60
|
+
kind: 'scoped-package-name';
|
|
61
|
+
scope: string;
|
|
62
|
+
name: string;
|
|
63
|
+
ruleText: string;
|
|
64
|
+
};
|
|
65
|
+
/** Parsed allowlists used by the policy evaluator. */
|
|
66
|
+
export type AllowedPackages = ReadonlyArray<AllowedPackagesRule>;
|
|
67
|
+
/** A policy decision for one installed package record. */
|
|
68
|
+
export type Decision = {
|
|
69
|
+
record: InstalledPackageRecord;
|
|
70
|
+
outcome: 'allowed-by-license';
|
|
71
|
+
} | {
|
|
72
|
+
record: InstalledPackageRecord;
|
|
73
|
+
outcome: 'allowed-by-scope-rule';
|
|
74
|
+
matchedPackageRule: string;
|
|
75
|
+
} | {
|
|
76
|
+
record: InstalledPackageRecord;
|
|
77
|
+
outcome: 'allowed-by-package-version-rule';
|
|
78
|
+
matchedPackageRule: string;
|
|
79
|
+
} | {
|
|
80
|
+
record: InstalledPackageRecord;
|
|
81
|
+
outcome: 'allowed-by-package-name-rule';
|
|
82
|
+
matchedPackageRule: string;
|
|
83
|
+
} | {
|
|
84
|
+
record: InstalledPackageRecord;
|
|
85
|
+
outcome: 'violation';
|
|
86
|
+
reason: ViolationReason;
|
|
87
|
+
};
|
|
88
|
+
/** The two top-level policy violation reasons. SPDX outcomes are diagnostic
|
|
89
|
+
* detail under `license-not-in-allowlist`. */
|
|
90
|
+
export type ViolationReason = {
|
|
91
|
+
kind: 'license-not-in-allowlist';
|
|
92
|
+
/** The original license string from package.json, verbatim. */
|
|
93
|
+
raw: string;
|
|
94
|
+
/** Diagnostic detail explaining how the SPDX evaluator landed here. */
|
|
95
|
+
detailCode?: 'literal-not-allowed-and-spdx-unparseable' | 'spdx-expression-not-satisfied';
|
|
96
|
+
/** Present iff `detailCode === "spdx-expression-not-satisfied"`. */
|
|
97
|
+
offendingLeaves?: string[];
|
|
98
|
+
} | {
|
|
99
|
+
kind: 'package-not-in-allowlist';
|
|
100
|
+
};
|
|
101
|
+
/** Configuration / runtime errors that halt execution before policy
|
|
102
|
+
* evaluation completes. They map to exit code 2. */
|
|
103
|
+
export type ConfigError = {
|
|
104
|
+
kind: 'missing-package-json';
|
|
105
|
+
cwd: string;
|
|
106
|
+
} | {
|
|
107
|
+
kind: 'missing-node-modules';
|
|
108
|
+
cwd: string;
|
|
109
|
+
} | {
|
|
110
|
+
kind: 'missing-allowed-hard-file';
|
|
111
|
+
path: string;
|
|
112
|
+
} | {
|
|
113
|
+
kind: 'invalid-package-override-rule';
|
|
114
|
+
path: string;
|
|
115
|
+
lineNumber: number;
|
|
116
|
+
line: string;
|
|
117
|
+
} | {
|
|
118
|
+
kind: 'invalid-workspace';
|
|
119
|
+
query: string;
|
|
120
|
+
reason: string;
|
|
121
|
+
} | {
|
|
122
|
+
kind: 'output-path-unwritable';
|
|
123
|
+
path: string;
|
|
124
|
+
cause: string;
|
|
125
|
+
} | {
|
|
126
|
+
kind: 'invalid-usage';
|
|
127
|
+
message: string;
|
|
128
|
+
};
|
|
129
|
+
/** Custom error wrapper so the CLI can recognise and exit 2 cleanly. */
|
|
130
|
+
export declare class LicenseGateConfigError extends Error {
|
|
131
|
+
readonly detail: ConfigError;
|
|
132
|
+
constructor(detail: ConfigError, message: string);
|
|
133
|
+
}
|
|
134
|
+
/** A `collect` row — the same as `InstalledPackageRecord` plus a flag for the
|
|
135
|
+
* project-root entry, which is included in `collect` output but skipped from
|
|
136
|
+
* `check` evaluation. */
|
|
137
|
+
export type CollectedRecord = InstalledPackageRecord & {
|
|
138
|
+
isProjectRoot?: boolean;
|
|
139
|
+
};
|
|
140
|
+
/** The result returned by the programmatic `check()` API. */
|
|
141
|
+
export type CheckResult = {
|
|
142
|
+
decisions: Decision[];
|
|
143
|
+
violations: Array<Extract<Decision, {
|
|
144
|
+
outcome: 'violation';
|
|
145
|
+
}>>;
|
|
146
|
+
skippedProjectRoot: InstalledPackageRecord | null;
|
|
147
|
+
};
|
|
148
|
+
/** The result returned by the programmatic `collect()` API. */
|
|
149
|
+
export type CollectResult = {
|
|
150
|
+
records: CollectedRecord[];
|
|
151
|
+
};
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal types for @mirasen/license-gate.
|
|
3
|
+
*
|
|
4
|
+
* Closed discriminated unions throughout. Reporters and command layers should
|
|
5
|
+
* exhaustively switch on `outcome` and `kind` so that adding a new variant is
|
|
6
|
+
* a compile-time signal across the codebase.
|
|
7
|
+
*/
|
|
8
|
+
/** Sentinel string used when a package's license cannot be determined from
|
|
9
|
+
* `package.json#license` (missing, empty, or non-string shape). */
|
|
10
|
+
export const LICENSE_COULD_NOT_DETERMINE = 'could not determine';
|
|
11
|
+
/** Custom error wrapper so the CLI can recognise and exit 2 cleanly. */
|
|
12
|
+
export class LicenseGateConfigError extends Error {
|
|
13
|
+
detail;
|
|
14
|
+
constructor(detail, message) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = 'LicenseGateConfigError';
|
|
17
|
+
this.detail = detail;
|
|
18
|
+
}
|
|
19
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mirasen/license-gate",
|
|
3
|
+
"description": "Strict local license policy gate for npm projects.",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "Mirasen"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"mirasen",
|
|
11
|
+
"license",
|
|
12
|
+
"license-gate",
|
|
13
|
+
"license-check",
|
|
14
|
+
"license-checker",
|
|
15
|
+
"license-policy",
|
|
16
|
+
"license-compliance",
|
|
17
|
+
"dependency-licenses",
|
|
18
|
+
"npm",
|
|
19
|
+
"workspaces",
|
|
20
|
+
"monorepo",
|
|
21
|
+
"spdx",
|
|
22
|
+
"ci",
|
|
23
|
+
"typescript"
|
|
24
|
+
],
|
|
25
|
+
"homepage": "https://mirasen.io/license-gate",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/mirasen-io/license-gate.git"
|
|
29
|
+
},
|
|
30
|
+
"bugs": {
|
|
31
|
+
"url": "https://github.com/mirasen-io/license-gate/issues"
|
|
32
|
+
},
|
|
33
|
+
"type": "module",
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"bin": {
|
|
36
|
+
"license-gate": "./dist/cli.js"
|
|
37
|
+
},
|
|
38
|
+
"exports": {
|
|
39
|
+
".": {
|
|
40
|
+
"types": "./dist/index.d.ts",
|
|
41
|
+
"import": "./dist/index.js",
|
|
42
|
+
"default": "./dist/index.js"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "rimraf ./dist && tsc --project tsconfig.json && npm run postbuild && npm run prepack",
|
|
47
|
+
"build:release": "rimraf ./dist && tsc --project tsconfig-release.json && npm run postbuild && npm run prepack",
|
|
48
|
+
"postbuild": "node scripts/postbuild.js",
|
|
49
|
+
"prepack": "publint",
|
|
50
|
+
"format": "prettier --write .",
|
|
51
|
+
"lint": "prettier --check . && eslint .",
|
|
52
|
+
"check": "tsc --project tsconfig.json --noEmit",
|
|
53
|
+
"check:test": "tsc --project tsconfig-test.json",
|
|
54
|
+
"test": "npm run check:test && vitest run --run",
|
|
55
|
+
"coverage": "npm run check:test && vitest run --coverage",
|
|
56
|
+
"changeset:version": "changeset version && npm install && git add --all",
|
|
57
|
+
"changeset:publish": "changeset publish"
|
|
58
|
+
},
|
|
59
|
+
"files": [
|
|
60
|
+
"dist",
|
|
61
|
+
"CHANGELOG.md",
|
|
62
|
+
"!dist/**/*.test.*",
|
|
63
|
+
"!dist/**/*.spec.*"
|
|
64
|
+
],
|
|
65
|
+
"dependencies": {
|
|
66
|
+
"@npmcli/arborist": "^9.7.0",
|
|
67
|
+
"spdx-expression-parse": "^4.0.0"
|
|
68
|
+
},
|
|
69
|
+
"devDependencies": {
|
|
70
|
+
"@changesets/cli": "^2.28.1",
|
|
71
|
+
"@eslint/compat": "^2.0.0",
|
|
72
|
+
"@eslint/js": "^10.0.1",
|
|
73
|
+
"@types/node": "^25.0.2",
|
|
74
|
+
"@types/npmcli__arborist": "^6.3.3",
|
|
75
|
+
"@vitest/coverage-v8": "^4.1.8",
|
|
76
|
+
"eslint": "^10.0.2",
|
|
77
|
+
"eslint-config-prettier": "^10.1.2",
|
|
78
|
+
"globals": "^17.4.0",
|
|
79
|
+
"prettier": "^3.5.3",
|
|
80
|
+
"publint": "^0.3.11",
|
|
81
|
+
"rimraf": "^6.0.1",
|
|
82
|
+
"typescript": "^6.0.3",
|
|
83
|
+
"typescript-eslint": "^8.57.2",
|
|
84
|
+
"vitest": "^4.0.3"
|
|
85
|
+
},
|
|
86
|
+
"engines": {
|
|
87
|
+
"node": ">=22.9.0"
|
|
88
|
+
}
|
|
89
|
+
}
|