checkly 8.22.0 → 8.23.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/ai-context/skills-command/references/configure-playwright-checks.md +24 -19
- package/dist/commands/debug/parse-project.js +3 -0
- package/dist/commands/debug/parse-project.js.map +1 -1
- package/dist/commands/deploy.js +3 -0
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/pw-test.js +3 -0
- package/dist/commands/pw-test.js.map +1 -1
- package/dist/commands/test.js +3 -0
- package/dist/commands/test.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js.map +1 -1
- package/dist/constructs/playwright-check-bundle.d.ts +5 -5
- package/dist/constructs/playwright-check-bundle.js.map +1 -1
- package/dist/constructs/project.js +5 -2
- package/dist/constructs/project.js.map +1 -1
- package/dist/constructs/session.d.ts +2 -1
- package/dist/constructs/session.js +2 -1
- package/dist/constructs/session.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/services/check-parser/bundler.d.ts +79 -8
- package/dist/services/check-parser/bundler.js +567 -9
- package/dist/services/check-parser/bundler.js.map +1 -1
- package/dist/services/check-parser/cache-hash.d.ts +141 -17
- package/dist/services/check-parser/cache-hash.js +78 -12
- package/dist/services/check-parser/cache-hash.js.map +1 -1
- package/dist/services/check-parser/faux-package.d.ts +5 -0
- package/dist/services/check-parser/faux-package.js +9 -1
- package/dist/services/check-parser/faux-package.js.map +1 -1
- package/dist/services/check-parser/lockfile-pruner.d.ts +104 -0
- package/dist/services/check-parser/lockfile-pruner.js +1107 -0
- package/dist/services/check-parser/lockfile-pruner.js.map +1 -0
- package/dist/services/check-parser/package-files/package-manager.d.ts +34 -0
- package/dist/services/check-parser/package-files/package-manager.js +131 -3
- package/dist/services/check-parser/package-files/package-manager.js.map +1 -1
- package/dist/services/check-parser/package-files/pnpmfile.d.ts +40 -0
- package/dist/services/check-parser/package-files/pnpmfile.js +322 -0
- package/dist/services/check-parser/package-files/pnpmfile.js.map +1 -0
- package/dist/services/check-parser/package-files/resolver.d.ts +6 -1
- package/dist/services/check-parser/package-files/resolver.js +34 -0
- package/dist/services/check-parser/package-files/resolver.js.map +1 -1
- package/dist/services/check-parser/package-files/workspace.d.ts +16 -1
- package/dist/services/check-parser/package-files/workspace.js +17 -2
- package/dist/services/check-parser/package-files/workspace.js.map +1 -1
- package/dist/services/check-parser/package-prune.d.ts +68 -0
- package/dist/services/check-parser/package-prune.js +274 -0
- package/dist/services/check-parser/package-prune.js.map +1 -0
- package/dist/services/check-parser/parser.js +9 -0
- package/dist/services/check-parser/parser.js.map +1 -1
- package/dist/services/check-parser/patched-dependencies.d.ts +133 -0
- package/dist/services/check-parser/patched-dependencies.js +428 -0
- package/dist/services/check-parser/patched-dependencies.js.map +1 -0
- package/dist/services/checkly-config-loader.d.ts +164 -10
- package/dist/services/checkly-config-loader.js +39 -0
- package/dist/services/checkly-config-loader.js.map +1 -1
- package/dist/services/embedded-packages/cache.d.ts +8 -4
- package/dist/services/embedded-packages/cache.js +27 -6
- package/dist/services/embedded-packages/cache.js.map +1 -1
- package/dist/services/embedded-packages/diagnostics.d.ts +129 -0
- package/dist/services/embedded-packages/diagnostics.js +212 -0
- package/dist/services/embedded-packages/diagnostics.js.map +1 -0
- package/dist/services/embedded-packages/lockfile-filter.d.ts +20 -0
- package/dist/services/embedded-packages/lockfile-filter.js +40 -0
- package/dist/services/embedded-packages/lockfile-filter.js.map +1 -0
- package/dist/services/embedded-packages/lockfile-packages.d.ts +31 -2
- package/dist/services/embedded-packages/lockfile-packages.js +234 -30
- package/dist/services/embedded-packages/lockfile-packages.js.map +1 -1
- package/dist/services/embedded-packages/materializer.d.ts +19 -5
- package/dist/services/embedded-packages/materializer.js +445 -91
- package/dist/services/embedded-packages/materializer.js.map +1 -1
- package/dist/services/embedded-packages/npmrc.d.ts +163 -21
- package/dist/services/embedded-packages/npmrc.js +440 -75
- package/dist/services/embedded-packages/npmrc.js.map +1 -1
- package/dist/services/embedded-packages/spec.d.ts +89 -17
- package/dist/services/embedded-packages/spec.js +199 -30
- package/dist/services/embedded-packages/spec.js.map +1 -1
- package/dist/services/embedded-packages/url.d.ts +39 -0
- package/dist/services/embedded-packages/url.js +60 -0
- package/dist/services/embedded-packages/url.js.map +1 -0
- package/dist/services/playwright-project-bundler.js +27 -23
- package/dist/services/playwright-project-bundler.js.map +1 -1
- package/dist/services/runner/registries.d.ts +144 -0
- package/dist/services/runner/registries.js +232 -0
- package/dist/services/runner/registries.js.map +1 -0
- package/oclif.manifest.json +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
3
|
+
import Debug from 'debug';
|
|
4
|
+
import { isMap, parse as parseYaml, parseDocument } from 'yaml';
|
|
5
|
+
import { pathToPosix } from '../util.js';
|
|
6
|
+
const debug = Debug('checkly:cli:services:check-parser:patched-dependencies');
|
|
7
|
+
/**
|
|
8
|
+
* Serialization options that make a `yaml` round trip of a pnpm lockfile
|
|
9
|
+
* byte-identical to what pnpm itself writes. `lineWidth: 0` disables the
|
|
10
|
+
* folding that would otherwise rewrap long `resolution:` lines, and
|
|
11
|
+
* `flowCollectionPadding: false` reproduces pnpm's unpadded `{integrity: ...}`
|
|
12
|
+
* spelling. Both are required; with either one at its default the serializer
|
|
13
|
+
* reformats lines it was not asked to touch.
|
|
14
|
+
*/
|
|
15
|
+
const YAML_STRINGIFY_OPTIONS = { lineWidth: 0, flowCollectionPadding: false };
|
|
16
|
+
const PATCHED_DEPENDENCIES = 'patchedDependencies';
|
|
17
|
+
/**
|
|
18
|
+
* The directory pnpm's own `pnpm patch-commit` writes patches to, relative to
|
|
19
|
+
* the workspace root. Shared so that the auto-include that bundles patches and
|
|
20
|
+
* the filtering that removes them cannot drift apart: widening one without the
|
|
21
|
+
* other would silently leave orphaned patch files in every bundle.
|
|
22
|
+
*/
|
|
23
|
+
export const PNPM_PATCHES_DIR = 'patches';
|
|
24
|
+
/**
|
|
25
|
+
* Whether an archive path names a patch file the filtering may remove from a
|
|
26
|
+
* bundle: a `.patch` directly under {@link PNPM_PATCHES_DIR}. A declaration
|
|
27
|
+
* may point anywhere, including at a file bundled for an unrelated reason, so
|
|
28
|
+
* only the conventional location is removable.
|
|
29
|
+
*/
|
|
30
|
+
export function isRemovablePatchPath(archivePath) {
|
|
31
|
+
return new RegExp(`^${PNPM_PATCHES_DIR}/[^/]+\\.patch$`).test(archivePath);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Reads a config's `patchedDependencies` map. Returns an empty map when the
|
|
35
|
+
* config declares none, and `undefined` when the file cannot be parsed or the
|
|
36
|
+
* map is not shaped as expected — callers treat that as "do not filter".
|
|
37
|
+
*/
|
|
38
|
+
export function readPatchedDependencies(config) {
|
|
39
|
+
let parsed;
|
|
40
|
+
try {
|
|
41
|
+
parsed = config.kind === 'package.json'
|
|
42
|
+
? JSON.parse(config.content)
|
|
43
|
+
// An empty or comment-only YAML document parses to null: an ordinary
|
|
44
|
+
// pnpm-workspace.yaml that declares no settings, not an unreadable file.
|
|
45
|
+
// JSON has no such spelling — JSON.parse throws on empty input.
|
|
46
|
+
: parseYaml(config.content) ?? {};
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
debug(`Could not parse ${config.archivePath}: ${err}`);
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
const container = config.kind === 'package.json'
|
|
56
|
+
? parsed.pnpm
|
|
57
|
+
: parsed;
|
|
58
|
+
if (container === undefined || container === null) {
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
if (typeof container !== 'object' || Array.isArray(container)) {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
const section = container[PATCHED_DEPENDENCIES];
|
|
65
|
+
if (section === undefined || section === null) {
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
if (typeof section !== 'object' || Array.isArray(section)) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
const declarations = [];
|
|
72
|
+
for (const [key, value] of Object.entries(section)) {
|
|
73
|
+
// pnpm only accepts a path string here. Anything else is a config this
|
|
74
|
+
// code does not understand, so it declines to touch the bundle at all.
|
|
75
|
+
if (typeof value !== 'string') {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
declarations.push({ key, patchPath: value });
|
|
79
|
+
}
|
|
80
|
+
return declarations;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Reads a lockfile's `patchedDependencies` section as key → patch hash.
|
|
84
|
+
* pnpm 10 records `{ hash, path }` objects and pnpm 11 a bare hash string;
|
|
85
|
+
* both are accepted. Returns `undefined` when the lockfile cannot be parsed.
|
|
86
|
+
*/
|
|
87
|
+
export function readLockfilePatchHashes(lockfileContent) {
|
|
88
|
+
let parsed;
|
|
89
|
+
try {
|
|
90
|
+
parsed = parseYaml(lockfileContent);
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
debug(`Could not parse the lockfile: ${err}`);
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
const hashes = new Map();
|
|
97
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
const section = parsed[PATCHED_DEPENDENCIES];
|
|
101
|
+
if (section === undefined || section === null) {
|
|
102
|
+
return hashes;
|
|
103
|
+
}
|
|
104
|
+
if (typeof section !== 'object' || Array.isArray(section)) {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
for (const [key, value] of Object.entries(section)) {
|
|
108
|
+
const hash = typeof value === 'string' ? value : value?.hash;
|
|
109
|
+
if (typeof hash !== 'string' || hash === '') {
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
hashes.set(key, hash);
|
|
113
|
+
}
|
|
114
|
+
return hashes;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Finds the single config whose `patchedDependencies` the bundle should be
|
|
118
|
+
* filtered against, or `undefined` when there is nothing to do or the configs
|
|
119
|
+
* cannot be used.
|
|
120
|
+
*
|
|
121
|
+
* Declining when more than one config declares a non-empty map is deliberate:
|
|
122
|
+
* pnpm picks ONE site and ignores the other wholesale, and which site wins
|
|
123
|
+
* depends on the pnpm major (10 prefers `package.json`, 11 ignores it
|
|
124
|
+
* entirely). Editing the losing site is not merely useless — emptying the
|
|
125
|
+
* winning one would promote the loser, changing which patches apply.
|
|
126
|
+
*/
|
|
127
|
+
function findDeclaringConfig(configs) {
|
|
128
|
+
const declaring = [];
|
|
129
|
+
for (const config of configs) {
|
|
130
|
+
const declarations = readPatchedDependencies(config);
|
|
131
|
+
if (declarations === undefined) {
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
if (declarations.length > 0) {
|
|
135
|
+
declaring.push({ config, declarations });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (declaring.length > 1) {
|
|
139
|
+
debug('More than one config declares patchedDependencies; leaving the bundle alone');
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
return declaring[0];
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Whether a patch declaration still applies to something in `lockfileContent`.
|
|
146
|
+
*
|
|
147
|
+
* pnpm records the applied patch by hash: the `patchedDependencies` section
|
|
148
|
+
* pins `key → hash`, and that hash reappears as `patch_hash=<hash>` in the
|
|
149
|
+
* importer, snapshot and package entries of every package the patch was
|
|
150
|
+
* applied to. A declaration that applies to nothing keeps its section entry —
|
|
151
|
+
* the section mirrors the config, not the dependency graph — but its hash
|
|
152
|
+
* appears nowhere else, which makes the marker the sole discriminator. A
|
|
153
|
+
* whole-file search is safe because the section's own value never contains
|
|
154
|
+
* the literal `patch_hash=`.
|
|
155
|
+
*/
|
|
156
|
+
function hasMarker(hash, lockfileContent) {
|
|
157
|
+
return hash !== undefined && lockfileContent.includes(`patch_hash=${hash}`);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Whether the prune is what stopped a patch from applying.
|
|
161
|
+
*
|
|
162
|
+
* Deliberately differential rather than a bare absence test on the pruned
|
|
163
|
+
* lockfile. Absence alone would mean that a lockfile this module cannot read
|
|
164
|
+
* markers out of — a future pnpm that keeps the `9` version string but spells
|
|
165
|
+
* them differently — reads as "nothing applies anywhere" and every declaration
|
|
166
|
+
* is stripped at once, which is the one outcome the module exists to prevent.
|
|
167
|
+
* Requiring the marker in the original first makes that case drop nothing.
|
|
168
|
+
*
|
|
169
|
+
* The pruned side falls back to the original's hash because a lockfile can
|
|
170
|
+
* lose the `patchedDependencies` section while keeping its markers; without
|
|
171
|
+
* the fallback such a patch would read as no longer applied.
|
|
172
|
+
*/
|
|
173
|
+
function droppedByPrune(key, prunedHashes, originalHashes, originalLockfileContent, prunedLockfileContent) {
|
|
174
|
+
const originalHash = originalHashes.get(key);
|
|
175
|
+
if (!hasMarker(originalHash, originalLockfileContent)) {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
return !hasMarker(prunedHashes.get(key) ?? originalHash, prunedLockfileContent);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Resolves a declared patch path to its archive path, or `undefined` when it
|
|
182
|
+
* escapes the workspace root (the archive's own root) and therefore does not
|
|
183
|
+
* name a bundle entry this code may remove.
|
|
184
|
+
*/
|
|
185
|
+
function patchArchivePath(patchPath) {
|
|
186
|
+
// Traversal is judged on the path AS WRITTEN, before any normalization:
|
|
187
|
+
// pathToPosix normalizes internally, which collapses `..` segments and would
|
|
188
|
+
// hide a path that leaves the root and comes back
|
|
189
|
+
// (`patches/sub/../../package.json` collapses to `package.json`, naming a
|
|
190
|
+
// bundle file that is not a patch at all).
|
|
191
|
+
if (patchPath.split(/[/\\]/).includes('..')) {
|
|
192
|
+
return undefined;
|
|
193
|
+
}
|
|
194
|
+
const normalized = pathToPosix(patchPath);
|
|
195
|
+
if (path.posix.isAbsolute(normalized)) {
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
// `.` (what an empty path normalizes to) and a trailing slash name a
|
|
199
|
+
// directory, not a patch file, so they must never reach a caller that
|
|
200
|
+
// deletes bundle entries.
|
|
201
|
+
if (normalized === '.' || normalized.endsWith('/')) {
|
|
202
|
+
return undefined;
|
|
203
|
+
}
|
|
204
|
+
// pathToPosix only rewrites the platform's own separator and strips C:/D:
|
|
205
|
+
// drive prefixes, so a spelling from another platform can survive looking
|
|
206
|
+
// relative yet still denote a path this comparison cannot align with.
|
|
207
|
+
if (normalized.includes('\\') || /^[A-Za-z]:/.test(normalized)) {
|
|
208
|
+
return undefined;
|
|
209
|
+
}
|
|
210
|
+
return normalized;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Computes the patch declarations a bundle should stop shipping, together with
|
|
214
|
+
* the rewritten files that carry the removal. Returns `undefined` whenever the
|
|
215
|
+
* evidence is incomplete or an edit cannot be verified — the caller then ships
|
|
216
|
+
* the bundle unchanged, which is always safe.
|
|
217
|
+
*/
|
|
218
|
+
export function planPatchFilter(options) {
|
|
219
|
+
const { configs, originalLockfileContent, prunedLockfileContent } = options;
|
|
220
|
+
const declaring = findDeclaringConfig(configs);
|
|
221
|
+
if (declaring === undefined) {
|
|
222
|
+
return undefined;
|
|
223
|
+
}
|
|
224
|
+
const originalHashes = readLockfilePatchHashes(originalLockfileContent);
|
|
225
|
+
const prunedHashes = readLockfilePatchHashes(prunedLockfileContent);
|
|
226
|
+
if (originalHashes === undefined || prunedHashes === undefined) {
|
|
227
|
+
return undefined;
|
|
228
|
+
}
|
|
229
|
+
const unusedKeys = [];
|
|
230
|
+
// Both sets hold ARCHIVE paths, never the raw spelling: two declarations can
|
|
231
|
+
// point at one file with different spellings (`./patches/x.patch` and
|
|
232
|
+
// `patches/x.patch`), and comparing raw strings would drop a file a
|
|
233
|
+
// surviving declaration still needs.
|
|
234
|
+
const keptArchivePaths = new Set();
|
|
235
|
+
const candidateArchivePaths = new Set();
|
|
236
|
+
// A surviving declaration whose path resolves outside the bundle root cannot
|
|
237
|
+
// be compared against the in-root candidates at all, so no file is dropped
|
|
238
|
+
// in that case. The declarations and lockfile entries still go; an
|
|
239
|
+
// unreferenced patch file left in the bundle is inert.
|
|
240
|
+
let keptPathEscapesRoot = false;
|
|
241
|
+
for (const declaration of declaring.declarations) {
|
|
242
|
+
const archivePath = patchArchivePath(declaration.patchPath);
|
|
243
|
+
// A key the project's own lockfile never recorded is no evidence of
|
|
244
|
+
// anything: the pnpm that wrote it may simply not read the site the key
|
|
245
|
+
// was declared in. Removing it would silently unpatch a dependency that a
|
|
246
|
+
// different pnpm on the runner would patch.
|
|
247
|
+
const recorded = originalHashes.has(declaration.key);
|
|
248
|
+
if (!recorded) {
|
|
249
|
+
debug(`Patch '${declaration.key}' is not recorded in the project's lockfile; leaving it alone`);
|
|
250
|
+
}
|
|
251
|
+
const dropped = recorded && droppedByPrune(declaration.key, prunedHashes, originalHashes, originalLockfileContent, prunedLockfileContent);
|
|
252
|
+
if (!dropped) {
|
|
253
|
+
if (archivePath === undefined) {
|
|
254
|
+
keptPathEscapesRoot = true;
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
keptArchivePaths.add(archivePath);
|
|
258
|
+
}
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
unusedKeys.push(declaration.key);
|
|
262
|
+
if (archivePath === undefined) {
|
|
263
|
+
debug(`Patch path '${declaration.patchPath}' resolves outside the bundle root; leaving it alone`);
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
candidateArchivePaths.add(archivePath);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (unusedKeys.length === 0) {
|
|
270
|
+
return undefined;
|
|
271
|
+
}
|
|
272
|
+
const removed = new Set(unusedKeys);
|
|
273
|
+
const configContent = rewriteConfig(declaring.config, removed);
|
|
274
|
+
if (configContent === undefined) {
|
|
275
|
+
return undefined;
|
|
276
|
+
}
|
|
277
|
+
const rewrittenConfig = {
|
|
278
|
+
archivePath: declaring.config.archivePath,
|
|
279
|
+
content: configContent,
|
|
280
|
+
};
|
|
281
|
+
const lockfileContent = rewriteYamlSection(prunedLockfileContent, removed);
|
|
282
|
+
if (lockfileContent === undefined) {
|
|
283
|
+
return undefined;
|
|
284
|
+
}
|
|
285
|
+
// Two declarations may share a patch file; keep it while any survivor still
|
|
286
|
+
// points at it.
|
|
287
|
+
const droppedPatchPaths = keptPathEscapesRoot
|
|
288
|
+
? []
|
|
289
|
+
: Array.from(candidateArchivePaths).filter(archivePath => !keptArchivePaths.has(archivePath));
|
|
290
|
+
return { unusedKeys, rewrittenConfig, droppedPatchPaths, lockfileContent };
|
|
291
|
+
}
|
|
292
|
+
function rewriteConfig(config, removed) {
|
|
293
|
+
return config.kind === 'package.json'
|
|
294
|
+
? rewritePackageJson(config.content, removed)
|
|
295
|
+
: rewriteYamlSection(config.content, removed);
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Removes keys from a YAML document's top-level `patchedDependencies` map,
|
|
299
|
+
* dropping the map itself once it empties. Shared by `pnpm-workspace.yaml` and
|
|
300
|
+
* `pnpm-lock.yaml`, whose sections have the same shape.
|
|
301
|
+
*
|
|
302
|
+
* The result is verified structurally before it is returned: a serializer that
|
|
303
|
+
* reformatted or dropped anything else would ship silently, and for the
|
|
304
|
+
* lockfile it would also invalidate the verification the pruner already ran
|
|
305
|
+
* over the bytes it produced.
|
|
306
|
+
*/
|
|
307
|
+
export function rewriteYamlSection(content, removed) {
|
|
308
|
+
// parseDocument collects syntax errors on the document rather than throwing,
|
|
309
|
+
// so `errors` — not a try/catch — is what rejects malformed input here.
|
|
310
|
+
const doc = parseDocument(content);
|
|
311
|
+
if (doc.errors.length > 0) {
|
|
312
|
+
debug(`Could not parse YAML for rewriting: ${doc.errors[0].message}`);
|
|
313
|
+
return undefined;
|
|
314
|
+
}
|
|
315
|
+
const section = doc.get(PATCHED_DEPENDENCIES);
|
|
316
|
+
if (section === undefined || section === null) {
|
|
317
|
+
// Nothing to delete. The prune can legitimately return a lockfile that
|
|
318
|
+
// carries no section at all, in which case only the config needs editing.
|
|
319
|
+
return content;
|
|
320
|
+
}
|
|
321
|
+
if (!isMap(section)) {
|
|
322
|
+
return undefined;
|
|
323
|
+
}
|
|
324
|
+
for (const key of removed) {
|
|
325
|
+
doc.deleteIn([PATCHED_DEPENDENCIES, key]);
|
|
326
|
+
}
|
|
327
|
+
if (section.items.length === 0) {
|
|
328
|
+
doc.delete(PATCHED_DEPENDENCIES);
|
|
329
|
+
}
|
|
330
|
+
const rewritten = doc.toString(YAML_STRINGIFY_OPTIONS);
|
|
331
|
+
return verifyRewrite(content, rewritten, removed, parseYaml);
|
|
332
|
+
}
|
|
333
|
+
function rewritePackageJson(content, removed) {
|
|
334
|
+
let parsed;
|
|
335
|
+
try {
|
|
336
|
+
parsed = JSON.parse(content);
|
|
337
|
+
}
|
|
338
|
+
catch (err) {
|
|
339
|
+
debug(`Could not parse package.json for rewriting: ${err}`);
|
|
340
|
+
return undefined;
|
|
341
|
+
}
|
|
342
|
+
const section = parsed?.pnpm?.[PATCHED_DEPENDENCIES];
|
|
343
|
+
if (section === null || typeof section !== 'object') {
|
|
344
|
+
return undefined;
|
|
345
|
+
}
|
|
346
|
+
for (const key of removed) {
|
|
347
|
+
delete section[key];
|
|
348
|
+
}
|
|
349
|
+
if (Object.keys(section).length === 0) {
|
|
350
|
+
delete parsed.pnpm[PATCHED_DEPENDENCIES];
|
|
351
|
+
}
|
|
352
|
+
// Unlike the YAML path, which is byte-preserving, this reformats the whole
|
|
353
|
+
// manifest. The bundled copy is only ever an install input — nothing reads it
|
|
354
|
+
// back as text — and matching the original's formatting would mean carrying a
|
|
355
|
+
// JSON editor for no behavioral gain.
|
|
356
|
+
const rewritten = JSON.stringify(parsed, null, 2);
|
|
357
|
+
return verifyRewrite(content, rewritten, removed, JSON.parse);
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Asserts that a rewrite changed nothing but the intended keys, by comparing
|
|
361
|
+
* the reparsed result against the reparsed original with those keys deleted.
|
|
362
|
+
* A config can carry anything else pnpm understands — `catalog:`, `overrides`,
|
|
363
|
+
* `onlyBuiltDependencies` — and nothing downstream would notice it being
|
|
364
|
+
* mangled, so the check is what makes the edit safe to ship.
|
|
365
|
+
*
|
|
366
|
+
* Exported so that the rejection path — which no legitimate serializer output
|
|
367
|
+
* reaches, and which therefore cannot be driven through the callers — is
|
|
368
|
+
* directly testable.
|
|
369
|
+
*
|
|
370
|
+
* Package pruning keeps an analogous fail-closed verifier in
|
|
371
|
+
* package-prune.ts (`verifyPrunedManifest`); hardening either against a
|
|
372
|
+
* manifest quirk likely applies to both.
|
|
373
|
+
*/
|
|
374
|
+
export function verifyRewrite(original, rewritten, removed, parse) {
|
|
375
|
+
let expected;
|
|
376
|
+
let actual;
|
|
377
|
+
try {
|
|
378
|
+
expected = parse(original);
|
|
379
|
+
actual = parse(rewritten);
|
|
380
|
+
}
|
|
381
|
+
catch (err) {
|
|
382
|
+
debug(`Could not reparse a rewritten file for verification: ${err}`);
|
|
383
|
+
return undefined;
|
|
384
|
+
}
|
|
385
|
+
for (const container of [expected, expected?.pnpm]) {
|
|
386
|
+
const section = container?.[PATCHED_DEPENDENCIES];
|
|
387
|
+
if (section === null || typeof section !== 'object') {
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
for (const key of removed) {
|
|
391
|
+
delete section[key];
|
|
392
|
+
}
|
|
393
|
+
if (Object.keys(section).length === 0) {
|
|
394
|
+
delete container[PATCHED_DEPENDENCIES];
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
if (!isDeepStrictEqual(expected, actual)) {
|
|
398
|
+
debug('A rewritten file did not match the expected structure; leaving the bundle alone');
|
|
399
|
+
return undefined;
|
|
400
|
+
}
|
|
401
|
+
return rewritten;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Reports declarations the shipped bundle still carries but its shipped
|
|
405
|
+
* lockfile no longer records — the precondition for the remote install failing
|
|
406
|
+
* with `ERR_PNPM_LOCKFILE_CONFIG_MISMATCH`.
|
|
407
|
+
*
|
|
408
|
+
* Scoped to keys the project's original lockfile recorded, so a declaration
|
|
409
|
+
* the project's own pnpm never honoured is not reported as a bundling problem.
|
|
410
|
+
*/
|
|
411
|
+
export function findUnrepairedPatchKeys(options) {
|
|
412
|
+
const { configs, originalLockfileContent, shippedLockfileContent } = options;
|
|
413
|
+
const originalHashes = readLockfilePatchHashes(originalLockfileContent);
|
|
414
|
+
const shippedHashes = readLockfilePatchHashes(shippedLockfileContent);
|
|
415
|
+
if (originalHashes === undefined || shippedHashes === undefined) {
|
|
416
|
+
return [];
|
|
417
|
+
}
|
|
418
|
+
const unrepaired = new Set();
|
|
419
|
+
for (const config of configs) {
|
|
420
|
+
for (const declaration of readPatchedDependencies(config) ?? []) {
|
|
421
|
+
if (originalHashes.has(declaration.key) && !shippedHashes.has(declaration.key)) {
|
|
422
|
+
unrepaired.add(declaration.key);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return Array.from(unrepaired).sort();
|
|
427
|
+
}
|
|
428
|
+
//# sourceMappingURL=patched-dependencies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patched-dependencies.js","sourceRoot":"","sources":["../../../src/services/check-parser/patched-dependencies.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,8 @@ import type { Region } from '../index.js';
|
|
|
5
5
|
import { ReporterType } from '../reporters/reporter.js';
|
|
6
6
|
import { PlaywrightConfig } from '../constructs/playwright-config.js';
|
|
7
7
|
import { FileLoader } from '../loader/index.js';
|
|
8
|
+
import { BundlePackagesPrune } from './check-parser/package-prune.js';
|
|
9
|
+
import { Registries } from './runner/registries.js';
|
|
8
10
|
export type CheckConfigDefaults = Pick<CheckProps, 'activated' | 'alertChannels' | 'alertEscalationPolicy' | 'doubleCheck' | 'frequency' | 'locations' | 'muted' | 'privateLocations' | 'retryStrategy' | 'shouldFail' | 'tags'> & Pick<RuntimeCheckProps, 'environmentVariables' | 'runtimeId'> & {
|
|
9
11
|
playwrightConfig?: PlaywrightConfig;
|
|
10
12
|
};
|
|
@@ -12,7 +14,7 @@ export type PlaywrightSlimmedProp = Pick<PlaywrightCheckProps, 'name' | 'activat
|
|
|
12
14
|
logicalId: string;
|
|
13
15
|
playwrightConfigPath?: string;
|
|
14
16
|
};
|
|
15
|
-
export type ChecklyConfig = {
|
|
17
|
+
export type ChecklyConfig<UpstreamName extends string = string> = {
|
|
16
18
|
/**
|
|
17
19
|
* Friendly name for your project.
|
|
18
20
|
*/
|
|
@@ -86,19 +88,117 @@ export type ChecklyConfig = {
|
|
|
86
88
|
* Each entry is a package name (`'@acme/private-utils'`), which embeds
|
|
87
89
|
* every version of that package found in the workspace lockfile, or an
|
|
88
90
|
* exact `name@version` pin (`'legacy-private-pkg@2.1.0'`). Names may
|
|
89
|
-
* contain `*` wildcards (`'@acme/*'`, `'acme-*'`); a
|
|
90
|
-
* crosses the `/` scope separator
|
|
91
|
+
* contain `*` wildcards (`'@acme/*'`, `'acme-*'`); a single `*` never
|
|
92
|
+
* crosses the `/` scope separator, while a `**` does — `'**'` matches
|
|
93
|
+
* every package, and `'**-foo'` matches names ending in `-foo` in any
|
|
94
|
+
* scope or none. Directly before a `/`, a `**` may together with that
|
|
95
|
+
* `/` also match nothing, glob-style: `'**' + '/utils'` (one string;
|
|
96
|
+
* split here only because `*` followed by `/` would end this comment)
|
|
97
|
+
* matches both `utils` and `@acme/utils`. (Earlier CLI releases
|
|
98
|
+
* treated a run of stars as a single `*`.) List every package the
|
|
99
|
+
* runner
|
|
91
100
|
* cannot fetch, including private packages that only appear as
|
|
92
101
|
* transitive dependencies of other private packages — dependencies of
|
|
93
102
|
* listed packages are not embedded automatically.
|
|
94
103
|
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
104
|
+
* A `!` prefix turns an entry into an exclusion, which removes the
|
|
105
|
+
* packages it matches from what the entries *before* it selected.
|
|
106
|
+
* Entries therefore apply in order: `['@acme/*', '!@acme/legacy']`
|
|
107
|
+
* embeds the whole scope except `@acme/legacy`, while the reverse
|
|
108
|
+
* order embeds the whole scope, because the exclusion runs before
|
|
109
|
+
* anything has been selected. An exclusion that removes nothing is a
|
|
110
|
+
* no-op rather than an error. Removing every package an entry
|
|
111
|
+
* selected also silences that entry: no "not found" error, and no
|
|
112
|
+
* "cannot be embedded" warning even for packages it matched but did
|
|
113
|
+
* not exclude — run with `DEBUG='checkly:cli:services:embedded-packages'`
|
|
114
|
+
* to see what it reached. Since exclusions only subtract, a list of
|
|
115
|
+
* nothing but exclusions selects nothing; a configuration whose
|
|
116
|
+
* entries select no packages at all is reported as a warning.
|
|
117
|
+
*
|
|
118
|
+
* Only npm, pnpm, bun and Yarn Berry are supported at this time:
|
|
119
|
+
* packages are resolved against the workspace lockfile
|
|
120
|
+
* (`pnpm-lock.yaml`, `package-lock.json`, the text `bun.lock` —
|
|
121
|
+
* bun's binary `bun.lockb` is not supported — or a Yarn Berry
|
|
122
|
+
* `yarn.lock`; Yarn Classic v1 lockfiles are not) and always
|
|
123
|
+
* verified against its recorded integrity hashes. Yarn Berry
|
|
124
|
+
* lockfiles record no npm tarball integrity, so it is resolved from
|
|
125
|
+
* the registry's package metadata instead — one small metadata
|
|
126
|
+
* request per embedded package on every deploy, even with a warm
|
|
127
|
+
* cache. Downloads read registry credentials from `npm_config_*`
|
|
128
|
+
* environment variables, the project, workspace-root and user
|
|
129
|
+
* `.npmrc` files, and pnpm's global `auth.ini` (where `pnpm login`
|
|
130
|
+
* writes tokens on pnpm 11 and later), including the
|
|
131
|
+
* scope-qualified keys `pnpm login --scope` writes. bun or yarn
|
|
132
|
+
* users whose credentials live solely in `bunfig.toml` or
|
|
133
|
+
* `.yarnrc.yml` must duplicate them into `.npmrc` or set
|
|
134
|
+
* `npm_config_*` — referencing a token through an environment
|
|
135
|
+
* variable (`${NPM_TOKEN}`), never as plaintext, because `.npmrc`
|
|
136
|
+
* is uploaded with the code bundle. When the bundled lockfile is pruned to the code
|
|
137
|
+
* bundle's contents, the embedded set follows it: packages the pruned
|
|
138
|
+
* lockfile no longer references — dependencies of workspace members
|
|
139
|
+
* that are not part of the bundle — are neither embedded nor
|
|
140
|
+
* downloaded, even if an entry matches them. That usually means the
|
|
141
|
+
* runner does not need the package at all; if the checks genuinely
|
|
142
|
+
* need it, make the depending workspace member part of the bundle
|
|
143
|
+
* rather than disabling pruning (`CHECKLY_LOCKFILE_PRUNE=0` restores
|
|
144
|
+
* the unfiltered set, as a last resort). Changing the resolved set of
|
|
145
|
+
* embedded packages invalidates the runner's dependency cache.
|
|
100
146
|
*/
|
|
101
147
|
embed?: string[];
|
|
148
|
+
/**
|
|
149
|
+
* Dependencies to remove from the `package.json` files shipped inside
|
|
150
|
+
* the code bundle — the workspace root's and every bundled workspace
|
|
151
|
+
* member's. Applies to Playwright Check Suites only. The files on
|
|
152
|
+
* disk are never modified; only the bundled copies are rewritten.
|
|
153
|
+
*
|
|
154
|
+
* The manifests are rewritten before the bundled lockfile is pruned
|
|
155
|
+
* to the code bundle's contents, so the removed dependencies fall out
|
|
156
|
+
* of the bundled lockfile too. This is the escape hatch for
|
|
157
|
+
* dependencies that lockfile pruning alone cannot drop: with pnpm's
|
|
158
|
+
* `auto-install-peers`, a bundled member's unused `peerDependencies`
|
|
159
|
+
* are resolved as real dependencies of the regenerated lockfile even
|
|
160
|
+
* though the bundled code never imports them. Because the rewritten
|
|
161
|
+
* manifests only make sense next to a matching lockfile, the option
|
|
162
|
+
* requires lockfile pruning: if the bundled lockfile cannot be pruned
|
|
163
|
+
* in the same run — an unsupported package manager, a failed
|
|
164
|
+
* regeneration, or `CHECKLY_LOCKFILE_PRUNE=0` — the original
|
|
165
|
+
* manifests ship unchanged, with a warning. A bundle that ships no
|
|
166
|
+
* lockfile has nothing to fall out of sync with, so the pruned
|
|
167
|
+
* manifests always ship there.
|
|
168
|
+
*
|
|
169
|
+
* Accepts either an array of package name patterns, removed from
|
|
170
|
+
* every dependency class (`dependencies`, `devDependencies`,
|
|
171
|
+
* `peerDependencies` and `optionalDependencies`), or an object keyed
|
|
172
|
+
* by dependency class whose values are `true` (remove the whole
|
|
173
|
+
* class) or a pattern array (remove matching entries from that class
|
|
174
|
+
* only). Names may contain `*` wildcards (`'@acme/*'`, `'acme-*'`);
|
|
175
|
+
* a single `*` never crosses the `/` scope separator, so a bare
|
|
176
|
+
* `'*'` matches only unscoped names, while a `**` does cross it —
|
|
177
|
+
* to remove a whole class, use `true` or `['**']`, not `['*']`.
|
|
178
|
+
* Wildcards follow `bundle.packages.embed`'s rules, including the
|
|
179
|
+
* glob-style zero-segment match of a `**` directly before a `/`.
|
|
180
|
+
* (Earlier CLI releases treated a run of stars as a single `*`.)
|
|
181
|
+
* A `!` prefix turns an entry into an exclusion that
|
|
182
|
+
* removes what it matches from the entries *before* it selected,
|
|
183
|
+
* with `bundle.packages.embed`'s order-sensitive semantics:
|
|
184
|
+
* `['@acme/*', '!@acme/keep']` removes the scope except
|
|
185
|
+
* `@acme/keep`, while the reverse order removes the whole scope
|
|
186
|
+
* because the exclusion runs before anything has been selected. To
|
|
187
|
+
* remove a whole class *except* some packages, select everything
|
|
188
|
+
* first: `['**', '!@acme/keep']`.
|
|
189
|
+
* `true` cannot be combined with exclusions. Unlike
|
|
190
|
+
* `bundle.packages.embed` there are no
|
|
191
|
+
* `name@version` pins; they are rejected at config load. Removed
|
|
192
|
+
* `peerDependencies` take their `peerDependenciesMeta` entries with
|
|
193
|
+
* them, and `peerDependencies: true` clears `peerDependenciesMeta`
|
|
194
|
+
* entirely.
|
|
195
|
+
*
|
|
196
|
+
* Pruning is not validated against the code: you are responsible for
|
|
197
|
+
* not removing anything the bundled code actually needs at runtime.
|
|
198
|
+
* A pattern that matches nothing is not an error. Changing the
|
|
199
|
+
* pruned output invalidates the runner's dependency cache.
|
|
200
|
+
*/
|
|
201
|
+
prune?: BundlePackagesPrune;
|
|
102
202
|
};
|
|
103
203
|
};
|
|
104
204
|
/**
|
|
@@ -113,8 +213,10 @@ export type ChecklyConfig = {
|
|
|
113
213
|
dependencyCache?: {
|
|
114
214
|
/**
|
|
115
215
|
* Optional value mixed into the code bundle's cache hash in addition
|
|
116
|
-
* to its usual inputs
|
|
117
|
-
* the
|
|
216
|
+
* to its usual inputs — the workspace's dependency-install inputs.
|
|
217
|
+
* The exhaustive input list lives with the hash itself; see
|
|
218
|
+
* `ComposeCacheHashInput` in
|
|
219
|
+
* `services/check-parser/cache-hash.ts`.
|
|
118
220
|
* Change the value to force runners to reinstall the bundle's
|
|
119
221
|
* dependencies. Setting it for the first time invalidates the cache
|
|
120
222
|
* once. Numbers must be safe integers; unset and empty string leave
|
|
@@ -130,6 +232,58 @@ export type ChecklyConfig = {
|
|
|
130
232
|
version?: string | number;
|
|
131
233
|
};
|
|
132
234
|
};
|
|
235
|
+
/**
|
|
236
|
+
* Configuration applied on the Checkly runner when it executes checks.
|
|
237
|
+
*/
|
|
238
|
+
runner?: {
|
|
239
|
+
/**
|
|
240
|
+
* Registry routing for the dependency install of a Playwright Check
|
|
241
|
+
* Suite code bundle. Use this when the registries your `.npmrc` (or
|
|
242
|
+
* `pnpm-workspace.yaml` / `.yarnrc.yml`) points at resolve fine on
|
|
243
|
+
* the machine running the CLI but are unreachable from Checkly
|
|
244
|
+
* runners — e.g. a VPN-only mirror. When set, the runner installs
|
|
245
|
+
* packages through a local registry that selects upstreams according
|
|
246
|
+
* to these rules instead of the registries named in bundled config
|
|
247
|
+
* files; embedded packages (`bundle.packages.embed`) always take
|
|
248
|
+
* priority regardless of the rules. Applies to Playwright Check
|
|
249
|
+
* Suites only, and only on the runner: operations on the machine
|
|
250
|
+
* running the CLI — embedded-package downloads, lockfile pruning —
|
|
251
|
+
* still read `.npmrc` and `npm_config_*` credentials.
|
|
252
|
+
*
|
|
253
|
+
* `upstreams` names the registries the runner may fetch from. Each
|
|
254
|
+
* needs a base `url` (an absolute http(s) URL without query,
|
|
255
|
+
* fragment or inline credentials, since package paths are appended
|
|
256
|
+
* to it) and may carry bearer `auth`. An auth token must be exactly
|
|
257
|
+
* one environment variable reference in `${VAR}` syntax (e.g.
|
|
258
|
+
* `'${NPM_TOKEN}'`, in single quotes so the shell-like syntax is not
|
|
259
|
+
* expanded locally): the value is resolved from the check's
|
|
260
|
+
* environment variables on the runner, so the secret value appears
|
|
261
|
+
* in neither the config nor the uploaded code bundle. Any literal
|
|
262
|
+
* token content is rejected at config load.
|
|
263
|
+
*
|
|
264
|
+
* `packages` routes package names to upstreams, first match wins,
|
|
265
|
+
* top-down. Patterns use the same wildcard syntax as
|
|
266
|
+
* `bundle.packages.embed` (a single `*` never crosses the `/` scope
|
|
267
|
+
* separator, `**` does), but no `!` exclusions and no
|
|
268
|
+
* `name@version` pins. Each rule lists one or more upstream names
|
|
269
|
+
* tried in order — the first upstream that serves the package wins,
|
|
270
|
+
* and a 404 or unreachable upstream falls through to the next
|
|
271
|
+
* upstream in the same rule, never to a later rule (a broader rule
|
|
272
|
+
* as fallback would leak private package names to its upstreams).
|
|
273
|
+
* The last rule must be the match-all rule
|
|
274
|
+
* (`{ pattern: '**', ... }`) so every package has a route; a rule
|
|
275
|
+
* placed after a match-all could never apply and is rejected.
|
|
276
|
+
* Changing this configuration invalidates the runner's dependency
|
|
277
|
+
* cache.
|
|
278
|
+
*
|
|
279
|
+
* `defineConfig` type-checks that every upstream name used in
|
|
280
|
+
* `packages` is defined under `upstreams`; define the registries
|
|
281
|
+
* object inline in the config literal, since the check relies on
|
|
282
|
+
* type inference from the `upstreams` keys. The same rules are also
|
|
283
|
+
* enforced at config load for plain-JS configs.
|
|
284
|
+
*/
|
|
285
|
+
registries?: Registries<UpstreamName>;
|
|
286
|
+
};
|
|
133
287
|
/**
|
|
134
288
|
* CLI default configuration properties.
|
|
135
289
|
*/
|