@ploaness/cli 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.
Files changed (127) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +13 -0
  3. package/dist/bin.d.ts +3 -0
  4. package/dist/bin.d.ts.map +1 -0
  5. package/dist/bin.js +161 -0
  6. package/dist/bin.js.map +1 -0
  7. package/dist/checks/assets.d.ts +30 -0
  8. package/dist/checks/assets.d.ts.map +1 -0
  9. package/dist/checks/assets.js +169 -0
  10. package/dist/checks/assets.js.map +1 -0
  11. package/dist/checks/containers.d.ts +9 -0
  12. package/dist/checks/containers.d.ts.map +1 -0
  13. package/dist/checks/containers.js +194 -0
  14. package/dist/checks/containers.js.map +1 -0
  15. package/dist/checks/conventions.d.ts +8 -0
  16. package/dist/checks/conventions.d.ts.map +1 -0
  17. package/dist/checks/conventions.js +77 -0
  18. package/dist/checks/conventions.js.map +1 -0
  19. package/dist/checks/dependencies.d.ts +11 -0
  20. package/dist/checks/dependencies.d.ts.map +1 -0
  21. package/dist/checks/dependencies.js +389 -0
  22. package/dist/checks/dependencies.js.map +1 -0
  23. package/dist/checks/editorconfig.d.ts +5 -0
  24. package/dist/checks/editorconfig.d.ts.map +1 -0
  25. package/dist/checks/editorconfig.js +38 -0
  26. package/dist/checks/editorconfig.js.map +1 -0
  27. package/dist/checks/generated.d.ts +10 -0
  28. package/dist/checks/generated.d.ts.map +1 -0
  29. package/dist/checks/generated.js +65 -0
  30. package/dist/checks/generated.js.map +1 -0
  31. package/dist/checks/history.d.ts +19 -0
  32. package/dist/checks/history.d.ts.map +1 -0
  33. package/dist/checks/history.js +71 -0
  34. package/dist/checks/history.js.map +1 -0
  35. package/dist/checks/images.d.ts +14 -0
  36. package/dist/checks/images.d.ts.map +1 -0
  37. package/dist/checks/images.js +100 -0
  38. package/dist/checks/images.js.map +1 -0
  39. package/dist/checks/install.d.ts +5 -0
  40. package/dist/checks/install.d.ts.map +1 -0
  41. package/dist/checks/install.js +21 -0
  42. package/dist/checks/install.js.map +1 -0
  43. package/dist/checks/integrity.d.ts +11 -0
  44. package/dist/checks/integrity.d.ts.map +1 -0
  45. package/dist/checks/integrity.js +66 -0
  46. package/dist/checks/integrity.js.map +1 -0
  47. package/dist/checks/payload.d.ts +7 -0
  48. package/dist/checks/payload.d.ts.map +1 -0
  49. package/dist/checks/payload.js +81 -0
  50. package/dist/checks/payload.js.map +1 -0
  51. package/dist/checks/preflight.d.ts +5 -0
  52. package/dist/checks/preflight.d.ts.map +1 -0
  53. package/dist/checks/preflight.js +48 -0
  54. package/dist/checks/preflight.js.map +1 -0
  55. package/dist/checks/references.d.ts +18 -0
  56. package/dist/checks/references.d.ts.map +1 -0
  57. package/dist/checks/references.js +100 -0
  58. package/dist/checks/references.js.map +1 -0
  59. package/dist/checks/suppressions.d.ts +5 -0
  60. package/dist/checks/suppressions.d.ts.map +1 -0
  61. package/dist/checks/suppressions.js +50 -0
  62. package/dist/checks/suppressions.js.map +1 -0
  63. package/dist/checks/tailwind.d.ts +5 -0
  64. package/dist/checks/tailwind.d.ts.map +1 -0
  65. package/dist/checks/tailwind.js +29 -0
  66. package/dist/checks/tailwind.js.map +1 -0
  67. package/dist/checks/tests.d.ts +8 -0
  68. package/dist/checks/tests.d.ts.map +1 -0
  69. package/dist/checks/tests.js +123 -0
  70. package/dist/checks/tests.js.map +1 -0
  71. package/dist/checks/toolchain.d.ts +25 -0
  72. package/dist/checks/toolchain.d.ts.map +1 -0
  73. package/dist/checks/toolchain.js +165 -0
  74. package/dist/checks/toolchain.js.map +1 -0
  75. package/dist/checks/tree.d.ts +6 -0
  76. package/dist/checks/tree.d.ts.map +1 -0
  77. package/dist/checks/tree.js +52 -0
  78. package/dist/checks/tree.js.map +1 -0
  79. package/dist/checks/wiring.d.ts +5 -0
  80. package/dist/checks/wiring.d.ts.map +1 -0
  81. package/dist/checks/wiring.js +163 -0
  82. package/dist/checks/wiring.js.map +1 -0
  83. package/dist/commands/commit-message.d.ts +11 -0
  84. package/dist/commands/commit-message.d.ts.map +1 -0
  85. package/dist/commands/commit-message.js +57 -0
  86. package/dist/commands/commit-message.js.map +1 -0
  87. package/dist/commands/format.d.ts +4 -0
  88. package/dist/commands/format.d.ts.map +1 -0
  89. package/dist/commands/format.js +35 -0
  90. package/dist/commands/format.js.map +1 -0
  91. package/dist/commands/hooks.d.ts +9 -0
  92. package/dist/commands/hooks.d.ts.map +1 -0
  93. package/dist/commands/hooks.js +57 -0
  94. package/dist/commands/hooks.js.map +1 -0
  95. package/dist/commands/init.d.ts +4 -0
  96. package/dist/commands/init.d.ts.map +1 -0
  97. package/dist/commands/init.js +92 -0
  98. package/dist/commands/init.js.map +1 -0
  99. package/dist/commands/sync.d.ts +4 -0
  100. package/dist/commands/sync.d.ts.map +1 -0
  101. package/dist/commands/sync.js +30 -0
  102. package/dist/commands/sync.js.map +1 -0
  103. package/dist/commands/verify.d.ts +18 -0
  104. package/dist/commands/verify.d.ts.map +1 -0
  105. package/dist/commands/verify.js +96 -0
  106. package/dist/commands/verify.js.map +1 -0
  107. package/dist/context.d.ts +157 -0
  108. package/dist/context.d.ts.map +1 -0
  109. package/dist/context.js +345 -0
  110. package/dist/context.js.map +1 -0
  111. package/dist/exec.d.ts +80 -0
  112. package/dist/exec.d.ts.map +1 -0
  113. package/dist/exec.js +117 -0
  114. package/dist/exec.js.map +1 -0
  115. package/dist/gates.d.ts +61 -0
  116. package/dist/gates.d.ts.map +1 -0
  117. package/dist/gates.js +298 -0
  118. package/dist/gates.js.map +1 -0
  119. package/dist/index.d.ts +10 -0
  120. package/dist/index.d.ts.map +1 -0
  121. package/dist/index.js +12 -0
  122. package/dist/index.js.map +1 -0
  123. package/dist/report.d.ts +40 -0
  124. package/dist/report.d.ts.map +1 -0
  125. package/dist/report.js +224 -0
  126. package/dist/report.js.map +1 -0
  127. package/package.json +60 -0
@@ -0,0 +1,71 @@
1
+ // History gates. They read the repository rather than the build, so none of them needs a compilation and
2
+ // a freshly written commit can still be amended.
3
+ import { findMergeCommits, isNonTrivial, OWNED_HISTORY_REVISIONS, parseMessage, parseNumstat, validateMessage, } from '@ploaness/governance';
4
+ import { git } from '../context.js';
5
+ import { failed, passed } from '../exec.js';
6
+ const nonEmptyLines = (raw) => raw.split('\n').filter((line) => line.trim().length > 0);
7
+ const shasOf = (context, revisionArguments) => nonEmptyLines(git(context, ['rev-list', ...revisionArguments]));
8
+ /** Extended verification walks every commit, so a shallow clone is rejected up front. */
9
+ // Enough of a commit hash to identify it in a report without filling the line.
10
+ const SHORT_SHA_LENGTH = 9;
11
+ export const requireFullHistory = (context) => {
12
+ try {
13
+ return git(context, ['rev-parse', '--is-shallow-repository']) === 'true'
14
+ ? failed('the repository is shallow', [
15
+ 'the history gates walk every commit; check out with full depth (fetch-depth: 0 in CI)',
16
+ ])
17
+ : passed('the full history is present');
18
+ }
19
+ catch {
20
+ return failed('this is not a git repository', ['ploaness governs a versioned working tree']);
21
+ }
22
+ };
23
+ /**
24
+ * Validate commit messages. Every commit is held to every rule, including the ones git writes for you: a
25
+ * merge, a revert, or an autosquash subject must be given a conforming form by hand.
26
+ *
27
+ * It walks the same refs `linearHistory` does, and the default is the shared constant rather than a
28
+ * literal so the two cannot drift apart. Walking only HEAD was the earlier spelling and it left a hole
29
+ * this repository's own rules describe: a branch off HEAD's ancestry is history the repository owns and
30
+ * can rewrite, so a banned message there is a violation nothing reported. A real project carried an
31
+ * agent-attribution trailer on such a branch past a passing gate.
32
+ */
33
+ export const commitHistory = (context, revisionArguments = OWNED_HISTORY_REVISIONS) => {
34
+ const shas = shasOf(context, revisionArguments);
35
+ const findings = shas.flatMap((sha) => {
36
+ const message = parseMessage(git(context, ['log', '--format=%B', '-n', '1', sha]));
37
+ const isBodyRequired = isNonTrivial(parseNumstat(git(context, ['show', '--numstat', '--format=', sha])));
38
+ return validateMessage(message, isBodyRequired).map((problem) => `${sha.slice(0, SHORT_SHA_LENGTH)} ${problem}`);
39
+ });
40
+ return findings.length > 0
41
+ ? failed(`${String(findings.length)} commit-message problem(s) across ${String(shas.length)} commit(s)`, findings)
42
+ : passed(`${String(shas.length)} commit message(s) conform`);
43
+ };
44
+ /** Validate one pending message, from a message file the author points at. */
45
+ export const commitMessageProblems = (context, raw) => {
46
+ const isRequireBody = isNonTrivial(parseNumstat(git(context, ['diff', '--cached', '--numstat'])));
47
+ return validateMessage(parseMessage(raw), isRequireBody);
48
+ };
49
+ // One line per commit: the commit hash followed by its parent hashes, all space separated. Counting the
50
+ // parents git recorded is what makes the rule unforgeable: a subject that mentions merging is an ordinary
51
+ // commit, and rewording a merge does not hide it.
52
+ const PARENT_FORMAT = '--format=%H %P';
53
+ /** The history is linear: a merge commit is prohibited wherever this repository owns it. */
54
+ export const linearHistory = (context) => {
55
+ const commits = nonEmptyLines(git(context, ['log', ...OWNED_HISTORY_REVISIONS, PARENT_FORMAT])).map((line) => {
56
+ const hashes = line.trim().split(' ');
57
+ return {
58
+ sha: hashes[0] ?? '',
59
+ subject: '',
60
+ parentCount: Math.max(0, hashes.length - 1),
61
+ };
62
+ });
63
+ const violations = findMergeCommits(commits.map((commit) => ({
64
+ ...commit,
65
+ subject: commit.parentCount > 1 ? git(context, ['log', '--format=%s', '-n', '1', commit.sha]) : '',
66
+ })));
67
+ return violations.length > 0
68
+ ? failed(`${String(violations.length)} merge commit(s) in the history`, violations.map((violation) => `${violation.sha.slice(0, SHORT_SHA_LENGTH)} ${violation.reason}`))
69
+ : passed(`${String(commits.length)} commit(s) form a linear history`);
70
+ };
71
+ //# sourceMappingURL=history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/checks/history.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /** What the image half of the freshness report found, or why it could not look. */
2
+ export interface ImageReport {
3
+ readonly scanned: number;
4
+ /** Report lines, each already phrased for the gate's finding list. */
5
+ readonly lines: readonly string[];
6
+ /** Set when the registry could not establish what is current, which fails the gate. */
7
+ readonly failure: string | undefined;
8
+ }
9
+ /**
10
+ * Read every image the harness pins against its registry.
11
+ * @returns the report lines, or the failure that stopped the registry from answering.
12
+ */
13
+ export declare const imageFreshness: () => Promise<ImageReport>;
14
+ //# sourceMappingURL=images.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"images.d.ts","sourceRoot":"","sources":["../../src/checks/images.ts"],"names":[],"mappings":"AA8BA,mFAAmF;AACnF,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,sEAAsE;IACtE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,uFAAuF;IACvF,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;CACrC;AA6ED;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAa,OAAO,CAAC,WAAW,CA0C1D,CAAA"}
@@ -0,0 +1,100 @@
1
+ // The registry reads behind the image half of the freshness report.
2
+ //
3
+ // Everything that decides anything lives in `@ploaness/governance`: what a stable tag is, which tags
4
+ // are comparable with the pinned one, which is newest, and how a finding reads. What is left here is
5
+ // the HTTP, which is why this file is in the CLI at all.
6
+ //
7
+ // A newer image never fails the run. The freshness bound is a claim about a release line, and a tag is
8
+ // not required to carry one - so an update is reported and the build carries on. Failure stays where
9
+ // the guideline puts it: a declaration this cannot parse, or a registry that cannot say what is current.
10
+ import { asRecord, CONTAINER_IMAGES, describeContainerDrift, describeContainerUpdate, isArray, judgeContainer, parseContainerReference, REQUEST_TIMEOUT_MS, } from '@ploaness/governance';
11
+ const DOCKER_HUB = 'https://hub.docker.com';
12
+ const PAGE_SIZE = 100;
13
+ // Enough for the largest repository the harness pins; hadolint publishes several hundred tags.
14
+ const MAX_PAGES = 10;
15
+ const FIRST_PAGE = 1;
16
+ const fetchJson = async (url) => {
17
+ const response = await fetch(url, { signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS) });
18
+ if (!response.ok) {
19
+ throw new Error(`Docker Hub returned ${String(response.status)} for ${url}`);
20
+ }
21
+ return await response.json();
22
+ };
23
+ const repoUrl = (reference) => `${DOCKER_HUB}/v2/namespaces/${reference.namespace}/repositories/${reference.repository}`;
24
+ const tagNames = (body) => {
25
+ const results = asRecord(body)['results'];
26
+ if (!isArray(results)) {
27
+ throw new TypeError('Docker Hub returned no tag list');
28
+ }
29
+ return results
30
+ .map((entry) => asRecord(entry)['name'])
31
+ .filter((name) => typeof name === 'string');
32
+ };
33
+ // Paged rather than taking the first hundred. A repository that publishes every patch of every minor
34
+ // pushes its newest tag off page one within a year, and reading only that page would report "current"
35
+ // forever - a silent wrong answer, which is worse than the failure an unreachable registry produces.
36
+ const tagsFrom = async (reference, page, soFar) => {
37
+ const names = tagNames(await fetchJson(`${repoUrl(reference)}/tags?page_size=${String(PAGE_SIZE)}&page=${String(page)}`));
38
+ const collected = [...soFar, ...names];
39
+ return names.length < PAGE_SIZE || page >= MAX_PAGES
40
+ ? collected
41
+ : await tagsFrom(reference, page + 1, collected);
42
+ };
43
+ const digestOf = async (reference, tag) => {
44
+ const answered = await fetchJson(`${repoUrl(reference)}/tags/${tag}`);
45
+ const digest = asRecord(answered)['digest'];
46
+ if (typeof digest !== 'string') {
47
+ throw new TypeError(`Docker Hub returned no digest for ${reference.name}:${tag}`);
48
+ }
49
+ return digest;
50
+ };
51
+ const inspect = async (reference) => ({
52
+ reference,
53
+ available: await tagsFrom(reference, FIRST_PAGE, []),
54
+ currentDigest: await digestOf(reference, reference.tag),
55
+ });
56
+ // The replacement digest is read only where an update exists, so a fully current harness costs one
57
+ // extra request per image rather than two.
58
+ const describe = async (verdict) => {
59
+ const newer = verdict.newer;
60
+ const update = newer === undefined
61
+ ? []
62
+ : [
63
+ describeContainerUpdate(verdict.reference, newer, await digestOf(verdict.reference, newer.raw)),
64
+ ];
65
+ const drift = verdict.hasDrifted
66
+ ? [describeContainerDrift(verdict.reference, verdict.currentDigest)]
67
+ : [];
68
+ return [...update, ...drift];
69
+ };
70
+ /**
71
+ * Read every image the harness pins against its registry.
72
+ * @returns the report lines, or the failure that stopped the registry from answering.
73
+ */
74
+ export const imageFreshness = async () => {
75
+ const declared = Object.entries(CONTAINER_IMAGES).map(([tool, reference]) => parseContainerReference(tool, reference));
76
+ const pinned = declared.filter((reference) => reference !== undefined);
77
+ if (pinned.length !== declared.length) {
78
+ return {
79
+ scanned: 0,
80
+ lines: [],
81
+ failure: `${String(declared.length - pinned.length)} pinned image(s) are not written as ` +
82
+ '<repo>:<tag>@sha256:<digest>',
83
+ };
84
+ }
85
+ try {
86
+ const inspected = await Promise.all(pinned.map(async (reference) => inspect(reference)));
87
+ const verdicts = inspected.map((inspection) => judgeContainer(inspection));
88
+ const described = await Promise.all(verdicts.map(async (verdict) => describe(verdict)));
89
+ return { scanned: pinned.length, lines: described.flat(), failure: undefined };
90
+ }
91
+ catch (error) {
92
+ const reason = error instanceof Error ? error.message : String(error);
93
+ return {
94
+ scanned: pinned.length,
95
+ lines: [],
96
+ failure: `the image registry could not establish what is current: ${reason}`,
97
+ };
98
+ }
99
+ };
100
+ //# sourceMappingURL=images.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"images.js","sourceRoot":"","sources":["../../src/checks/images.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { Repository as Repo } from '../context.js';
2
+ import { type GateResult } from '../exec.js';
3
+ /** The repository must name the dependencies permitted to run an install script. */
4
+ export declare const installScripts: (repo: Repo) => GateResult;
5
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/checks/install.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,IAAI,IAAI,EAAE,MAAM,eAAe,CAAA;AACvD,OAAO,EAAU,KAAK,UAAU,EAAU,MAAM,YAAY,CAAA;AAQ5D,oFAAoF;AACpF,eAAO,MAAM,cAAc,GAAI,MAAM,IAAI,KAAG,UAMpC,CAAA"}
@@ -0,0 +1,21 @@
1
+ // Install-script allowlist. The decision lives in governance; this reads the two files pnpm accepts it in.
2
+ //
3
+ // Left undeclared, every package in the resolved set may run a build or postinstall script during
4
+ // `pnpm install` - the broadest surface a project has for executing code it never called. The gate
5
+ // requires the allowlist to exist and says nothing about what is on it: which packages a project trusts
6
+ // with an install script is a decision for the project to record, not one the harness can make for it.
7
+ import { declaresInstallScriptAllowlist } from '@ploaness/governance';
8
+ import { failed, passed } from '../exec.js';
9
+ const WORKSPACE_FILE = 'pnpm-workspace.yaml';
10
+ // The workspace file arrives already read, from the repository root. It used to be read relative to
11
+ // whatever directory the run started in, which in a workspace member is a directory the file cannot be
12
+ // in - and pnpm honours `pnpm.onlyBuiltDependencies` only at the root too, so the finding advised
13
+ // declaring the key somewhere it would have no effect.
14
+ /** The repository must name the dependencies permitted to run an install script. */
15
+ export const installScripts = (repo) => declaresInstallScriptAllowlist(repo.workspaceFile, repo.packageJson)
16
+ ? passed('the dependencies permitted to run an install script are declared')
17
+ : failed('no install-script allowlist is declared', [
18
+ `declare onlyBuiltDependencies in ${WORKSPACE_FILE}, or under the "pnpm" key of package.json`,
19
+ 'an empty list is a valid answer: it permits no dependency to run an install script',
20
+ ]);
21
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/checks/install.ts"],"names":[],"mappings":"AAAA,2GAA2G;AAC3G,EAAE;AACF,kGAAkG;AAClG,mGAAmG;AACnG,wGAAwG;AACxG,uGAAuG;AACvG,OAAO,EAAE,8BAA8B,EAAE,MAAM,sBAAsB,CAAA;AAErE,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM,YAAY,CAAA;AAE5D,MAAM,cAAc,GAAW,qBAAqB,CAAA;AAEpD,oGAAoG;AACpG,uGAAuG;AACvG,kGAAkG;AAClG,uDAAuD;AACvD,oFAAoF;AACpF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,IAAU,EAAc,EAAE,CACvD,8BAA8B,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,WAAW,CAAC;IAClE,CAAC,CAAC,MAAM,CAAC,kEAAkE,CAAC;IAC5E,CAAC,CAAC,MAAM,CAAC,yCAAyC,EAAE;QAChD,oCAAoC,cAAc,2CAA2C;QAC7F,oFAAoF;KACrF,CAAC,CAAA"}
@@ -0,0 +1,11 @@
1
+ import { type Context } from '../context.js';
2
+ import { type GateResult } from '../exec.js';
3
+ /** Decode every tracked image and fail on any that is corrupt or truncated. */
4
+ export declare const imageAssets: (context: Context) => GateResult;
5
+ /**
6
+ * Measure the total gzipped client JavaScript against the budget. Gzipped byte counts of built output are
7
+ * a fixed function of the source and the pinned dependency versions, so the number moves only when your
8
+ * change moves the bundle. That determinism is why this is a gate and a Lighthouse score is not.
9
+ */
10
+ export declare const bundle: (context: Context) => GateResult;
11
+ //# sourceMappingURL=integrity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integrity.d.ts","sourceRoot":"","sources":["../../src/checks/integrity.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,KAAK,OAAO,EAA+B,MAAM,eAAe,CAAA;AACzE,OAAO,EAAU,KAAK,UAAU,EAAU,MAAM,YAAY,CAAA;AAE5D,+EAA+E;AAC/E,eAAO,MAAM,WAAW,GAAI,SAAS,OAAO,KAAG,UAc9C,CAAA;AAeD;;;;GAIG;AACH,eAAO,MAAM,MAAM,GAAI,SAAS,OAAO,KAAG,UA8BzC,CAAA"}
@@ -0,0 +1,66 @@
1
+ // Asset integrity: an image that will not render, and a client bundle that has quietly doubled. Both are
2
+ // defects a status check and an accessibility sweep miss, because the response is a valid 200 and the
3
+ // markup is correct.
4
+ import { existsSync, readdirSync, readFileSync } from 'node:fs';
5
+ import path from 'node:path';
6
+ import { gzipSync } from 'node:zlib';
7
+ import { evaluateBundle, isSupportedImagePath, validateImageBytes, } from '@ploaness/governance';
8
+ import { hasOwnRuntime, trackedFiles } from '../context.js';
9
+ import { failed, passed } from '../exec.js';
10
+ /** Decode every tracked image and fail on any that is corrupt or truncated. */
11
+ export const imageAssets = (context) => {
12
+ const images = trackedFiles(context.root)
13
+ .filter(isSupportedImagePath)
14
+ .filter((file) => existsSync(path.join(context.root, file)));
15
+ const findings = images.flatMap((file) => {
16
+ const reason = validateImageBytes(file, readFileSync(path.join(context.root, file)));
17
+ return reason === null ? [] : [`${file}: ${reason}`];
18
+ });
19
+ return findings.length > 0
20
+ ? failed(`${String(findings.length)} corrupt or truncated image asset(s)`, findings)
21
+ : passed(`all ${String(images.length)} tracked image asset(s) decode`);
22
+ };
23
+ const collectJavaScript = (directory) => readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
24
+ const full = path.join(directory, entry.name);
25
+ if (entry.isDirectory()) {
26
+ return collectJavaScript(full);
27
+ }
28
+ return entry.name.endsWith('.js') ? [full] : [];
29
+ });
30
+ const BYTES_PER_KIB = 1024;
31
+ const KIB_DECIMALS = 1;
32
+ const asKiB = (bytes) => `${(bytes / BYTES_PER_KIB).toFixed(KIB_DECIMALS)} KiB`;
33
+ /**
34
+ * Measure the total gzipped client JavaScript against the budget. Gzipped byte counts of built output are
35
+ * a fixed function of the source and the pinned dependency versions, so the number moves only when your
36
+ * change moves the bundle. That determinism is why this is a gate and a Lighthouse score is not.
37
+ */
38
+ export const bundle = (context) => {
39
+ // A library ships no client bundle, so there is no `.next/static` to measure and its absence is not
40
+ // a missing build. Reported as a pass here for the same reason `build` reports one: the member has no
41
+ // runtime, which is a fact about what it declares rather than a step somebody skipped.
42
+ if (!hasOwnRuntime(context)) {
43
+ return passed('this package has no runtime of its own, so it ships no client bundle');
44
+ }
45
+ const staticDirectory = path.join(context.root, '.next', 'static');
46
+ if (!existsSync(staticDirectory)) {
47
+ return failed('the production build output is missing', [
48
+ `${path.relative(context.root, staticDirectory)} not found; the build gate must run first`,
49
+ ]);
50
+ }
51
+ const files = collectJavaScript(staticDirectory).map((file) => ({
52
+ path: file,
53
+ gzipBytes: gzipSync(readFileSync(file), { level: 9 }).length,
54
+ }));
55
+ const report = evaluateBundle(files, context.settings.bundleBudgetBytes);
56
+ const summary = `client JS ${asKiB(report.totalGzipBytes)} gzip across ${String(report.fileCount)} files ` +
57
+ `(budget ${asKiB(report.budgetBytes)})`;
58
+ return report.isWithinBudget
59
+ ? passed(summary)
60
+ : failed(`${summary} and is over budget`, [
61
+ // Not "raise the setting": `readSettings` clamps it with `Math.min`, so a project can only
62
+ // ever lower it. Advising an action the code forbids is the defect this message used to be.
63
+ "investigate the added weight; the ceiling is the harness's, and a project may only lower it",
64
+ ]);
65
+ };
66
+ //# sourceMappingURL=integrity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integrity.js","sourceRoot":"","sources":["../../src/checks/integrity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { type Context, type Member } from '../context.js';
2
+ import { type GateResult } from '../exec.js';
3
+ /** Regenerate the Payload types and admin import map, then fail on any drift. */
4
+ export declare const payloadGenerated: (context: Context) => GateResult;
5
+ /** Apply the source rules to every tracked TypeScript file under the declared source roots. */
6
+ export declare const payloadRules: (context: Member) => GateResult;
7
+ //# sourceMappingURL=payload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payload.d.ts","sourceRoot":"","sources":["../../src/checks/payload.ts"],"names":[],"mappings":"AASA,OAAO,EACL,KAAK,OAAO,EAEZ,KAAK,MAAM,EAIZ,MAAM,eAAe,CAAA;AACtB,OAAO,EAAsB,KAAK,UAAU,EAAmC,MAAM,YAAY,CAAA;AAWjG,iFAAiF;AACjF,eAAO,MAAM,gBAAgB,GAAI,SAAS,OAAO,KAAG,UA0CnD,CAAA;AAaD,+FAA+F;AAC/F,eAAO,MAAM,YAAY,GAAI,SAAS,MAAM,KAAG,UAkB9C,CAAA"}
@@ -0,0 +1,81 @@
1
+ // The Payload-specific gates: the generated artefacts must match the configuration that produces them,
2
+ // and the Local API must be used in a way that neither over-fetches nor skips access control.
3
+ import { existsSync, readFileSync } from 'node:fs';
4
+ import path from 'node:path';
5
+ import { findPayloadViolations, findSourceViolations, } from '@ploaness/governance';
6
+ import { git, resolveProjectTool, runEnvironment, trackedFiles, } from '../context.js';
7
+ import { asFindings, failed, passed, runNode } from '../exec.js';
8
+ // Resolution failure is an answer rather than an exception the caller must catch.
9
+ const resolveProjectToolOrUndefined = (context, tool) => {
10
+ try {
11
+ return resolveProjectTool(context, tool);
12
+ }
13
+ catch {
14
+ return undefined;
15
+ }
16
+ };
17
+ /** Regenerate the Payload types and admin import map, then fail on any drift. */
18
+ export const payloadGenerated = (context) => {
19
+ const payloadCli = resolveProjectToolOrUndefined(context, 'payload');
20
+ if (payloadCli === undefined) {
21
+ return failed('the payload CLI could not be resolved from the project', [
22
+ 'ploaness governs Payload projects, so "payload" must be installed in the project itself',
23
+ ]);
24
+ }
25
+ for (const target of ['generate:types', 'generate:importmap']) {
26
+ const result = runNode(payloadCli, [target], {
27
+ cwd: context.root,
28
+ // The project's own environment first, then the one option ploaness owns - so a `.env` cannot
29
+ // silence the deprecation flag, and every other variable the configuration reads is present.
30
+ env: { ...runEnvironment(context), NODE_OPTIONS: '--no-deprecation' },
31
+ });
32
+ if (result.code !== 0) {
33
+ return failed(`payload ${target} failed`, asFindings(result.output));
34
+ }
35
+ }
36
+ // The SETTING rather than the constant behind it. Every other consumer of the artefact list already
37
+ // read the setting - the write denials, the biome carve-outs, the scaffolder - and this one did not,
38
+ // so a project that declared where its import map actually lives had that file denied, excluded, and
39
+ // regenerated, but never diffed. The gate then reported that the artefacts matched a configuration it
40
+ // had not compared them against, and the drift it had just written surfaced two gates later as an
41
+ // unexplained working-tree change.
42
+ const drifted = context.settings.generatedArtefacts.filter((target) => {
43
+ if (!existsSync(path.join(context.root, target))) {
44
+ return false;
45
+ }
46
+ try {
47
+ return git(context, ['diff', '--name-only', '--', target]).length > 0;
48
+ }
49
+ catch {
50
+ return false;
51
+ }
52
+ });
53
+ return drifted.length > 0
54
+ ? failed('generated Payload artefacts drifted from the configuration', [
55
+ ...drifted.map((target) => `${target} changed when regenerated`),
56
+ 'commit the regenerated files',
57
+ ])
58
+ : passed('the generated Payload artefacts match the configuration');
59
+ };
60
+ const SOURCE_EXTENSIONS = ['.ts', '.tsx'];
61
+ // The language rules apply to every package; the Payload ones only to a package that has Payload to
62
+ // misuse. Held together, the import rule ran only where Payload did - so a frontend beside the CMS, the
63
+ // place a parent-relative import is MOST likely because it has no Payload config to anchor on, was the
64
+ // one package never checked for it.
65
+ const violationsIn = (source, isPayload) => [
66
+ ...findSourceViolations(source),
67
+ ...(isPayload ? findPayloadViolations(source) : []),
68
+ ];
69
+ /** Apply the source rules to every tracked TypeScript file under the declared source roots. */
70
+ export const payloadRules = (context) => {
71
+ const roots = context.settings.sourceRoots;
72
+ const candidates = trackedFiles(context.root).filter((file) => SOURCE_EXTENSIONS.some((extension) => file.endsWith(extension)) &&
73
+ roots.some((root) => file.startsWith(`${root}/`)) &&
74
+ !file.endsWith('payload-types.ts') &&
75
+ existsSync(path.join(context.root, file)));
76
+ const findings = candidates.flatMap((file) => violationsIn(readFileSync(path.join(context.root, file), 'utf8'), context.isPayload).map((violation) => `${file}:${String(violation.line)} [${violation.rule}] ${violation.reason}`));
77
+ return findings.length > 0
78
+ ? failed(`${String(findings.length)} source usage violation(s)`, findings)
79
+ : passed(`${String(candidates.length)} source file(s) follow the usage rules`);
80
+ };
81
+ //# sourceMappingURL=payload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payload.js","sourceRoot":"","sources":["../../src/checks/payload.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { type Repository } from '../context.js';
2
+ import { type GateResult } from '../exec.js';
3
+ /** Verify the project is a Payload application on a supported runtime. */
4
+ export declare const preflight: (context: Repository) => GateResult;
5
+ //# sourceMappingURL=preflight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preflight.d.ts","sourceRoot":"","sources":["../../src/checks/preflight.ts"],"names":[],"mappings":"AAaA,OAAO,EAAe,KAAK,UAAU,EAAY,MAAM,eAAe,CAAA;AACtE,OAAO,EAAU,KAAK,UAAU,EAAU,MAAM,YAAY,CAAA;AAoC5D,0EAA0E;AAC1E,eAAO,MAAM,SAAS,GAAI,SAAS,UAAU,KAAG,UAc/C,CAAA"}
@@ -0,0 +1,48 @@
1
+ // The gate that runs before every other one. ploaness governs Payload CMS projects, so it refuses to
2
+ // judge a project that is not one. Running anyway would produce a verdict about a contract the project
3
+ // never agreed to.
4
+ import { asOptionalText, asStringRecord, findPayloadMemberViolations, findPnpmRuntimeViolations, minimumNodeMajor, pinnedPnpmVersion, } from '@ploaness/governance';
5
+ import { readPins } from '../context.js';
6
+ import { failed, passed } from '../exec.js';
7
+ // Read from `pins.json`, not written here. The floor was a constant in this file, which made it a rule
8
+ // living in the I/O layer and a fourth copy of a number the pins already state - and this copy is the
9
+ // one that decided a verdict, so it was the copy that could silently disagree with `engines.node`.
10
+ const requiredNodeMajor = () => minimumNodeMajor(asStringRecord(readPins()['engines'])['node']);
11
+ // The pnpm this run is executing under, which is a different fact from the one the wiring gate reads.
12
+ // `packageManager` is what the project DECLARES, and Corepack obeys it only where Corepack is enabled;
13
+ // this is what actually resolved the tree every later gate then judges. Read from the pin rather than
14
+ // from `engines.pnpm`, which is derived from the same field.
15
+ const requiredPnpm = () => pinnedPnpmVersion(asOptionalText(readPins()['packageManager']));
16
+ // The two questions preflight asks about the project itself, separated from the runtime question so
17
+ // neither has to accumulate into a shared list.
18
+ // Asked of the REPOSITORY rather than of one directory. A workspace legitimately holds packages that
19
+ // are not Payload applications - a shared library, a frontend reading the CMS over HTTP - and refusing
20
+ // each of those individually would refuse the repository they belong to. What ploaness still will not
21
+ // judge is a repository with no Payload in it anywhere, which is the same refusal, one level up.
22
+ const projectProblems = (repository) => {
23
+ if (repository.packageJson === undefined) {
24
+ return ['no package.json found; run ploaness from the repository root'];
25
+ }
26
+ return findPayloadMemberViolations(repository.members.map((member) => ({
27
+ path: member.path,
28
+ isPayload: member.isPayload,
29
+ sourceRoots: member.settings.sourceRoots,
30
+ })));
31
+ };
32
+ /** Verify the project is a Payload application on a supported runtime. */
33
+ export const preflight = (context) => {
34
+ const projectFindings = projectProblems(context);
35
+ const nodeMajor = Number(process.versions.node.split('.', 1)[0] ?? '0');
36
+ const required = requiredNodeMajor();
37
+ const findings = [
38
+ ...projectFindings,
39
+ ...(required !== undefined && nodeMajor < required
40
+ ? [`Node ${process.versions.node} is below the required ${String(required)}`]
41
+ : []),
42
+ ...findPnpmRuntimeViolations(process.env['npm_config_user_agent'], requiredPnpm()),
43
+ ];
44
+ return findings.length > 0
45
+ ? failed('project is not a supported Payload application on a pinned toolchain', findings)
46
+ : passed(`Payload project on Node ${process.versions.node}`);
47
+ };
48
+ //# sourceMappingURL=preflight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preflight.js","sourceRoot":"","sources":["../../src/checks/preflight.ts"],"names":[],"mappings":"AAAA,qGAAqG;AACrG,uGAAuG;AACvG,mBAAmB;AAEnB,OAAO,EACL,cAAc,EACd,cAAc,EACd,2BAA2B,EAC3B,yBAAyB,EAEzB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAgC,QAAQ,EAAE,MAAM,eAAe,CAAA;AACtE,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM,YAAY,CAAA;AAE5D,uGAAuG;AACvG,sGAAsG;AACtG,mGAAmG;AACnG,MAAM,iBAAiB,GAAG,GAAuB,EAAE,CACjD,gBAAgB,CAAC,cAAc,CAAC,QAAQ,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;AAEjE,sGAAsG;AACtG,uGAAuG;AACvG,sGAAsG;AACtG,6DAA6D;AAC7D,MAAM,YAAY,GAAG,GAAuB,EAAE,CAC5C,iBAAiB,CAAC,cAAc,CAAC,QAAQ,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAA;AAEjE,oGAAoG;AACpG,gDAAgD;AAChD,qGAAqG;AACrG,uGAAuG;AACvG,sGAAsG;AACtG,iGAAiG;AACjG,MAAM,eAAe,GAAG,CAAC,UAAsB,EAAqB,EAAE;IACpE,IAAI,UAAU,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QACzC,OAAO,CAAC,8DAA8D,CAAC,CAAA;IACzE,CAAC;IACD,OAAO,2BAA2B,CAChC,UAAU,CAAC,OAAO,CAAC,GAAG,CACpB,CAAC,MAAc,EAAe,EAAE,CAAC,CAAC;QAChC,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,WAAW;KACzC,CAAC,CACH,CACF,CAAA;AACH,CAAC,CAAA;AAED,0EAA0E;AAC1E,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,OAAmB,EAAc,EAAE;IAC3D,MAAM,eAAe,GAAsB,eAAe,CAAC,OAAO,CAAC,CAAA;IACnE,MAAM,SAAS,GAAW,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAA;IAC/E,MAAM,QAAQ,GAAuB,iBAAiB,EAAE,CAAA;IACxD,MAAM,QAAQ,GAAsB;QAClC,GAAG,eAAe;QAClB,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,SAAS,GAAG,QAAQ;YAChD,CAAC,CAAC,CAAC,QAAQ,OAAO,CAAC,QAAQ,CAAC,IAAI,0BAA0B,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7E,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,yBAAyB,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,EAAE,YAAY,EAAE,CAAC;KACnF,CAAA;IACD,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC;QACxB,CAAC,CAAC,MAAM,CAAC,sEAAsE,EAAE,QAAQ,CAAC;QAC1F,CAAC,CAAC,MAAM,CAAC,2BAA2B,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;AAChE,CAAC,CAAA"}
@@ -0,0 +1,18 @@
1
+ import { type Context, type Repository as Repo } from '../context.js';
2
+ import { type GateResult } from '../exec.js';
3
+ /**
4
+ * Every npm script and full-path file the agent docs name must still exist.
5
+ * @param repository the repository being judged, and the members whose docs it holds.
6
+ * @param reservedWords words that look like a script but name something else, such as a gate. The
7
+ * registry supplies them, so this module does not have to import it back and create a cycle.
8
+ */
9
+ export declare const documentation: (repository: Repo, reservedWords?: ReadonlySet<string>) => GateResult;
10
+ /**
11
+ * A concrete source file carved out of a tool config must still exist on disk, and a declared exclusion
12
+ * must exclude something. Both are the same defect at different scales: a carve-out that reaches
13
+ * nothing leaves the report reading exactly as it would have read without it.
14
+ */
15
+ export declare const configReferences: (context: Context) => GateResult;
16
+ /** The frontmatter an agent uses to discover and invoke a skill must be well formed. */
17
+ export declare const skills: (context: Context) => GateResult;
18
+ //# sourceMappingURL=references.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"references.d.ts","sourceRoot":"","sources":["../../src/checks/references.ts"],"names":[],"mappings":"AAoBA,OAAO,EACL,KAAK,OAAO,EAEZ,KAAK,UAAU,IAAI,IAAI,EAGxB,MAAM,eAAe,CAAA;AACtB,OAAO,EAAU,KAAK,UAAU,EAAU,MAAM,YAAY,CAAA;AA4B5D;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GACxB,YAAY,IAAI,EAChB,gBAAe,WAAW,CAAC,MAAM,CAAqB,KACrD,UA4BF,CAAA;AAiCD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAAI,SAAS,OAAO,KAAG,UAoBnD,CAAA;AAED,wFAAwF;AACxF,eAAO,MAAM,MAAM,GAAI,SAAS,OAAO,KAAG,UAgBzC,CAAA"}