@ploaness/cli 1.6.0 → 1.8.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/dist/bin.js +20 -11
- package/dist/bin.js.map +1 -1
- package/dist/checks/blocklist.d.ts.map +1 -1
- package/dist/checks/blocklist.js +2 -1
- package/dist/checks/blocklist.js.map +1 -1
- package/dist/checks/compliance-report.d.ts +5 -0
- package/dist/checks/compliance-report.d.ts.map +1 -0
- package/dist/checks/compliance-report.js +15 -0
- package/dist/checks/compliance-report.js.map +1 -0
- package/dist/checks/conventions.d.ts.map +1 -1
- package/dist/checks/conventions.js +2 -5
- package/dist/checks/conventions.js.map +1 -1
- package/dist/checks/dependencies.d.ts +16 -0
- package/dist/checks/dependencies.d.ts.map +1 -1
- package/dist/checks/dependencies.js +30 -13
- package/dist/checks/dependencies.js.map +1 -1
- package/dist/checks/environment.d.ts +2 -2
- package/dist/checks/environment.d.ts.map +1 -1
- package/dist/checks/environment.js.map +1 -1
- package/dist/checks/images.d.ts.map +1 -1
- package/dist/checks/images.js +8 -4
- package/dist/checks/images.js.map +1 -1
- package/dist/checks/install.d.ts +3 -3
- package/dist/checks/install.d.ts.map +1 -1
- package/dist/checks/install.js +3 -3
- package/dist/checks/install.js.map +1 -1
- package/dist/checks/license-inventory.d.ts +14 -0
- package/dist/checks/license-inventory.d.ts.map +1 -0
- package/dist/checks/license-inventory.js +15 -0
- package/dist/checks/license-inventory.js.map +1 -0
- package/dist/checks/oci-images.d.ts +6 -0
- package/dist/checks/oci-images.d.ts.map +1 -0
- package/dist/checks/oci-images.js +63 -0
- package/dist/checks/oci-images.js.map +1 -0
- package/dist/checks/oxlint.d.ts.map +1 -1
- package/dist/checks/oxlint.js +1 -1
- package/dist/checks/oxlint.js.map +1 -1
- package/dist/checks/payload.d.ts.map +1 -1
- package/dist/checks/payload.js +12 -7
- package/dist/checks/payload.js.map +1 -1
- package/dist/checks/references.d.ts +2 -2
- package/dist/checks/references.d.ts.map +1 -1
- package/dist/checks/references.js.map +1 -1
- package/dist/checks/sbom.d.ts +5 -0
- package/dist/checks/sbom.d.ts.map +1 -0
- package/dist/checks/sbom.js +12 -0
- package/dist/checks/sbom.js.map +1 -0
- package/dist/checks/tests.d.ts +2 -0
- package/dist/checks/tests.d.ts.map +1 -1
- package/dist/checks/tests.js +16 -6
- package/dist/checks/tests.js.map +1 -1
- package/dist/checks/wiring.d.ts.map +1 -1
- package/dist/checks/wiring.js +3 -3
- package/dist/checks/wiring.js.map +1 -1
- package/dist/commands/commit-message.d.ts +1 -1
- package/dist/commands/commit-message.d.ts.map +1 -1
- package/dist/commands/commit-message.js +2 -2
- package/dist/commands/commit-message.js.map +1 -1
- package/dist/commands/compliance-report.d.ts +4 -0
- package/dist/commands/compliance-report.d.ts.map +1 -0
- package/dist/commands/compliance-report.js +25 -0
- package/dist/commands/compliance-report.js.map +1 -0
- package/dist/commands/sbom.d.ts +4 -0
- package/dist/commands/sbom.d.ts.map +1 -0
- package/dist/commands/sbom.js +13 -0
- package/dist/commands/sbom.js.map +1 -0
- package/dist/commands/verify.d.ts +3 -3
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +40 -12
- package/dist/commands/verify.js.map +1 -1
- package/dist/compliance-report.d.ts +25 -0
- package/dist/compliance-report.d.ts.map +1 -0
- package/dist/compliance-report.js +278 -0
- package/dist/compliance-report.js.map +1 -0
- package/dist/gates.d.ts +3 -3
- package/dist/gates.d.ts.map +1 -1
- package/dist/gates.js +11 -1
- package/dist/gates.js.map +1 -1
- package/dist/output-directory.d.ts +23 -0
- package/dist/output-directory.d.ts.map +1 -0
- package/dist/output-directory.js +46 -0
- package/dist/output-directory.js.map +1 -0
- package/dist/probes/payload-defaults.probe.js +2 -2
- package/dist/probes/payload-defaults.probe.js.map +1 -1
- package/dist/sbom.d.ts +5 -0
- package/dist/sbom.d.ts.map +1 -0
- package/dist/sbom.js +171 -0
- package/dist/sbom.js.map +1 -0
- package/package.json +11 -7
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Repository } from '../context.js';
|
|
2
|
+
/** Produce a release-associated workspace inventory without changing the source or its installation. */
|
|
3
|
+
export declare const sbom: (repository: Repository, arguments_: readonly string[]) => number;
|
|
4
|
+
//# sourceMappingURL=sbom.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sbom.d.ts","sourceRoot":"","sources":["../../src/commands/sbom.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAG/C,wGAAwG;AACxG,eAAO,MAAM,IAAI,GAAI,YAAY,UAAU,EAAE,YAAY,SAAS,MAAM,EAAE,KAAG,MAQ5E,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { parseSbomArguments } from '@ploaness/governance';
|
|
2
|
+
import { writeSbom } from '../sbom.js';
|
|
3
|
+
/** Produce a release-associated workspace inventory without changing the source or its installation. */
|
|
4
|
+
export const sbom = (repository, arguments_) => {
|
|
5
|
+
const options = parseSbomArguments(arguments_);
|
|
6
|
+
if (options === undefined) {
|
|
7
|
+
throw new Error('usage: ploaness sbom --artifact <file> [--artifact <file> ...] [--output <directory>]');
|
|
8
|
+
}
|
|
9
|
+
const destination = writeSbom(repository, options);
|
|
10
|
+
console.info(`SBOM and release metadata written to ${destination}`);
|
|
11
|
+
return 0;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=sbom.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sbom.js","sourceRoot":"","sources":["../../src/commands/sbom.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAsB,MAAM,sBAAsB,CAAA;AAE7E,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAEtC,wGAAwG;AACxG,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,UAAsB,EAAE,UAA6B,EAAU,EAAE;IACpF,MAAM,OAAO,GAA8B,kBAAkB,CAAC,UAAU,CAAC,CAAA;IACzE,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,uFAAuF,CAAC,CAAA;IAC1G,CAAC;IACD,MAAM,WAAW,GAAW,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;IAC1D,OAAO,CAAC,IAAI,CAAC,wCAAwC,WAAW,EAAE,CAAC,CAAA;IACnE,OAAO,CAAC,CAAA;AACV,CAAC,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Repository } from '../context.js';
|
|
2
2
|
import { type PlannedGate } from '../gates.js';
|
|
3
3
|
/**
|
|
4
4
|
* Run Default or Extended verification.
|
|
@@ -6,7 +6,7 @@ import { type PlannedGate } from '../gates.js';
|
|
|
6
6
|
* @param isExtended whether to include the history, build, bundle, and end-to-end gates.
|
|
7
7
|
* @returns the process exit code.
|
|
8
8
|
*/
|
|
9
|
-
export declare const verify: (repository:
|
|
9
|
+
export declare const verify: (repository: Repository, isExtended: boolean) => Promise<number>;
|
|
10
10
|
/**
|
|
11
11
|
* Run one gate by identifier. A single gate is a debugging aid, never a verdict.
|
|
12
12
|
* @param repository the resolved repository environment.
|
|
@@ -14,5 +14,5 @@ export declare const verify: (repository: Repo, isExtended: boolean) => Promise<
|
|
|
14
14
|
* @param isVerbose whether to print what the gate's tool wrote, not only the verdict it produced.
|
|
15
15
|
* @returns the process exit code.
|
|
16
16
|
*/
|
|
17
|
-
export declare const verifyOne: (repository:
|
|
17
|
+
export declare const verifyOne: (repository: Repository, planned: PlannedGate, isVerbose?: boolean) => Promise<number>;
|
|
18
18
|
//# sourceMappingURL=verify.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/commands/verify.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/commands/verify.ts"],"names":[],"mappings":"AAKA,OAAO,EAA8B,KAAK,UAAU,EAAE,MAAM,eAAe,CAAA;AAE3E,OAAO,EAAuB,KAAK,WAAW,EAAW,MAAM,aAAa,CAAA;AAuG5E;;;;;GAKG;AACH,eAAO,MAAM,MAAM,GAAU,YAAY,UAAU,EAAE,YAAY,OAAO,KAAG,OAAO,CAAC,MAAM,CAOxF,CAAA;AAsBD;;;;;;GAMG;AACH,eAAO,MAAM,SAAS,GACpB,YAAY,UAAU,EACtB,SAAS,WAAW,EACpB,YAAW,OAAe,KACzB,OAAO,CAAC,MAAM,CAWhB,CAAA"}
|
package/dist/commands/verify.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
// Verification: run the gates in order and report one verdict. A gate that throws is a failed gate, not
|
|
2
2
|
// a crashed run, because a tool that cannot start is indistinguishable from a tool that found a defect:
|
|
3
3
|
// either way the project is not verified.
|
|
4
|
-
import { endsRun } from '@ploaness/governance';
|
|
4
|
+
import { canRunBuiltBrowser, endsRun, recordBuildSuccess } from '@ploaness/governance';
|
|
5
|
+
import { browserReadiness } from '../checks/tests.js';
|
|
6
|
+
import { hasOwnRuntime } from '../context.js';
|
|
5
7
|
import { failed } from '../exec.js';
|
|
6
|
-
import { planFor } from '../gates.js';
|
|
8
|
+
import { gateById, planFor } from '../gates.js';
|
|
7
9
|
import { beginGate, reportGate, reportHalt, reportHeader, reportNote, reportOutput, reportVerdict, } from '../report.js';
|
|
8
10
|
const asMessage = (error) => (error instanceof Error ? error.message : String(error));
|
|
9
11
|
// The union is narrowed exactly here, once. Everywhere else a gate is a gate; this is the one place
|
|
10
12
|
// that has to know a repository-scope gate is handed the repository and a member-scope gate its member.
|
|
11
|
-
const invoke = async (planned,
|
|
13
|
+
const invoke = async (planned, repository) => {
|
|
12
14
|
if (planned.gate.scope === 'repository') {
|
|
13
|
-
return await planned.gate.run(
|
|
15
|
+
return await planned.gate.run(repository);
|
|
14
16
|
}
|
|
15
17
|
const member = planned.member;
|
|
16
18
|
if (member === undefined) {
|
|
@@ -20,18 +22,25 @@ const invoke = async (planned, repo) => {
|
|
|
20
22
|
}
|
|
21
23
|
return await planned.gate.run(member);
|
|
22
24
|
};
|
|
23
|
-
const runGate = async (planned,
|
|
25
|
+
const runGate = async (planned, repository, built) => {
|
|
24
26
|
try {
|
|
25
|
-
|
|
27
|
+
const step = { gateId: planned.gate.id, member: planned.member?.path };
|
|
28
|
+
const isRuntime = planned.member !== undefined && hasOwnRuntime(planned.member);
|
|
29
|
+
if (built !== undefined && !canRunBuiltBrowser(step, isRuntime, built)) {
|
|
30
|
+
return failed('this run did not establish a production build for the browser suite', [
|
|
31
|
+
'repair the build failure and rerun full verification',
|
|
32
|
+
]);
|
|
33
|
+
}
|
|
34
|
+
return await invoke(planned, repository);
|
|
26
35
|
}
|
|
27
36
|
catch (error) {
|
|
28
37
|
return failed(`the ${planned.gate.id} gate could not run`, [asMessage(error)]);
|
|
29
38
|
}
|
|
30
39
|
};
|
|
31
40
|
/** Time one gate and package it as the outcome the report layer prints. */
|
|
32
|
-
const timeGate = async (planned,
|
|
41
|
+
const timeGate = async (planned, repository, built) => {
|
|
33
42
|
const started = Date.now();
|
|
34
|
-
const result = await runGate(planned,
|
|
43
|
+
const result = await runGate(planned, repository, built);
|
|
35
44
|
return {
|
|
36
45
|
gate: planned.gate,
|
|
37
46
|
result,
|
|
@@ -44,24 +53,25 @@ const timeGate = async (planned, repo) => {
|
|
|
44
53
|
const identifierWidth = (planned) => planned.reduce((widest, step) => Math.max(widest, step.gate.id.length), 0);
|
|
45
54
|
// A sequence with an exit rather than a plain map, because a run does not always reach the end. The
|
|
46
55
|
// rule that decides is `endsRun`, in governance; this supplies the outcome and the mode.
|
|
47
|
-
const runPlan = async (planned,
|
|
56
|
+
const runPlan = async (planned, repository, width, built = new Set()) => {
|
|
48
57
|
const [step, ...rest] = planned;
|
|
49
58
|
if (step === undefined) {
|
|
50
59
|
return [];
|
|
51
60
|
}
|
|
52
61
|
beginGate(step.gate, width);
|
|
53
|
-
const outcome = await timeGate(step,
|
|
62
|
+
const outcome = await timeGate(step, repository, built);
|
|
54
63
|
reportGate(outcome, width);
|
|
55
64
|
const isPrecondition = step.gate.isPrecondition === true;
|
|
56
65
|
if (endsRun({
|
|
57
66
|
isFailure: !outcome.result.ok,
|
|
58
67
|
isPrecondition,
|
|
59
|
-
isEnforced:
|
|
68
|
+
isEnforced: repository.isEnforced,
|
|
60
69
|
})) {
|
|
61
70
|
reportHalt(step.gate, rest.length, isPrecondition);
|
|
62
71
|
return [outcome];
|
|
63
72
|
}
|
|
64
|
-
|
|
73
|
+
const nextBuilt = recordBuildSuccess(built, { gateId: step.gate.id, member: step.member?.path }, outcome.result.ok);
|
|
74
|
+
return [outcome, ...(await runPlan(rest, repository, width, nextBuilt))];
|
|
65
75
|
};
|
|
66
76
|
/**
|
|
67
77
|
* Run Default or Extended verification.
|
|
@@ -77,6 +87,21 @@ export const verify = async (repository, isExtended) => {
|
|
|
77
87
|
const outcomes = await runPlan(planned, repository, width);
|
|
78
88
|
return reportVerdict(outcomes, isExtended, repository.isEnforced, Date.now() - started);
|
|
79
89
|
};
|
|
90
|
+
const hasBrowserBuild = async (repository, planned) => {
|
|
91
|
+
const started = Date.now();
|
|
92
|
+
const readiness = planned.member === undefined ? undefined : await browserReadiness(planned.member);
|
|
93
|
+
if (readiness !== undefined) {
|
|
94
|
+
reportGate({ gate: planned.gate, result: readiness, durationMs: Date.now() - started, member: planned.member?.path }, planned.gate.id.length);
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
const buildGate = gateById('build');
|
|
98
|
+
if (buildGate === undefined) {
|
|
99
|
+
throw new Error('the e2e prerequisite build gate is missing');
|
|
100
|
+
}
|
|
101
|
+
const built = await timeGate({ gate: buildGate, member: planned.member }, repository);
|
|
102
|
+
reportGate(built, buildGate.id.length);
|
|
103
|
+
return built.result.ok;
|
|
104
|
+
};
|
|
80
105
|
/**
|
|
81
106
|
* Run one gate by identifier. A single gate is a debugging aid, never a verdict.
|
|
82
107
|
* @param repository the resolved repository environment.
|
|
@@ -85,6 +110,9 @@ export const verify = async (repository, isExtended) => {
|
|
|
85
110
|
* @returns the process exit code.
|
|
86
111
|
*/
|
|
87
112
|
export const verifyOne = async (repository, planned, isVerbose = false) => {
|
|
113
|
+
if (planned.gate.id === 'e2e' && !(await hasBrowserBuild(repository, planned))) {
|
|
114
|
+
return 1;
|
|
115
|
+
}
|
|
88
116
|
const outcome = await timeGate(planned, repository);
|
|
89
117
|
reportGate(outcome, planned.gate.id.length);
|
|
90
118
|
if (isVerbose) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/commands/verify.ts"],"names":[],"mappings":"AAAA,wGAAwG;AACxG,wGAAwG;AACxG,0CAA0C;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/commands/verify.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type NoticeFile } from '@ploaness/governance';
|
|
2
|
+
import { type Repository } from './context.js';
|
|
3
|
+
/** Where the report is written and which SBOM it embeds. */
|
|
4
|
+
export interface ComplianceReportOptions {
|
|
5
|
+
readonly output: string;
|
|
6
|
+
readonly sbomDirectory: string;
|
|
7
|
+
}
|
|
8
|
+
/** What a run of the report writer produced. */
|
|
9
|
+
export interface WrittenReport {
|
|
10
|
+
readonly directory: string;
|
|
11
|
+
readonly files: readonly string[];
|
|
12
|
+
/** Why no PDF was rendered, when none was. */
|
|
13
|
+
readonly pdfSkipped: string | undefined;
|
|
14
|
+
}
|
|
15
|
+
/** The licence and notice files one installed package directory ships, never through a link. */
|
|
16
|
+
export declare const noticeFilesIn: (directory: string) => readonly NoticeFile[];
|
|
17
|
+
/**
|
|
18
|
+
* Write the compliance report for the current tree: one HTML document, and its PDF rendering when
|
|
19
|
+
* the project has a browser to print with.
|
|
20
|
+
* @param repository the repository the report describes.
|
|
21
|
+
* @param options where to write it and which SBOM to embed.
|
|
22
|
+
* @returns the files written.
|
|
23
|
+
*/
|
|
24
|
+
export declare const writeComplianceReport: (repository: Repository, options: ComplianceReportOptions) => Promise<WrittenReport>;
|
|
25
|
+
//# sourceMappingURL=compliance-report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compliance-report.d.ts","sourceRoot":"","sources":["../src/compliance-report.ts"],"names":[],"mappings":"AAKA,OAAO,EAaL,KAAK,UAAU,EAShB,MAAM,sBAAsB,CAAA;AAG7B,OAAO,EAAqB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAA;AAKjE,4DAA4D;AAC5D,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;CAC/B;AAED,gDAAgD;AAChD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,8CAA8C;IAC9C,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;CACxC;AA+CD,gGAAgG;AAChG,eAAO,MAAM,aAAa,GAAI,WAAW,MAAM,KAAG,SAAS,UAAU,EAU/D,CAAA;AA4QN;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,GAChC,YAAY,UAAU,EACtB,SAAS,uBAAuB,KAC/B,OAAO,CAAC,aAAa,CA4BvB,CAAA"}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { existsSync, lstatSync, readdirSync, readFileSync, unlinkSync } from 'node:fs';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { pathToFileURL } from 'node:url';
|
|
6
|
+
import { asOptionalText, asText, buildComplianceReport, classifyVulnerabilities, contentsPages, coordinateOf, directDependencyNames, HARNESS_EXCEPTIONS, isArray, outlinePages, parseLicenseInventory, REPORT_FILE_PREFIX, readKey, renderComplianceReport, reportFileStem, } from '@ploaness/governance';
|
|
7
|
+
import { readAdvisories } from './checks/dependencies.js';
|
|
8
|
+
import { runLicenseInventory } from './checks/license-inventory.js';
|
|
9
|
+
import { cliDirectory, git } from './context.js';
|
|
10
|
+
import { ignoredOutputDirectory, publishFiles } from './output-directory.js';
|
|
11
|
+
import { workingTreeFingerprint } from './working-tree.js';
|
|
12
|
+
// A licence file larger than this is not a licence file; reading it whole would put a bundle or a data
|
|
13
|
+
// file into the report.
|
|
14
|
+
const MAX_NOTICE_BYTES = 262_144;
|
|
15
|
+
const PLAYWRIGHT = '@playwright/test';
|
|
16
|
+
// A licence file is named LICENSE, LICENCE, COPYING or NOTICE, optionally with a variant such as `-MIT` or
|
|
17
|
+
// `-3RD-PARTY`, and optionally with a text or licence-name extension. The report leaves the project, so any
|
|
18
|
+
// other file that merely starts with one of those words, such as `license.key`, is never read.
|
|
19
|
+
const NOTICE_BASE = /^(?:licen[cs]e|copying|notice)(?:-[a-z\d]{1,20}){0,3}$/iu;
|
|
20
|
+
const NOTICE_EXTENSIONS = new Set([
|
|
21
|
+
'',
|
|
22
|
+
'md',
|
|
23
|
+
'markdown',
|
|
24
|
+
'txt',
|
|
25
|
+
'rst',
|
|
26
|
+
'mit',
|
|
27
|
+
'bsd',
|
|
28
|
+
'isc',
|
|
29
|
+
'apache',
|
|
30
|
+
'apache2',
|
|
31
|
+
]);
|
|
32
|
+
// A variant names a licence or a scope, never a credential: `license-key.txt` is a key, not a licence.
|
|
33
|
+
const CREDENTIAL_WORD = /key|secret|token|private|password|credential|cert/iu;
|
|
34
|
+
const isNoticeName = (name) => {
|
|
35
|
+
const dot = name.indexOf('.');
|
|
36
|
+
const base = dot === -1 ? name : name.slice(0, dot);
|
|
37
|
+
const extension = dot === -1 ? '' : name.slice(dot + 1).toLowerCase();
|
|
38
|
+
return NOTICE_BASE.test(base) && !CREDENTIAL_WORD.test(base) && NOTICE_EXTENSIONS.has(extension);
|
|
39
|
+
};
|
|
40
|
+
const readJsonFile = (file) => JSON.parse(readFileSync(file, 'utf8'));
|
|
41
|
+
const sha256 = (content) => createHash('sha256').update(content).digest('hex');
|
|
42
|
+
const readInventory = (repository, isProductionOnly) => {
|
|
43
|
+
const result = runLicenseInventory(repository, isProductionOnly);
|
|
44
|
+
const packages = result.code === 0 ? parseLicenseInventory(result.stdout) : undefined;
|
|
45
|
+
if (packages === undefined) {
|
|
46
|
+
throw new Error(`the license inventory could not be read for the compliance report: ${result.output}`);
|
|
47
|
+
}
|
|
48
|
+
return packages;
|
|
49
|
+
};
|
|
50
|
+
/** The licence and notice files one installed package directory ships, never through a link. */
|
|
51
|
+
export const noticeFilesIn = (directory) => (existsSync(directory) ? readdirSync(directory) : [])
|
|
52
|
+
.filter((name) => isNoticeName(name))
|
|
53
|
+
.toSorted((left, right) => left.localeCompare(right))
|
|
54
|
+
.flatMap((name) => {
|
|
55
|
+
const file = path.join(directory, name);
|
|
56
|
+
// `lstat`, so a symbolic link is never followed: the report leaves the project, and a package that
|
|
57
|
+
// ships its licence as a link could otherwise copy any file the build can read into it.
|
|
58
|
+
const stat = lstatSync(file);
|
|
59
|
+
return stat.isFile() && stat.size <= MAX_NOTICE_BYTES ? [{ name, text: readFileSync(file, 'utf8') }] : [];
|
|
60
|
+
});
|
|
61
|
+
// Each installed directory names its own version, which is how a notice is tied to one coordinate
|
|
62
|
+
// rather than to every version the inventory groups under the package name.
|
|
63
|
+
const noticesOf = (entry) => entry.paths.map((directory) => {
|
|
64
|
+
const manifest = path.join(directory, 'package.json');
|
|
65
|
+
const version = existsSync(manifest) ? asText(readKey(readJsonFile(manifest), 'version')) : '';
|
|
66
|
+
return {
|
|
67
|
+
coordinate: version.length > 0 && entry.versions.length > 0 ? coordinateOf(entry.name, version) : entry.name,
|
|
68
|
+
files: noticeFilesIn(directory),
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
// The SBOM must describe the tree the report describes. A report built on an inventory from an earlier
|
|
72
|
+
// tree would print a hash that matches its download and still certify the wrong dependencies.
|
|
73
|
+
const readCurrentSbom = (directory, fingerprint) => {
|
|
74
|
+
const bomFile = path.join(directory, 'bom.cdx.json');
|
|
75
|
+
const releaseFile = path.join(directory, 'release.json');
|
|
76
|
+
if (!(existsSync(bomFile) && existsSync(releaseFile))) {
|
|
77
|
+
throw new Error(`no SBOM in ${directory}; run the sbom gate or \`ploaness compliance-report\` first`);
|
|
78
|
+
}
|
|
79
|
+
const text = readFileSync(bomFile, 'utf8');
|
|
80
|
+
const release = JSON.parse(readFileSync(releaseFile, 'utf8'));
|
|
81
|
+
if (readKey(release, 'sourceFingerprint') !== fingerprint || readKey(release, 'sbomSha256') !== sha256(text)) {
|
|
82
|
+
throw new Error(`the SBOM in ${directory} does not describe the current tree; run the sbom gate or ` +
|
|
83
|
+
'`ploaness compliance-report` to regenerate it');
|
|
84
|
+
}
|
|
85
|
+
const components = readKey(JSON.parse(text), 'components');
|
|
86
|
+
return {
|
|
87
|
+
text,
|
|
88
|
+
sha256: sha256(text),
|
|
89
|
+
components: isArray(components) ? components.length : 0,
|
|
90
|
+
generator: asText(readKey(readKey(release, 'generator'), 'image')),
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
// The typefaces the report is set in, from the OFL-licensed Fontsource packages this package depends on.
|
|
94
|
+
// Only the Latin subset is embedded. A character outside it falls back to the next face in the stack.
|
|
95
|
+
const FONT_FILES = [
|
|
96
|
+
{
|
|
97
|
+
family: 'Source Serif 4',
|
|
98
|
+
style: 'normal',
|
|
99
|
+
weight: '200 900',
|
|
100
|
+
url: import.meta.resolve('@fontsource-variable/source-serif-4/files/source-serif-4-latin-wght-normal.woff2'),
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
family: 'Source Serif 4',
|
|
104
|
+
style: 'italic',
|
|
105
|
+
weight: '200 900',
|
|
106
|
+
url: import.meta.resolve('@fontsource-variable/source-serif-4/files/source-serif-4-latin-wght-italic.woff2'),
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
family: 'Playfair Display',
|
|
110
|
+
style: 'normal',
|
|
111
|
+
weight: '400 900',
|
|
112
|
+
url: import.meta.resolve('@fontsource-variable/playfair-display/files/playfair-display-latin-wght-normal.woff2'),
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
family: 'Source Code Pro',
|
|
116
|
+
style: 'normal',
|
|
117
|
+
weight: '200 900',
|
|
118
|
+
url: import.meta.resolve('@fontsource-variable/source-code-pro/files/source-code-pro-latin-wght-normal.woff2'),
|
|
119
|
+
},
|
|
120
|
+
];
|
|
121
|
+
const embeddedFonts = () => FONT_FILES.map((font) => ({
|
|
122
|
+
family: font.family,
|
|
123
|
+
style: font.style,
|
|
124
|
+
weight: font.weight,
|
|
125
|
+
data: readFileSync(new URL(font.url)).toString('base64'),
|
|
126
|
+
}));
|
|
127
|
+
const harnessVersion = () => {
|
|
128
|
+
const manifest = readJsonFile(path.join(cliDirectory(), 'package.json'));
|
|
129
|
+
return asText(readKey(manifest, 'version'));
|
|
130
|
+
};
|
|
131
|
+
const projectName = (repository) => {
|
|
132
|
+
const declared = asText(readKey(repository.packageJson, 'name'));
|
|
133
|
+
return declared.length > 0 ? declared : path.basename(repository.root);
|
|
134
|
+
};
|
|
135
|
+
// An ISO timestamp up to whole seconds, `YYYY-MM-DDTHH:MM:SS`.
|
|
136
|
+
const SECONDS_PRECISION = 19;
|
|
137
|
+
const timestamp = () => `${new Date().toISOString().slice(0, SECONDS_PRECISION).replace('T', ' ')} UTC`;
|
|
138
|
+
const assemble = (repository, fingerprint, sbom) => {
|
|
139
|
+
const lockfile = path.join(repository.root, 'pnpm-lock.yaml');
|
|
140
|
+
const packages = readInventory(repository, false);
|
|
141
|
+
const production = readInventory(repository, true);
|
|
142
|
+
const auditedAt = timestamp();
|
|
143
|
+
const reading = readAdvisories(repository);
|
|
144
|
+
if (reading.kind === 'unreachable') {
|
|
145
|
+
throw new Error(['the advisory database was unreachable, so the report cannot state vulnerabilities', ...reading.findings].join('\n'));
|
|
146
|
+
}
|
|
147
|
+
return buildComplianceReport({
|
|
148
|
+
projectName: projectName(repository),
|
|
149
|
+
projectDescription: asOptionalText(readKey(repository.packageJson, 'description')),
|
|
150
|
+
source: {
|
|
151
|
+
commit: git(repository, ['rev-parse', 'HEAD']),
|
|
152
|
+
isDirty: git(repository, ['status', '--porcelain']).length > 0,
|
|
153
|
+
fingerprint,
|
|
154
|
+
lockfileSha256: sha256(readFileSync(lockfile)),
|
|
155
|
+
},
|
|
156
|
+
generatedAt: timestamp(),
|
|
157
|
+
harnessVersion: harnessVersion(),
|
|
158
|
+
packages,
|
|
159
|
+
production,
|
|
160
|
+
directNames: directDependencyNames(repository.projects.map((project) => project.packageJson)),
|
|
161
|
+
vulnerabilities: classifyVulnerabilities(reading.advisories, repository.settings.vulnerabilityAllowlist, repository.settings.vulnerabilitySeverity, HARNESS_EXCEPTIONS),
|
|
162
|
+
advisoryRecords: reading.advisories.length,
|
|
163
|
+
auditedAt,
|
|
164
|
+
sbom: { sha256: sbom.sha256, components: sbom.components, generator: sbom.generator },
|
|
165
|
+
notices: packages.flatMap((entry) => noticesOf(entry)),
|
|
166
|
+
});
|
|
167
|
+
};
|
|
168
|
+
// The browser is the project's own Playwright, which full verification already requires for the
|
|
169
|
+
// end-to-end suite. A repository with no member that declares it - a library - has no browser to
|
|
170
|
+
// print with, and gets the HTML alone rather than a browser installed behind its back.
|
|
171
|
+
// Asked of the manifest before the resolver: pnpm's hidden hoist makes a package resolvable from a member
|
|
172
|
+
// that never declared it, and a report must not depend on which other member happened to install it.
|
|
173
|
+
const declaresPlaywright = (project) => directDependencyNames([project.packageJson]).includes(PLAYWRIGHT);
|
|
174
|
+
const playwrightEntry = (repository) => repository.projects
|
|
175
|
+
.filter((project) => declaresPlaywright(project))
|
|
176
|
+
.flatMap((project) => {
|
|
177
|
+
try {
|
|
178
|
+
return [createRequire(path.join(repository.root, project.path, 'package.json')).resolve(PLAYWRIGHT)];
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return [];
|
|
182
|
+
}
|
|
183
|
+
})[0];
|
|
184
|
+
// `@playwright/test` exports its `test` function as the module, with the browser launchers as properties
|
|
185
|
+
// of that function, so a lookup that accepts only plain objects never finds them.
|
|
186
|
+
const isObjectLike = (value) => value !== null && (typeof value === 'object' || typeof value === 'function');
|
|
187
|
+
const chromiumOf = (value) => isObjectLike(value) && 'chromium' in value ? value.chromium : undefined;
|
|
188
|
+
const launchOf = (value) => (isObjectLike(value) && 'launch' in value ? value.launch : undefined);
|
|
189
|
+
const defaultOf = (value) => (isObjectLike(value) && 'default' in value ? value.default : undefined);
|
|
190
|
+
const isPlaywright = (candidate) => typeof launchOf(chromiumOf(candidate)) === 'function';
|
|
191
|
+
const launchChromium = async (playwright) => {
|
|
192
|
+
try {
|
|
193
|
+
return await playwright.chromium.launch();
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
throw new Error(`Chromium could not be launched to print the PDF: ${String(error)}\n` +
|
|
197
|
+
'install it with `pnpm exec playwright install chromium`', { cause: error });
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
const PDF_OPTIONS = {
|
|
201
|
+
format: 'A4',
|
|
202
|
+
printBackground: true,
|
|
203
|
+
preferCSSPageSize: true,
|
|
204
|
+
outline: true,
|
|
205
|
+
tagged: true,
|
|
206
|
+
};
|
|
207
|
+
// Evaluated in the page. The numbers only occupy slots the contents already reserve, so writing them does
|
|
208
|
+
// not move a heading to another page and the second print matches the first.
|
|
209
|
+
const fillContentsPages = (pages) => `for (const [id, page] of ${JSON.stringify([...pages])}) {` +
|
|
210
|
+
"const slot = document.querySelector('#toc .page[data-for=\"' + id + '\"]'); " +
|
|
211
|
+
'if (slot) slot.textContent = String(page) }';
|
|
212
|
+
const printPdf = async (entry, html) => {
|
|
213
|
+
const loaded = await import(pathToFileURL(entry).href);
|
|
214
|
+
const playwright = isPlaywright(loaded) ? loaded : defaultOf(loaded);
|
|
215
|
+
if (!isPlaywright(playwright)) {
|
|
216
|
+
throw new Error(`${entry} does not export Playwright's chromium launcher`);
|
|
217
|
+
}
|
|
218
|
+
const browser = await launchChromium(playwright);
|
|
219
|
+
try {
|
|
220
|
+
const page = await browser.newPage();
|
|
221
|
+
await page.setContent(html, { waitUntil: 'load' });
|
|
222
|
+
await page.emulateMedia({ media: 'print' });
|
|
223
|
+
const draft = await page.pdf(PDF_OPTIONS);
|
|
224
|
+
const pages = contentsPages(outlinePages(Buffer.from(draft).toString('latin1')));
|
|
225
|
+
if (pages.size === 0) {
|
|
226
|
+
return draft;
|
|
227
|
+
}
|
|
228
|
+
await page.evaluate(fillContentsPages(pages));
|
|
229
|
+
return await page.pdf(PDF_OPTIONS);
|
|
230
|
+
}
|
|
231
|
+
finally {
|
|
232
|
+
await browser.close();
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
// Reports from earlier commits are removed, so the directory holds exactly one report to send.
|
|
236
|
+
const removeEarlierReports = (directory, keep) => {
|
|
237
|
+
const present = existsSync(directory) ? readdirSync(directory) : [];
|
|
238
|
+
for (const name of present) {
|
|
239
|
+
if (name.startsWith(REPORT_FILE_PREFIX) && /\.(?:html|pdf)$/u.test(name) && !keep.includes(name)) {
|
|
240
|
+
unlinkSync(path.join(directory, name));
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
/**
|
|
245
|
+
* Write the compliance report for the current tree: one HTML document, and its PDF rendering when
|
|
246
|
+
* the project has a browser to print with.
|
|
247
|
+
* @param repository the repository the report describes.
|
|
248
|
+
* @param options where to write it and which SBOM to embed.
|
|
249
|
+
* @returns the files written.
|
|
250
|
+
*/
|
|
251
|
+
export const writeComplianceReport = async (repository, options) => {
|
|
252
|
+
const before = workingTreeFingerprint(repository.root);
|
|
253
|
+
const sbom = readCurrentSbom(path.resolve(repository.root, options.sbomDirectory), before);
|
|
254
|
+
const report = assemble(repository, before, sbom);
|
|
255
|
+
const stem = reportFileStem(report.projectName, report.source.commit);
|
|
256
|
+
const htmlName = `${stem}.html`;
|
|
257
|
+
const pdfName = `${stem}.pdf`;
|
|
258
|
+
const directory = ignoredOutputDirectory(repository, options.output, {
|
|
259
|
+
files: [htmlName, pdfName, `${htmlName}.tmp`, `${pdfName}.tmp`],
|
|
260
|
+
label: 'Compliance report',
|
|
261
|
+
});
|
|
262
|
+
const html = renderComplianceReport(report, { sbom: sbom.text, fonts: embeddedFonts() }, stem);
|
|
263
|
+
const entry = playwrightEntry(repository);
|
|
264
|
+
const pdf = entry === undefined ? undefined : await printPdf(entry, html);
|
|
265
|
+
if (before !== workingTreeFingerprint(repository.root)) {
|
|
266
|
+
throw new Error('the authored tree changed while the compliance report was generated; regenerate it');
|
|
267
|
+
}
|
|
268
|
+
const outputs = pdf === undefined ? { [htmlName]: html } : { [htmlName]: html, [pdfName]: pdf };
|
|
269
|
+
const written = Object.keys(outputs);
|
|
270
|
+
removeEarlierReports(directory, written);
|
|
271
|
+
publishFiles(directory, outputs);
|
|
272
|
+
return {
|
|
273
|
+
directory,
|
|
274
|
+
files: written.map((file) => path.join(directory, file)),
|
|
275
|
+
pdfSkipped: pdf === undefined ? 'no workspace package declares @playwright/test, so no browser can print it' : undefined,
|
|
276
|
+
};
|
|
277
|
+
};
|
|
278
|
+
//# sourceMappingURL=compliance-report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compliance-report.js","sourceRoot":"","sources":["../src/compliance-report.ts"],"names":[],"mappings":"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"}
|
package/dist/gates.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Member, Repository
|
|
1
|
+
import type { Member, Repository } from './context.js';
|
|
2
2
|
import type { GateResult } from './exec.js';
|
|
3
3
|
/** What every gate declares, whatever it judges. */
|
|
4
4
|
interface GateMeta {
|
|
@@ -27,7 +27,7 @@ interface GateMeta {
|
|
|
27
27
|
*/
|
|
28
28
|
export type Gate = (GateMeta & {
|
|
29
29
|
readonly scope: 'repository';
|
|
30
|
-
readonly run: (
|
|
30
|
+
readonly run: (repository: Repository) => GateResult | Promise<GateResult>;
|
|
31
31
|
}) | (GateMeta & {
|
|
32
32
|
readonly scope: 'package' | 'payload';
|
|
33
33
|
readonly run: (member: Member) => GateResult | Promise<GateResult>;
|
|
@@ -56,6 +56,6 @@ export interface PlannedGate {
|
|
|
56
56
|
* @param isExtended whether extended verification's gates are included.
|
|
57
57
|
* @returns one planned invocation per step, in run order.
|
|
58
58
|
*/
|
|
59
|
-
export declare const planFor: (repository:
|
|
59
|
+
export declare const planFor: (repository: Repository, isExtended: boolean) => readonly PlannedGate[];
|
|
60
60
|
export {};
|
|
61
61
|
//# sourceMappingURL=gates.d.ts.map
|
package/dist/gates.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gates.d.ts","sourceRoot":"","sources":["../src/gates.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"gates.d.ts","sourceRoot":"","sources":["../src/gates.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAE3C,oDAAoD;AACpD,UAAU,QAAQ;IAChB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,uDAAuD;IACvD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,gEAAgE;IAChE,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAC5B;;;;;;OAMG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAA;CAClC;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,IAAI,GACZ,CAAC,QAAQ,GAAG;IACV,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAA;IAC5B,QAAQ,CAAC,GAAG,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;CAC3E,CAAC,GACF,CAAC,QAAQ,GAAG;IACV,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,CAAA;IACrC,QAAQ,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;CACnE,CAAC,CAAA;AAmTN,+CAA+C;AAC/C,eAAO,MAAM,SAAS,EAAE,SAAS,IAAI,EAAuD,CAAA;AAE5F;;;GAGG;AACH,eAAO,MAAM,QAAQ,GAAI,YAAY,OAAO,KAAG,SAAS,IAAI,EACF,CAAA;AAE1D,sCAAsC;AACtC,eAAO,MAAM,QAAQ,GAAI,IAAI,MAAM,KAAG,IAAI,GAAG,SAAoE,CAAA;AAEjH,iFAAiF;AACjF,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;IACnB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;CACpC;AAQD;;;;;;;;;GASG;AACH,eAAO,MAAM,OAAO,GAAI,YAAY,UAAU,EAAE,YAAY,OAAO,KAAG,SAAS,WAAW,EAoBzF,CAAA"}
|
package/dist/gates.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { planSteps } from '@ploaness/governance';
|
|
3
3
|
import { assets } from './checks/assets.js';
|
|
4
4
|
import { blocklist } from './checks/blocklist.js';
|
|
5
|
+
import { complianceReport } from './checks/compliance-report.js';
|
|
5
6
|
import { actions, containers, secrets } from './checks/containers.js';
|
|
6
7
|
import { conventions } from './checks/conventions.js';
|
|
7
8
|
import { dependencyFreshness, licenses, vulnerabilities } from './checks/dependencies.js';
|
|
@@ -16,6 +17,7 @@ import { oxlint } from './checks/oxlint.js';
|
|
|
16
17
|
import { adminViews, payloadDefaults, payloadGenerated, payloadRules } from './checks/payload.js';
|
|
17
18
|
import { preflight } from './checks/preflight.js';
|
|
18
19
|
import { configReferences, documentation, skills } from './checks/references.js';
|
|
20
|
+
import { sbomInventory } from './checks/sbom.js';
|
|
19
21
|
import { shell } from './checks/shell.js';
|
|
20
22
|
import { suppressions } from './checks/suppressions.js';
|
|
21
23
|
import { tailwindTokens } from './checks/tailwind.js';
|
|
@@ -266,7 +268,7 @@ const DEFAULT_GATES = [
|
|
|
266
268
|
];
|
|
267
269
|
/**
|
|
268
270
|
* Extended verification adds the shell scripts, the infrastructure definitions, history, build, bundle,
|
|
269
|
-
*
|
|
271
|
+
* end-to-end checks, and a workspace dependency inventory.
|
|
270
272
|
*/
|
|
271
273
|
const EXTENDED_GATES = [
|
|
272
274
|
// First in the tier because it is the cheapest thing in it: a static read of the tracked scripts,
|
|
@@ -304,6 +306,14 @@ const EXTENDED_GATES = [
|
|
|
304
306
|
{ id: 'build', scope: 'package', title: 'production build', isExtended: true, run: build },
|
|
305
307
|
{ id: 'bundle', scope: 'package', title: 'client bundle budget', isExtended: true, run: bundle },
|
|
306
308
|
{ id: 'e2e', scope: 'package', title: 'end-to-end suite', isExtended: true, run: endToEnd },
|
|
309
|
+
{ id: 'sbom', scope: 'repository', title: 'dependency inventory', isExtended: true, run: sbomInventory },
|
|
310
|
+
{
|
|
311
|
+
id: 'compliance-report',
|
|
312
|
+
scope: 'repository',
|
|
313
|
+
title: 'compliance report',
|
|
314
|
+
isExtended: true,
|
|
315
|
+
run: complianceReport,
|
|
316
|
+
},
|
|
307
317
|
];
|
|
308
318
|
// Last in BOTH modes, which it was not. It closed `DEFAULT_GATES`, and the extended gates were appended
|
|
309
319
|
// after it - so `build`, `bundle`, and `e2e` all ran once the fingerprint had already been compared.
|