@trofimyukdev/repo-truth 0.0.0-stage → 0.1.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 (120) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +273 -2
  3. package/dist/action.d.ts +52 -0
  4. package/dist/action.js +182 -0
  5. package/dist/action.js.map +1 -0
  6. package/dist/checks/action-pins.d.ts +52 -0
  7. package/dist/checks/action-pins.js +196 -0
  8. package/dist/checks/action-pins.js.map +1 -0
  9. package/dist/checks/autosquash.d.ts +23 -0
  10. package/dist/checks/autosquash.js +85 -0
  11. package/dist/checks/autosquash.js.map +1 -0
  12. package/dist/checks/bidi-controls.d.ts +58 -0
  13. package/dist/checks/bidi-controls.js +172 -0
  14. package/dist/checks/bidi-controls.js.map +1 -0
  15. package/dist/checks/binary-files.d.ts +53 -0
  16. package/dist/checks/binary-files.js +157 -0
  17. package/dist/checks/binary-files.js.map +1 -0
  18. package/dist/checks/config-changes.d.ts +57 -0
  19. package/dist/checks/config-changes.js +175 -0
  20. package/dist/checks/config-changes.js.map +1 -0
  21. package/dist/checks/credentials.d.ts +35 -0
  22. package/dist/checks/credentials.js +138 -0
  23. package/dist/checks/credentials.js.map +1 -0
  24. package/dist/checks/install-scripts.d.ts +39 -0
  25. package/dist/checks/install-scripts.js +173 -0
  26. package/dist/checks/install-scripts.js.map +1 -0
  27. package/dist/checks/lint-rules.d.ts +49 -0
  28. package/dist/checks/lint-rules.js +184 -0
  29. package/dist/checks/lint-rules.js.map +1 -0
  30. package/dist/checks/path-policy.d.ts +40 -0
  31. package/dist/checks/path-policy.js +195 -0
  32. package/dist/checks/path-policy.js.map +1 -0
  33. package/dist/checks/raised-timeouts.d.ts +66 -0
  34. package/dist/checks/raised-timeouts.js +248 -0
  35. package/dist/checks/raised-timeouts.js.map +1 -0
  36. package/dist/checks/script-changes.d.ts +51 -0
  37. package/dist/checks/script-changes.js +199 -0
  38. package/dist/checks/script-changes.js.map +1 -0
  39. package/dist/checks/secret-files.d.ts +58 -0
  40. package/dist/checks/secret-files.js +165 -0
  41. package/dist/checks/secret-files.js.map +1 -0
  42. package/dist/checks/strictness.d.ts +59 -0
  43. package/dist/checks/strictness.js +260 -0
  44. package/dist/checks/strictness.js.map +1 -0
  45. package/dist/checks/submodules.d.ts +51 -0
  46. package/dist/checks/submodules.js +172 -0
  47. package/dist/checks/submodules.js.map +1 -0
  48. package/dist/checks/suppressions.d.ts +53 -0
  49. package/dist/checks/suppressions.js +203 -0
  50. package/dist/checks/suppressions.js.map +1 -0
  51. package/dist/checks/workflow-permissions.d.ts +56 -0
  52. package/dist/checks/workflow-permissions.js +237 -0
  53. package/dist/checks/workflow-permissions.js.map +1 -0
  54. package/dist/checks/workflow-weakening.d.ts +38 -0
  55. package/dist/checks/workflow-weakening.js +172 -0
  56. package/dist/checks/workflow-weakening.js.map +1 -0
  57. package/dist/cli.d.ts +31 -0
  58. package/dist/cli.js +300 -0
  59. package/dist/cli.js.map +1 -0
  60. package/dist/commit-range.d.ts +28 -0
  61. package/dist/commit-range.js +152 -0
  62. package/dist/commit-range.js.map +1 -0
  63. package/dist/config.d.ts +35 -0
  64. package/dist/config.js +235 -0
  65. package/dist/config.js.map +1 -0
  66. package/dist/conflict-markers.d.ts +40 -0
  67. package/dist/conflict-markers.js +234 -0
  68. package/dist/conflict-markers.js.map +1 -0
  69. package/dist/dependency-sources.d.ts +32 -0
  70. package/dist/dependency-sources.js +260 -0
  71. package/dist/dependency-sources.js.map +1 -0
  72. package/dist/figure-claims.d.ts +35 -0
  73. package/dist/figure-claims.js +139 -0
  74. package/dist/figure-claims.js.map +1 -0
  75. package/dist/figure-text.d.ts +22 -0
  76. package/dist/figure-text.js +119 -0
  77. package/dist/figure-text.js.map +1 -0
  78. package/dist/index.d.ts +46 -0
  79. package/dist/index.js +38 -0
  80. package/dist/index.js.map +1 -0
  81. package/dist/large-blobs.d.ts +35 -0
  82. package/dist/large-blobs.js +163 -0
  83. package/dist/large-blobs.js.map +1 -0
  84. package/dist/lockfile-drift.d.ts +36 -0
  85. package/dist/lockfile-drift.js +206 -0
  86. package/dist/lockfile-drift.js.map +1 -0
  87. package/dist/lowered-thresholds.d.ts +70 -0
  88. package/dist/lowered-thresholds.js +281 -0
  89. package/dist/lowered-thresholds.js.map +1 -0
  90. package/dist/measurement-rule.d.ts +39 -0
  91. package/dist/measurement-rule.js +213 -0
  92. package/dist/measurement-rule.js.map +1 -0
  93. package/dist/portable-paths.d.ts +37 -0
  94. package/dist/portable-paths.js +215 -0
  95. package/dist/portable-paths.js.map +1 -0
  96. package/dist/registry.d.ts +43 -0
  97. package/dist/registry.js +144 -0
  98. package/dist/registry.js.map +1 -0
  99. package/dist/replay-plan.d.ts +36 -0
  100. package/dist/replay-plan.js +196 -0
  101. package/dist/replay-plan.js.map +1 -0
  102. package/dist/replayed-figures.d.ts +36 -0
  103. package/dist/replayed-figures.js +159 -0
  104. package/dist/replayed-figures.js.map +1 -0
  105. package/dist/snapshot-refreshes.d.ts +36 -0
  106. package/dist/snapshot-refreshes.js +202 -0
  107. package/dist/snapshot-refreshes.js.map +1 -0
  108. package/dist/stray-files.d.ts +52 -0
  109. package/dist/stray-files.js +234 -0
  110. package/dist/stray-files.js.map +1 -0
  111. package/dist/symlinks.d.ts +28 -0
  112. package/dist/symlinks.js +193 -0
  113. package/dist/symlinks.js.map +1 -0
  114. package/dist/trailers.d.ts +36 -0
  115. package/dist/trailers.js +110 -0
  116. package/dist/trailers.js.map +1 -0
  117. package/dist/weakened-tests.d.ts +94 -0
  118. package/dist/weakened-tests.js +458 -0
  119. package/dist/weakened-tests.js.map +1 -0
  120. package/package.json +31 -4
@@ -0,0 +1,234 @@
1
+ /**
2
+ * Conflict markers.
3
+ *
4
+ * A merge, a rebase or a cherry-pick that stops on a conflict writes marker
5
+ * lines into the file, and whoever resolves it by editing around them can
6
+ * commit them. A compiler catches that in some files and not in others: a
7
+ * Markdown page, a YAML fixture or a JSON snapshot carries the markers
8
+ * silently. This check reads the lines `git diff base...candidate` shows as
9
+ * ADDED and reports every conflict marker among them with its file and line.
10
+ *
11
+ * Only added lines count. A marker the base already holds is not the range's
12
+ * doing, and a line the range removes is never read as one it adds, so the
13
+ * commit that deletes a leftover marker is not itself reported. The lines come
14
+ * from git's diff of the two commits, never from the working tree.
15
+ *
16
+ * A marker is a line that begins with exactly seven of one marker character
17
+ * followed by whitespace or the end of the line. `<` opens a conflict, `|`
18
+ * opens the common ancestor's part and `>` closes it; those three are always
19
+ * findings. `=` separates the two sides, and a line of seven equals signs is
20
+ * also what underlines a Markdown heading, so a separator is a finding only
21
+ * between an opening marker and the next closing marker among the added lines
22
+ * of the same file.
23
+ */
24
+ import { execFile } from "node:child_process";
25
+ const NAME = "RT-09";
26
+ /** Seven of one marker character, then ASCII whitespace or the end of the line. */
27
+ const MARKER = /^(?:(<{7})|(\|{7})|(={7})|(>{7}))(?:[ \t\r\f\v]|$)/;
28
+ function markerKind(line) {
29
+ const match = MARKER.exec(line);
30
+ if (match === null) {
31
+ return undefined;
32
+ }
33
+ if (match[1] !== undefined)
34
+ return "opening";
35
+ if (match[2] !== undefined)
36
+ return "base";
37
+ if (match[3] !== undefined)
38
+ return "separator";
39
+ return "closing";
40
+ }
41
+ function runGit(cwd, args) {
42
+ return new Promise((resolve, reject) => {
43
+ execFile("git", args, { cwd, maxBuffer: 1024 * 1024 * 1024, encoding: "buffer" }, (error, stdout, stderr) => {
44
+ if (error) {
45
+ const detail = stderr.toString("utf8").trim();
46
+ reject(new Error(detail.length > 0 ? detail : error.message));
47
+ return;
48
+ }
49
+ resolve(stdout);
50
+ });
51
+ });
52
+ }
53
+ /** Escape control characters so a name or revision cannot replay a terminal sequence or split a line. */
54
+ function escapeControl(text) {
55
+ let escaped = "";
56
+ for (const char of text) {
57
+ const codePoint = char.codePointAt(0) ?? 0;
58
+ if (codePoint < 0x20 || (codePoint >= 0x7f && codePoint < 0xa0)) {
59
+ escaped += `\\u{${codePoint.toString(16).padStart(4, "0")}}`;
60
+ }
61
+ else {
62
+ escaped += char;
63
+ }
64
+ }
65
+ return escaped;
66
+ }
67
+ function quote(text) {
68
+ return `"${escapeControl(text)}"`;
69
+ }
70
+ function decodePath(bytes) {
71
+ try {
72
+ return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
73
+ }
74
+ catch {
75
+ return bytes.toString("latin1");
76
+ }
77
+ }
78
+ function splitNul(out) {
79
+ const paths = [];
80
+ let start = 0;
81
+ for (let i = 0; i < out.length; i += 1) {
82
+ if (out[i] === 0) {
83
+ if (i > start) {
84
+ paths.push(decodePath(out.subarray(start, i)));
85
+ }
86
+ start = i + 1;
87
+ }
88
+ }
89
+ return paths;
90
+ }
91
+ async function resolveCommit(cwd, revision) {
92
+ if (revision.length === 0 || revision.startsWith("-")) {
93
+ throw new Error(`revision ${quote(revision)} names no commit`);
94
+ }
95
+ let hash;
96
+ try {
97
+ const out = await runGit(cwd, ["rev-parse", "--verify", "--quiet", `${revision}^{commit}`]);
98
+ hash = out.toString("utf8").trim();
99
+ }
100
+ catch (error) {
101
+ throw new Error(`revision ${quote(revision)} names no commit: ${error.message}`);
102
+ }
103
+ if (hash.length === 0) {
104
+ throw new Error(`revision ${quote(revision)} names no commit`);
105
+ }
106
+ return hash;
107
+ }
108
+ /** The lines added to each file, in the order git lists the files. */
109
+ async function addedLines(cwd, base, candidate) {
110
+ const common = [
111
+ "-c",
112
+ "core.quotePath=false",
113
+ "diff",
114
+ "--no-ext-diff",
115
+ "--no-textconv",
116
+ "--no-color",
117
+ "--no-renames",
118
+ "--ignore-submodules=none",
119
+ "--submodule=short",
120
+ "--text",
121
+ ];
122
+ const range = `${base}...${candidate}`;
123
+ let names;
124
+ let patch;
125
+ try {
126
+ names = splitNul(await runGit(cwd, [...common, "--name-only", "-z", range, "--"]));
127
+ patch = await runGit(cwd, [...common, "-U0", range, "--"]);
128
+ }
129
+ catch (error) {
130
+ throw new Error(`could not read the lines added by ${quote(`${base}...${candidate}`)}: ${error.message}`);
131
+ }
132
+ const files = [];
133
+ let current;
134
+ let oldLeft = 0;
135
+ let newLeft = 0;
136
+ let newLine = 0;
137
+ let lastHeader = "";
138
+ // Both listings come from the same diff, so the Nth `diff --git` section is the Nth name.
139
+ for (const raw of patch.toString("latin1").split("\n")) {
140
+ if (oldLeft > 0 || newLeft > 0) {
141
+ if (raw.startsWith("+") && newLeft > 0) {
142
+ current?.push({ line: newLine, text: raw.slice(1) });
143
+ newLine += 1;
144
+ newLeft -= 1;
145
+ }
146
+ else if (raw.startsWith("-") && oldLeft > 0) {
147
+ oldLeft -= 1;
148
+ }
149
+ continue;
150
+ }
151
+ if (raw.startsWith("diff --git ")) {
152
+ // A path whose type changes is two sections under one identical header: one path.
153
+ if (raw !== lastHeader) {
154
+ current = [];
155
+ files.push({ path: names[files.length] ?? "", lines: current });
156
+ }
157
+ lastHeader = raw;
158
+ continue;
159
+ }
160
+ const hunk = /^@@ -\d+(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/.exec(raw);
161
+ if (hunk !== null) {
162
+ oldLeft = hunk[1] === undefined ? 1 : Number(hunk[1]);
163
+ newLeft = hunk[3] === undefined ? 1 : Number(hunk[3]);
164
+ newLine = Number(hunk[2]);
165
+ }
166
+ }
167
+ if (files.length !== names.length) {
168
+ throw new Error(`git listed ${names.length} changed path(s) but ${files.length} in its patch`);
169
+ }
170
+ return files;
171
+ }
172
+ /** The findings among one file's added lines, as evidence lines. */
173
+ function findingsIn(path, lines) {
174
+ const evidence = [];
175
+ const label = escapeControl(path);
176
+ let open = false;
177
+ let pending = [];
178
+ for (const { line, text } of lines) {
179
+ const kind = markerKind(text);
180
+ if (kind === undefined) {
181
+ continue;
182
+ }
183
+ const entry = `${label}:${line}: ${kind} marker`;
184
+ if (kind === "separator") {
185
+ if (open) {
186
+ pending.push(entry);
187
+ }
188
+ continue;
189
+ }
190
+ if (kind === "closing") {
191
+ evidence.push(...pending);
192
+ open = false;
193
+ pending = [];
194
+ }
195
+ else if (kind === "opening") {
196
+ open = true;
197
+ }
198
+ evidence.push(entry);
199
+ }
200
+ return evidence;
201
+ }
202
+ /**
203
+ * Check the lines `base...candidate` adds for leftover conflict markers.
204
+ * Fails closed: a revision that names no commit, or any git invocation that
205
+ * fails, is a `fail` record naming the cause - never a `pass`, and never a
206
+ * thrown error.
207
+ */
208
+ export async function checkConflictMarkers(options) {
209
+ try {
210
+ const { cwd, base, candidate } = options;
211
+ const baseCommit = await resolveCommit(cwd, base);
212
+ const candidateCommit = await resolveCommit(cwd, candidate);
213
+ const files = await addedLines(cwd, baseCommit, candidateCommit);
214
+ const evidence = [];
215
+ let scanned = 0;
216
+ for (const { path, lines } of files) {
217
+ scanned += lines.length;
218
+ evidence.push(...findingsIn(path, lines));
219
+ }
220
+ if (evidence.length > 0) {
221
+ return { name: NAME, status: "fail", evidence };
222
+ }
223
+ return {
224
+ name: NAME,
225
+ status: "pass",
226
+ evidence: [`${scanned} added line(s) in ${quote(base)}...${quote(candidate)} hold no conflict marker`],
227
+ };
228
+ }
229
+ catch (error) {
230
+ const message = error instanceof Error ? error.message : String(error);
231
+ return { name: NAME, status: "fail", evidence: [escapeControl(message)] };
232
+ }
233
+ }
234
+ //# sourceMappingURL=conflict-markers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conflict-markers.js","sourceRoot":"","sources":["../src/conflict-markers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Dependency sources.
3
+ *
4
+ * A dependency names where it comes from as well as which version. This check
5
+ * reads what the range adds or changes in the root manifest's dependency
6
+ * fields, `overrides` and `resolutions`, and the resolved URLs on the lines the
7
+ * range adds to the root lockfiles, and reports each dependency that does not
8
+ * come from a registry, with the rule it breaks: [git], [url], [path], [alias]
9
+ * or [registry]. A specifier the base already held is never judged. Lockfiles
10
+ * are read as the range adds their lines and never parsed whole.
11
+ */
12
+ import type { CheckRecord } from "./index.js";
13
+ /** The hosts a lockfile may resolve from when the caller gives none. */
14
+ export declare const DEFAULT_REGISTRIES: string[];
15
+ /** Where to look, and which two revisions bound the range. */
16
+ export interface DependencySourcesOptions {
17
+ /** The git repository to run in. */
18
+ readonly cwd: string;
19
+ /** The revision the range starts after. */
20
+ readonly base: string;
21
+ /** The revision the range ends at. */
22
+ readonly candidate: string;
23
+ /** The hosts a lockfile may resolve from; replaces `DEFAULT_REGISTRIES`. */
24
+ readonly registries?: readonly string[];
25
+ }
26
+ /**
27
+ * Report each dependency the range adds or changes that does not come from a
28
+ * registry. Fails closed: a manifest that does not parse, a revision that names
29
+ * no commit, or any git invocation that fails is a `fail` record naming the
30
+ * cause - never a `pass`, and never a thrown error.
31
+ */
32
+ export declare function checkDependencySources(options: DependencySourcesOptions): Promise<CheckRecord>;
@@ -0,0 +1,260 @@
1
+ /**
2
+ * Dependency sources.
3
+ *
4
+ * A dependency names where it comes from as well as which version. This check
5
+ * reads what the range adds or changes in the root manifest's dependency
6
+ * fields, `overrides` and `resolutions`, and the resolved URLs on the lines the
7
+ * range adds to the root lockfiles, and reports each dependency that does not
8
+ * come from a registry, with the rule it breaks: [git], [url], [path], [alias]
9
+ * or [registry]. A specifier the base already held is never judged. Lockfiles
10
+ * are read as the range adds their lines and never parsed whole.
11
+ */
12
+ import { execFile } from "node:child_process";
13
+ import { DEPENDENCY_FIELDS } from "./lockfile-drift.js";
14
+ const NAME = "RT-18";
15
+ const MANIFEST = "package.json";
16
+ /** The hosts a lockfile may resolve from when the caller gives none. */
17
+ export const DEFAULT_REGISTRIES = ["registry.npmjs.org", "registry.yarnpkg.com"];
18
+ const JSON_LOCKFILES = ["package-lock.json", "npm-shrinkwrap.json"];
19
+ const YARN_LOCKFILE = "yarn.lock";
20
+ function runGit(cwd, args) {
21
+ return new Promise((resolve, reject) => {
22
+ execFile("git", args, { cwd, maxBuffer: 1024 * 1024 * 1024, encoding: "buffer" }, (error, stdout, stderr) => {
23
+ if (error) {
24
+ const detail = stderr.toString("utf8").trim();
25
+ reject(new Error(detail.length > 0 ? detail : error.message));
26
+ return;
27
+ }
28
+ resolve(stdout);
29
+ });
30
+ });
31
+ }
32
+ /** Escape everything outside printable ASCII so a name cannot replay a control sequence. */
33
+ function escapeText(text) {
34
+ let escaped = "";
35
+ for (const char of text) {
36
+ const codePoint = char.codePointAt(0) ?? 0;
37
+ if (codePoint >= 0x20 && codePoint <= 0x7e) {
38
+ escaped += char;
39
+ }
40
+ else {
41
+ escaped += `\\u{${codePoint.toString(16).padStart(4, "0")}}`;
42
+ }
43
+ }
44
+ return escaped;
45
+ }
46
+ function quote(text) {
47
+ return `"${escapeText(text)}"`;
48
+ }
49
+ async function resolveCommit(cwd, revision) {
50
+ if (revision.length === 0 || revision.startsWith("-")) {
51
+ throw new Error(`revision ${quote(revision)} names no commit`);
52
+ }
53
+ try {
54
+ const out = await runGit(cwd, ["rev-parse", "--verify", "--quiet", `${revision}^{commit}`]);
55
+ const hash = out.toString("utf8").trim();
56
+ if (hash.length === 0) {
57
+ throw new Error("empty answer");
58
+ }
59
+ return hash;
60
+ }
61
+ catch (error) {
62
+ throw new Error(`revision ${quote(revision)} names no commit: ${error.message}`);
63
+ }
64
+ }
65
+ /** The text of a root file at a commit, or undefined when the commit has no such file. */
66
+ async function readFileAt(root, commit, path) {
67
+ const out = (await runGit(root, ["ls-tree", "-z", commit, "--", path])).toString("utf8");
68
+ const entry = out.split("\0")[0] ?? "";
69
+ const match = /^(\d+) (\w+) ([0-9a-f]+)\t(.*)$/s.exec(entry);
70
+ if (match === null || match[4] !== path || match[2] !== "blob") {
71
+ return undefined;
72
+ }
73
+ return (await runGit(root, ["cat-file", "blob", match[3]])).toString("utf8");
74
+ }
75
+ function isMapping(value) {
76
+ return value !== null && typeof value === "object" && !Array.isArray(value);
77
+ }
78
+ function walk(node, field, chain, out) {
79
+ for (const key of Object.keys(node)) {
80
+ const value = node[key];
81
+ if (typeof value === "string") {
82
+ out.push({ field, chain: key === "." ? chain : [...chain, key], specifier: value });
83
+ }
84
+ else if (isMapping(value)) {
85
+ walk(value, field, [...chain, key], out);
86
+ }
87
+ }
88
+ }
89
+ function declaredIn(text, label) {
90
+ let parsed;
91
+ try {
92
+ parsed = JSON.parse(text);
93
+ }
94
+ catch (error) {
95
+ throw new Error(`${MANIFEST} at ${label} is not valid JSON: ${error.message}`);
96
+ }
97
+ if (!isMapping(parsed)) {
98
+ throw new Error(`${MANIFEST} at ${label} is not a JSON object`);
99
+ }
100
+ const out = [];
101
+ for (const field of DEPENDENCY_FIELDS) {
102
+ const value = Object.prototype.hasOwnProperty.call(parsed, field) ? parsed[field] : undefined;
103
+ if (isMapping(value)) {
104
+ for (const key of Object.keys(value)) {
105
+ const specifier = value[key];
106
+ if (typeof specifier === "string") {
107
+ out.push({ field, chain: [key], specifier });
108
+ }
109
+ }
110
+ }
111
+ }
112
+ for (const field of ["overrides", "resolutions"]) {
113
+ const value = Object.prototype.hasOwnProperty.call(parsed, field) ? parsed[field] : undefined;
114
+ if (isMapping(value)) {
115
+ walk(value, field, [], out);
116
+ }
117
+ }
118
+ return out;
119
+ }
120
+ /** The package a dependency key stands for: a path of packages, optionally scoped, optionally with a version. */
121
+ function packageName(key) {
122
+ let name = key;
123
+ const at = name.lastIndexOf("@");
124
+ if (at > 0) {
125
+ name = name.slice(0, at);
126
+ }
127
+ const match = /(@[^/]+\/[^/]+|[^/]+)$/.exec(name);
128
+ return match === null ? name : match[1];
129
+ }
130
+ const PATH_FORM = /^(file:|link:|portal:|\.\/|\.\.\/|\/|~\/)/;
131
+ const GIT_PREFIX = /^(git\+|git:|github:|gitlab:|bitbucket:|gist:)/;
132
+ const GIT_SHORTHAND = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+(#.*)?$/;
133
+ /** The rule a specifier breaks, or undefined when it is an ordinary one. */
134
+ function classify(name, specifier) {
135
+ const spec = specifier.trim();
136
+ if (PATH_FORM.test(spec))
137
+ return "path";
138
+ if (GIT_PREFIX.test(spec) || GIT_SHORTHAND.test(spec))
139
+ return "git";
140
+ if (/^https?:/.test(spec))
141
+ return "url";
142
+ if (spec.startsWith("npm:")) {
143
+ const rest = spec.slice(4);
144
+ const at = rest.lastIndexOf("@");
145
+ const target = at > 0 ? rest.slice(0, at) : rest;
146
+ return target === name ? undefined : "alias";
147
+ }
148
+ return undefined;
149
+ }
150
+ function hostOf(url) {
151
+ try {
152
+ const host = new URL(url).hostname.toLowerCase();
153
+ return host.length > 0 ? host : undefined;
154
+ }
155
+ catch {
156
+ return undefined;
157
+ }
158
+ }
159
+ /** The lines a range adds to a root file, as [line in candidate, text]. */
160
+ async function addedLines(root, ancestor, candidate, path) {
161
+ const out = (await runGit(root, [
162
+ "-c",
163
+ "core.quotepath=off",
164
+ "diff",
165
+ "--no-ext-diff",
166
+ "--no-color",
167
+ "--no-renames",
168
+ "--unified=0",
169
+ ancestor,
170
+ candidate,
171
+ "--",
172
+ `:(literal)${path}`,
173
+ ])).toString("utf8");
174
+ const added = [];
175
+ let line = 0;
176
+ let inHunk = false;
177
+ for (const text of out.split("\n")) {
178
+ const header = /^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/.exec(text);
179
+ if (header !== null) {
180
+ line = Number(header[1]);
181
+ inHunk = true;
182
+ }
183
+ else if (inHunk && text.startsWith("+")) {
184
+ added.push([line, text.slice(1).replace(/\r$/, "")]);
185
+ line += 1;
186
+ }
187
+ }
188
+ return added;
189
+ }
190
+ /**
191
+ * Report each dependency the range adds or changes that does not come from a
192
+ * registry. Fails closed: a manifest that does not parse, a revision that names
193
+ * no commit, or any git invocation that fails is a `fail` record naming the
194
+ * cause - never a `pass`, and never a thrown error.
195
+ */
196
+ export async function checkDependencySources(options) {
197
+ try {
198
+ const { cwd, base, candidate } = options;
199
+ const registries = (options.registries ?? DEFAULT_REGISTRIES).map((host) => host.toLowerCase());
200
+ const baseCommit = await resolveCommit(cwd, base);
201
+ const candidateCommit = await resolveCommit(cwd, candidate);
202
+ const root = (await runGit(cwd, ["rev-parse", "--show-toplevel"])).toString("utf8").replace(/\r?\n$/, "");
203
+ let ancestor;
204
+ try {
205
+ ancestor = (await runGit(root, ["merge-base", baseCommit, candidateCommit])).toString("utf8").trim();
206
+ }
207
+ catch (error) {
208
+ throw new Error(`no merge base of ${quote(base)} and ${quote(candidate)}: ${error.message}`);
209
+ }
210
+ if (ancestor.length === 0) {
211
+ throw new Error(`no merge base of ${quote(base)} and ${quote(candidate)}`);
212
+ }
213
+ const before = await readFileAt(root, ancestor, MANIFEST);
214
+ const after = await readFileAt(root, candidateCommit, MANIFEST);
215
+ const declaredBefore = before === undefined ? [] : declaredIn(before, quote(base));
216
+ const declaredAfter = after === undefined ? [] : declaredIn(after, quote(candidate));
217
+ const findings = [];
218
+ const held = new Set(declaredBefore.map((d) => JSON.stringify([d.field, d.chain, d.specifier])));
219
+ for (const dep of declaredAfter) {
220
+ if (held.has(JSON.stringify([dep.field, dep.chain, dep.specifier])))
221
+ continue;
222
+ const rule = classify(packageName(dep.chain[dep.chain.length - 1] ?? ""), dep.specifier);
223
+ if (rule !== undefined) {
224
+ findings.push(`${MANIFEST} ${dep.field} ${quote(dep.chain.join(" > "))} ${quote(dep.specifier)} [${rule}]`);
225
+ }
226
+ }
227
+ let lockLines = 0;
228
+ for (const file of [...JSON_LOCKFILES, YARN_LOCKFILE]) {
229
+ const lines = await addedLines(root, ancestor, candidateCommit, file);
230
+ lockLines += lines.length;
231
+ for (const [number, text] of lines) {
232
+ const match = file === YARN_LOCKFILE
233
+ ? /^\s*"?resolved"?[\s:]+"?([^"\s]+)"?/.exec(text)
234
+ : /"resolved"\s*:\s*"([^"]*)"/.exec(text);
235
+ if (match === null)
236
+ continue;
237
+ const host = hostOf(match[1]);
238
+ if (host === undefined || !registries.includes(host)) {
239
+ findings.push(`${file} line ${number} host ${quote(host ?? `unparseable ${match[1]}`)} [registry]`);
240
+ }
241
+ }
242
+ }
243
+ if (before === undefined && after === undefined && lockLines === 0) {
244
+ return {
245
+ name: NAME,
246
+ status: "skip",
247
+ evidence: [`no ${MANIFEST} found in ${quote(base)}..${quote(candidate)} and no lockfile line added`],
248
+ };
249
+ }
250
+ if (findings.length > 0) {
251
+ return { name: NAME, status: "fail", evidence: findings };
252
+ }
253
+ return { name: NAME, status: "pass", evidence: ["no dependency from outside the registry"] };
254
+ }
255
+ catch (error) {
256
+ const message = error instanceof Error ? error.message : String(error);
257
+ return { name: NAME, status: "fail", evidence: [escapeText(message)] };
258
+ }
259
+ }
260
+ //# sourceMappingURL=dependency-sources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependency-sources.js","sourceRoot":"","sources":["../src/dependency-sources.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Figure claims.
3
+ *
4
+ * A measured figure is written in one form: a git command in a code span, the
5
+ * word `printed`, and the output in a code span. This finds the claims of that
6
+ * form a range adds, in its Markdown pages and in its commit messages. It
7
+ * reads only through git, with an argument vector and never a shell, and never
8
+ * from the working tree: a page is read as a blob of the candidate, and only
9
+ * the lines the range adds to it - against the file of the merge base it was
10
+ * renamed from, when git pairs it with one - can hold a claim. The text of a
11
+ * page or a body is read by `claimsInText`, which is RT-28's.
12
+ */
13
+ /** One figure claim of the range. */
14
+ export interface FigureClaim {
15
+ /** `<path>:<line>` for a page, the full commit id for a commit body. */
16
+ readonly where: string;
17
+ /** The text of the command's code span. */
18
+ readonly command: string;
19
+ /** The text of the claimed output's code span. */
20
+ readonly claimed: string;
21
+ }
22
+ export interface FigureClaimsOptions {
23
+ readonly cwd: string;
24
+ /** The revision the range starts after. */
25
+ readonly base: string;
26
+ /** The revision the range ends at. */
27
+ readonly candidate: string;
28
+ }
29
+ export type FigureClaimsResult = {
30
+ claims: FigureClaim[];
31
+ } | {
32
+ failure: string;
33
+ };
34
+ /** Every figure claim the range adds, or a failure naming why they could not be read. */
35
+ export declare function readFigureClaims(options: FigureClaimsOptions): Promise<FigureClaimsResult>;