wyvrnpm 2.10.2 → 2.12.2
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/README.md +1914 -1860
- package/bin/{wyvrn.js → wyvrnpm.js} +66 -0
- package/cmake/cpp.cmake +9 -9
- package/cmake/functions.cmake +224 -224
- package/cmake/macros.cmake +284 -284
- package/package.json +3 -2
- package/src/auth.js +66 -66
- package/src/binary-dir.js +95 -0
- package/src/bootstrap/cookbook.js +196 -196
- package/src/bootstrap/detect.js +150 -150
- package/src/bootstrap/index.js +220 -220
- package/src/bootstrap/version.js +72 -72
- package/src/build/cache.js +344 -344
- package/src/build/clone.js +170 -170
- package/src/build/cmake.js +342 -342
- package/src/build/index.js +299 -297
- package/src/build/msvc-env.js +260 -260
- package/src/build/recipe.js +188 -188
- package/src/commands/add.js +141 -141
- package/src/commands/bootstrap.js +96 -96
- package/src/commands/build.js +482 -452
- package/src/commands/cache.js +189 -189
- package/src/commands/clean.js +80 -80
- package/src/commands/configure.js +92 -92
- package/src/commands/init.js +70 -70
- package/src/commands/install-skill.js +115 -115
- package/src/commands/install.js +730 -674
- package/src/commands/link.js +320 -320
- package/src/commands/profile.js +237 -237
- package/src/commands/publish.js +584 -555
- package/src/commands/show.js +252 -252
- package/src/commands/version.js +187 -0
- package/src/compat.js +273 -273
- package/src/conf/index.js +415 -391
- package/src/conf/namespaces.js +94 -94
- package/src/context.js +230 -230
- package/src/http-fetch.js +53 -53
- package/src/ignore.js +118 -118
- package/src/logger.js +122 -122
- package/src/options.js +303 -303
- package/src/settings-overrides.js +152 -152
- package/src/toolchain/deps.js +164 -164
- package/src/toolchain/index.js +212 -212
- package/src/toolchain/presets.js +356 -340
- package/src/toolchain/template.cmake +77 -77
- package/src/upload-built.js +265 -265
- package/src/version-range.js +301 -301
- package/src/zip-safe.js +52 -52
- package/src/zip-stream.js +126 -0
package/src/zip-safe.js
CHANGED
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Defense-in-depth against Zip Slip (CVE-2018-1002200 family). Both
|
|
5
|
-
* node-stream-zip and adm-zip claim to handle this upstream, but we
|
|
6
|
-
* don't want to take the library's word for it on a supply-chain-
|
|
7
|
-
* critical code path. Pre-scan zip entry names before extraction and
|
|
8
|
-
* reject anything that could write outside the target directory.
|
|
9
|
-
*
|
|
10
|
-
* The ZIP spec uses forward slashes only, but Windows-produced archives
|
|
11
|
-
* sometimes leak backslashes — normalise both.
|
|
12
|
-
*
|
|
13
|
-
* @param {string} entryName zip-internal path as reported by the zip library
|
|
14
|
-
* @param {string} [context] optional archive identifier for the error message
|
|
15
|
-
* @throws {Error} if the entry name is absolute, contains a path-traversal
|
|
16
|
-
* segment, or starts with a Windows drive-letter prefix.
|
|
17
|
-
*/
|
|
18
|
-
function assertSafeZipEntryName(entryName, context) {
|
|
19
|
-
const where = context ? ` in ${context}` : '';
|
|
20
|
-
|
|
21
|
-
if (/^[A-Za-z]:[\\/]/.test(entryName)) {
|
|
22
|
-
throw new Error(`unsafe zip entry${where}: drive-letter absolute path ${JSON.stringify(entryName)}`);
|
|
23
|
-
}
|
|
24
|
-
if (entryName.startsWith('/') || entryName.startsWith('\\')) {
|
|
25
|
-
throw new Error(`unsafe zip entry${where}: absolute path ${JSON.stringify(entryName)}`);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const segments = entryName.split(/[\\/]+/);
|
|
29
|
-
for (const seg of segments) {
|
|
30
|
-
if (seg === '..') {
|
|
31
|
-
throw new Error(`unsafe zip entry${where}: path-traversal segment in ${JSON.stringify(entryName)}`);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Convenience: validate every name in an iterable. Throws on the first
|
|
38
|
-
* offender (fail-fast) rather than collecting all violations.
|
|
39
|
-
*
|
|
40
|
-
* @param {Iterable<string>} names
|
|
41
|
-
* @param {string} [context]
|
|
42
|
-
*/
|
|
43
|
-
function assertAllSafeZipEntryNames(names, context) {
|
|
44
|
-
for (const name of names) {
|
|
45
|
-
assertSafeZipEntryName(name, context);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
module.exports = {
|
|
50
|
-
assertSafeZipEntryName,
|
|
51
|
-
assertAllSafeZipEntryNames,
|
|
52
|
-
};
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Defense-in-depth against Zip Slip (CVE-2018-1002200 family). Both
|
|
5
|
+
* node-stream-zip and adm-zip claim to handle this upstream, but we
|
|
6
|
+
* don't want to take the library's word for it on a supply-chain-
|
|
7
|
+
* critical code path. Pre-scan zip entry names before extraction and
|
|
8
|
+
* reject anything that could write outside the target directory.
|
|
9
|
+
*
|
|
10
|
+
* The ZIP spec uses forward slashes only, but Windows-produced archives
|
|
11
|
+
* sometimes leak backslashes — normalise both.
|
|
12
|
+
*
|
|
13
|
+
* @param {string} entryName zip-internal path as reported by the zip library
|
|
14
|
+
* @param {string} [context] optional archive identifier for the error message
|
|
15
|
+
* @throws {Error} if the entry name is absolute, contains a path-traversal
|
|
16
|
+
* segment, or starts with a Windows drive-letter prefix.
|
|
17
|
+
*/
|
|
18
|
+
function assertSafeZipEntryName(entryName, context) {
|
|
19
|
+
const where = context ? ` in ${context}` : '';
|
|
20
|
+
|
|
21
|
+
if (/^[A-Za-z]:[\\/]/.test(entryName)) {
|
|
22
|
+
throw new Error(`unsafe zip entry${where}: drive-letter absolute path ${JSON.stringify(entryName)}`);
|
|
23
|
+
}
|
|
24
|
+
if (entryName.startsWith('/') || entryName.startsWith('\\')) {
|
|
25
|
+
throw new Error(`unsafe zip entry${where}: absolute path ${JSON.stringify(entryName)}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const segments = entryName.split(/[\\/]+/);
|
|
29
|
+
for (const seg of segments) {
|
|
30
|
+
if (seg === '..') {
|
|
31
|
+
throw new Error(`unsafe zip entry${where}: path-traversal segment in ${JSON.stringify(entryName)}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Convenience: validate every name in an iterable. Throws on the first
|
|
38
|
+
* offender (fail-fast) rather than collecting all violations.
|
|
39
|
+
*
|
|
40
|
+
* @param {Iterable<string>} names
|
|
41
|
+
* @param {string} [context]
|
|
42
|
+
*/
|
|
43
|
+
function assertAllSafeZipEntryNames(names, context) {
|
|
44
|
+
for (const name of names) {
|
|
45
|
+
assertSafeZipEntryName(name, context);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
module.exports = {
|
|
50
|
+
assertSafeZipEntryName,
|
|
51
|
+
assertAllSafeZipEntryNames,
|
|
52
|
+
};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Streaming zip writer. Replaces adm-zip's load-into-memory model on
|
|
4
|
+
// the publish + source-build write paths so multi-GB files (gRPC
|
|
5
|
+
// static libs, embedded test corpora, …) don't trip Node's
|
|
6
|
+
// `Buffer.byteLength` cap of ~2 GiB inside `fs.readFileSync`.
|
|
7
|
+
//
|
|
8
|
+
// Wraps `archiver` behind an adm-zip-compatible facade
|
|
9
|
+
// (`addLocalFile(fullPath, zipDir)`) so existing call sites stay
|
|
10
|
+
// largely unchanged — the only structural difference is that
|
|
11
|
+
// `finalize()` is async (the file is written progressively as entries
|
|
12
|
+
// are added; closing the underlying stream is what flushes the
|
|
13
|
+
// central directory). Adm-zip's `writeZip()` was sync and required
|
|
14
|
+
// holding the full archive in memory.
|
|
15
|
+
//
|
|
16
|
+
// archiver auto-promotes to ZIP64 when the archive crosses the 4 GB
|
|
17
|
+
// or >65535-entries thresholds, so consumers using `node-stream-zip`
|
|
18
|
+
// (the default extraction path in [src/download.js](download.js))
|
|
19
|
+
// continue to extract correctly without any special handling.
|
|
20
|
+
//
|
|
21
|
+
// adm-zip stays in deps for the consumer-side reading we still do in
|
|
22
|
+
// `install-skill` and the small write of `scripts/repack-skill.js`,
|
|
23
|
+
// where bundle sizes are measured in KB and adm-zip's API is simpler.
|
|
24
|
+
|
|
25
|
+
const fs = require('fs');
|
|
26
|
+
const path = require('path');
|
|
27
|
+
const archiver = require('archiver');
|
|
28
|
+
|
|
29
|
+
class StreamingZipWriter {
|
|
30
|
+
/**
|
|
31
|
+
* @param {string} outPath Output path for the zip file.
|
|
32
|
+
* @param {object} [opts]
|
|
33
|
+
* @param {number} [opts.compressionLevel=6] zlib level 0..9.
|
|
34
|
+
* archiver default is 9 (max compression). 6 is the widely-accepted
|
|
35
|
+
* "balanced" pick — for our artefact mix (mostly already-compressed
|
|
36
|
+
* binaries: .lib/.dll, JPEGs, PNGs in test fixtures), level 9 burns
|
|
37
|
+
* minutes for sub-percent gains over level 6. Override per-call if
|
|
38
|
+
* the artefact is text-heavy.
|
|
39
|
+
*/
|
|
40
|
+
constructor(outPath, opts = {}) {
|
|
41
|
+
const { compressionLevel = 6 } = opts;
|
|
42
|
+
|
|
43
|
+
this._outPath = outPath;
|
|
44
|
+
this._out = fs.createWriteStream(outPath);
|
|
45
|
+
this._archive = archiver('zip', { zlib: { level: compressionLevel } });
|
|
46
|
+
this._closed = false;
|
|
47
|
+
this._error = null;
|
|
48
|
+
|
|
49
|
+
// Wire error propagation up front. archiver emits 'warning' for
|
|
50
|
+
// recoverable issues (e.g. ENOENT on a file that vanished between
|
|
51
|
+
// queue and read) — we propagate ALL of them rather than silently
|
|
52
|
+
// dropping content (CLAUDE.md §2 principle 8: silent fallback is a
|
|
53
|
+
// bug). adm-zip's `readFileSync` would have failed loudly in the
|
|
54
|
+
// same scenario; matching that behaviour here means a
|
|
55
|
+
// disappearing file during publish surfaces as an error rather
|
|
56
|
+
// than a silently-incomplete artefact.
|
|
57
|
+
this._archive.on('error', (err) => { this._error = err; });
|
|
58
|
+
this._archive.on('warning', (err) => { this._error = err; });
|
|
59
|
+
this._out.on('error', (err) => { this._error = err; });
|
|
60
|
+
|
|
61
|
+
this._archive.pipe(this._out);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Stream a file into the archive at `<zipDir>/<basename(fullPath)>`.
|
|
66
|
+
* adm-zip-compatible signature so existing publish/source-build
|
|
67
|
+
* helpers (which were written against `AdmZip#addLocalFile`) work
|
|
68
|
+
* without per-call refactor.
|
|
69
|
+
*
|
|
70
|
+
* No `fs.readFileSync` happens here — archiver opens a read stream
|
|
71
|
+
* lazily during `.finalize()`. Memory usage stays flat regardless of
|
|
72
|
+
* file size.
|
|
73
|
+
*
|
|
74
|
+
* @param {string} fullPath Absolute path on disk.
|
|
75
|
+
* @param {string} zipDir Directory inside the zip (forward
|
|
76
|
+
* slashes); empty string places the file at the zip root.
|
|
77
|
+
*/
|
|
78
|
+
addLocalFile(fullPath, zipDir) {
|
|
79
|
+
if (this._error) throw this._error;
|
|
80
|
+
const base = path.basename(fullPath);
|
|
81
|
+
const name = (typeof zipDir === 'string' && zipDir.length > 0)
|
|
82
|
+
? `${zipDir.replace(/\\/g, '/')}/${base}`
|
|
83
|
+
: base;
|
|
84
|
+
this._archive.file(fullPath, { name });
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Stream a Buffer / string into the archive at the given path. Used
|
|
89
|
+
* for synthesised entries that aren't on disk (the publish flow
|
|
90
|
+
* doesn't hit this today, but it keeps parity with adm-zip's
|
|
91
|
+
* `addFile(path, content)` for future use).
|
|
92
|
+
*
|
|
93
|
+
* @param {string} zipPath
|
|
94
|
+
* @param {Buffer|string} content
|
|
95
|
+
*/
|
|
96
|
+
addFile(zipPath, content) {
|
|
97
|
+
if (this._error) throw this._error;
|
|
98
|
+
this._archive.append(content, { name: zipPath.replace(/\\/g, '/') });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Close the archive and flush bytes to disk. Must be awaited — the
|
|
103
|
+
* file is not fully written until the underlying WriteStream emits
|
|
104
|
+
* `close`.
|
|
105
|
+
*
|
|
106
|
+
* @returns {Promise<void>}
|
|
107
|
+
*/
|
|
108
|
+
finalize() {
|
|
109
|
+
if (this._closed) return Promise.resolve();
|
|
110
|
+
this._closed = true;
|
|
111
|
+
return new Promise((resolve, reject) => {
|
|
112
|
+
// Reject if any error already accumulated before finalize was called.
|
|
113
|
+
if (this._error) return reject(this._error);
|
|
114
|
+
|
|
115
|
+
this._out.on('close', () => {
|
|
116
|
+
if (this._error) reject(this._error);
|
|
117
|
+
else resolve();
|
|
118
|
+
});
|
|
119
|
+
this._out.on('error', reject);
|
|
120
|
+
this._archive.on('error', reject);
|
|
121
|
+
this._archive.finalize();
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
module.exports = { StreamingZipWriter };
|