@blamejs/core 0.12.7 → 0.12.8
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/CHANGELOG.md +2 -0
- package/lib/archive-tar-read.js +418 -0
- package/lib/archive-tar.js +557 -0
- package/lib/archive.js +5 -0
- package/lib/audit.js +22 -7
- package/lib/backup/index.js +196 -12
- package/lib/guard-archive.js +40 -0
- package/lib/safe-archive.js +35 -15
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/backup/index.js
CHANGED
|
@@ -65,6 +65,8 @@ var compliance = lazyRequire(function () { return require("../compliance"); });
|
|
|
65
65
|
// module graph (CLI tools, stand-alone backup runners). The db()
|
|
66
66
|
// callable resolves on first access.
|
|
67
67
|
var dbModuleLazy = lazyRequire(function () { return require("../db"); });
|
|
68
|
+
var archiveLazy = lazyRequire(function () { return require("../archive"); });
|
|
69
|
+
var archiveAdaptersLazy = lazyRequire(function () { return require("../archive-adapters"); });
|
|
68
70
|
var { defineClass } = require("../framework-error");
|
|
69
71
|
|
|
70
72
|
var BackupError = defineClass("BackupError");
|
|
@@ -993,6 +995,7 @@ module.exports = {
|
|
|
993
995
|
create: create,
|
|
994
996
|
diskStorage: diskStorage,
|
|
995
997
|
bundleAdapterStorage: bundleAdapterStorage,
|
|
998
|
+
migrate: migrate,
|
|
996
999
|
recommendedFiles: recommendedFiles,
|
|
997
1000
|
runInWorker: runInWorker,
|
|
998
1001
|
verifyManifestSignature: verifyManifestSignature,
|
|
@@ -1055,6 +1058,35 @@ function bundleAdapterStorage(opts) {
|
|
|
1055
1058
|
"bundleAdapterStorage: adapter missing method '" + required[i] + "'");
|
|
1056
1059
|
}
|
|
1057
1060
|
}
|
|
1061
|
+
// v0.12.8 — `format: "tar"` becomes the default for new bundles.
|
|
1062
|
+
// `format: "directory"` opts back into the v0.12.7 file-by-file
|
|
1063
|
+
// layout for operators with existing bundles. The format is
|
|
1064
|
+
// operator-supplied so a single backup engine can transition over
|
|
1065
|
+
// time + b.backup.migrate() handles the directory → tar conversion.
|
|
1066
|
+
var format = opts.format || "tar";
|
|
1067
|
+
if (format !== "tar" && format !== "directory") {
|
|
1068
|
+
throw new BackupError("backup/bad-format",
|
|
1069
|
+
"bundleAdapterStorage: format must be \"tar\" (default) or \"directory\" (legacy v0.12.7)");
|
|
1070
|
+
}
|
|
1071
|
+
// Codex P2 on v0.12.8 PR #159 — tar mode builds the whole archive
|
|
1072
|
+
// in memory before adapter.writeFile because the v0.12.8 adapter
|
|
1073
|
+
// contract is bytes-in (no writeStream method). The OOM-prevention
|
|
1074
|
+
// gate is maxBundleBytes: writeBundle pre-walks the source tree,
|
|
1075
|
+
// sums file sizes, and refuses upfront if the projected uncompressed
|
|
1076
|
+
// tar would exceed the cap. Default 8 GiB — accommodates typical
|
|
1077
|
+
// db + mail-spool + log bundles while refusing pathological inputs.
|
|
1078
|
+
// Defer-with-condition for true streaming: when the adapter
|
|
1079
|
+
// contract gains writeStream(key) (slated for v0.13+ alongside
|
|
1080
|
+
// multipart S3 upload primitives), this path switches to
|
|
1081
|
+
// tarBuilder.toStream() and writes chunks as they're produced.
|
|
1082
|
+
var maxBundleBytes = opts.maxBundleBytes !== undefined
|
|
1083
|
+
? opts.maxBundleBytes
|
|
1084
|
+
: 8 * 1024 * 1024 * 1024; // allow:raw-byte-literal — 8 GiB default cap; uses C.BYTES.bytes covers numeric-literal rule
|
|
1085
|
+
if (!numericBounds.isPositiveFiniteInt(maxBundleBytes)) { // allow:inline-numeric-bounds-cascade — required-with-default opt
|
|
1086
|
+
throw new BackupError("backup/bad-arg",
|
|
1087
|
+
"bundleAdapterStorage: maxBundleBytes must be a positive finite integer; got " +
|
|
1088
|
+
numericBounds.shape(opts.maxBundleBytes));
|
|
1089
|
+
}
|
|
1058
1090
|
|
|
1059
1091
|
function _ensureBundleId(bundleId) {
|
|
1060
1092
|
if (!_isValidBundleId(bundleId)) {
|
|
@@ -1078,6 +1110,17 @@ function bundleAdapterStorage(opts) {
|
|
|
1078
1110
|
return out;
|
|
1079
1111
|
}
|
|
1080
1112
|
|
|
1113
|
+
// Tar-format bundle storage stores the whole bundle as a single
|
|
1114
|
+
// key under `<bundleId>/bundle.tar`. The marker is named that way
|
|
1115
|
+
// so listBundles + hasBundle can locate either format by key
|
|
1116
|
+
// prefix walk.
|
|
1117
|
+
var TAR_KEY_SUFFIX = "/bundle.tar";
|
|
1118
|
+
|
|
1119
|
+
function _hasBundleKey(bundleId, format) {
|
|
1120
|
+
if (format === "tar") return adapter.hasKey(bundleId + TAR_KEY_SUFFIX);
|
|
1121
|
+
return adapter.hasKey(bundleId + "/manifest.json");
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1081
1124
|
return {
|
|
1082
1125
|
name: "adapter",
|
|
1083
1126
|
async writeBundle(bundleId, sourceDir) {
|
|
@@ -1086,16 +1129,52 @@ function bundleAdapterStorage(opts) {
|
|
|
1086
1129
|
throw new BackupError("backup/no-source",
|
|
1087
1130
|
"writeBundle: sourceDir does not exist: " + sourceDir);
|
|
1088
1131
|
}
|
|
1089
|
-
var alreadyHas = await
|
|
1132
|
+
var alreadyHas = await _hasBundleKey(bundleId, format);
|
|
1090
1133
|
if (alreadyHas) {
|
|
1091
1134
|
throw new BackupError("backup/bundle-exists",
|
|
1092
1135
|
"writeBundle: bundle '" + bundleId + "' already exists in storage");
|
|
1093
1136
|
}
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1137
|
+
if (format === "tar") {
|
|
1138
|
+
// Pack the source-directory tree into a single tar archive +
|
|
1139
|
+
// store under one key. Composes b.archive.tar.
|
|
1140
|
+
//
|
|
1141
|
+
// Codex P2 on v0.12.8 PR #159 — tar bytes are materialized in
|
|
1142
|
+
// memory because the v0.12.8 adapter contract is bytes-in
|
|
1143
|
+
// (writeFile takes a Buffer, no writeStream method). The
|
|
1144
|
+
// maxBundleBytes pre-walk computes the uncompressed payload
|
|
1145
|
+
// size (file bytes only — tar header overhead is bounded at
|
|
1146
|
+
// ~512 B per entry + 1024 B trailer) and refuses upfront so
|
|
1147
|
+
// pathological inputs throw `backup/bundle-too-large` instead
|
|
1148
|
+
// of OOM. The defer-with-condition for true streaming is
|
|
1149
|
+
// gated on the adapter contract gaining writeStream(key).
|
|
1150
|
+
var relPaths = _walkDirSync(sourceDir, []);
|
|
1151
|
+
var projectedBytes = 0;
|
|
1152
|
+
for (var pi = 0; pi < relPaths.length; pi += 1) {
|
|
1153
|
+
var stat = nodeFs.statSync(nodePath.join(sourceDir, relPaths[pi]));
|
|
1154
|
+
projectedBytes += stat.size;
|
|
1155
|
+
}
|
|
1156
|
+
if (projectedBytes > maxBundleBytes) {
|
|
1157
|
+
throw new BackupError("backup/bundle-too-large",
|
|
1158
|
+
"writeBundle: projected uncompressed bundle " + projectedBytes +
|
|
1159
|
+
" bytes exceeds maxBundleBytes=" + maxBundleBytes +
|
|
1160
|
+
" — split the source tree across multiple bundles or raise the cap");
|
|
1161
|
+
}
|
|
1162
|
+
var t = archiveLazy().tar();
|
|
1163
|
+
for (var i = 0; i < relPaths.length; i += 1) {
|
|
1164
|
+
var rel = relPaths[i];
|
|
1165
|
+
var bytes = nodeFs.readFileSync(nodePath.join(sourceDir, rel));
|
|
1166
|
+
t.addFile(rel, bytes);
|
|
1167
|
+
}
|
|
1168
|
+
var tarBytes = t.toBuffer();
|
|
1169
|
+
await adapter.writeFile(bundleId + TAR_KEY_SUFFIX, tarBytes);
|
|
1170
|
+
return;
|
|
1171
|
+
}
|
|
1172
|
+
// Directory format (v0.12.7 layout).
|
|
1173
|
+
var dirRelPaths = _walkDirSync(sourceDir, []);
|
|
1174
|
+
for (var j = 0; j < dirRelPaths.length; j += 1) {
|
|
1175
|
+
var dirRel = dirRelPaths[j];
|
|
1176
|
+
var dirBytes = nodeFs.readFileSync(nodePath.join(sourceDir, dirRel));
|
|
1177
|
+
await adapter.writeFile(bundleId + "/" + dirRel, dirBytes);
|
|
1099
1178
|
}
|
|
1100
1179
|
},
|
|
1101
1180
|
async readBundle(bundleId, destDir) {
|
|
@@ -1104,20 +1183,29 @@ function bundleAdapterStorage(opts) {
|
|
|
1104
1183
|
throw new BackupError("backup/dest-exists",
|
|
1105
1184
|
"readBundle: destDir already exists: " + destDir);
|
|
1106
1185
|
}
|
|
1107
|
-
|
|
1108
|
-
|
|
1186
|
+
// Detect which format this bundle is in — operators with mixed
|
|
1187
|
+
// pre-v0.12.8 + post-v0.12.8 bundles can read either back.
|
|
1188
|
+
var hasTar = await adapter.hasKey(bundleId + TAR_KEY_SUFFIX);
|
|
1189
|
+
var hasManifest = await adapter.hasKey(bundleId + "/manifest.json");
|
|
1190
|
+
if (!hasTar && !hasManifest) {
|
|
1109
1191
|
throw new BackupError("backup/bundle-not-found",
|
|
1110
1192
|
"readBundle: '" + bundleId + "' not in storage");
|
|
1111
1193
|
}
|
|
1112
1194
|
atomicFile.ensureDir(destDir);
|
|
1195
|
+
if (hasTar) {
|
|
1196
|
+
var tarBytes = await adapter.readFile(bundleId + TAR_KEY_SUFFIX);
|
|
1197
|
+
var reader = archiveLazy().read.tar(archiveAdaptersLazy().buffer(tarBytes));
|
|
1198
|
+
await reader.extract({ destination: destDir });
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1201
|
+
// Directory format readback (v0.12.7 layout).
|
|
1202
|
+
var keys = await adapter.listKeys(bundleId + "/");
|
|
1113
1203
|
for (var i = 0; i < keys.length; i += 1) {
|
|
1114
1204
|
var key = keys[i];
|
|
1115
1205
|
var prefix = bundleId + "/";
|
|
1116
1206
|
if (key.indexOf(prefix) !== 0) continue;
|
|
1117
1207
|
var rel = key.slice(prefix.length);
|
|
1118
|
-
// Path-safety: rel must not escape destDir.
|
|
1119
|
-
// verifyExtractionPath dual-check primitive when the dest
|
|
1120
|
-
// already exists (writeable directory just created).
|
|
1208
|
+
// Path-safety: rel must not escape destDir.
|
|
1121
1209
|
var destPath = nodePath.join(destDir, rel);
|
|
1122
1210
|
var resolvedDest = nodePath.resolve(destPath);
|
|
1123
1211
|
var resolvedRoot = nodePath.resolve(destDir);
|
|
@@ -1175,7 +1263,15 @@ function bundleAdapterStorage(opts) {
|
|
|
1175
1263
|
},
|
|
1176
1264
|
async hasBundle(bundleId) {
|
|
1177
1265
|
_ensureBundleId(bundleId);
|
|
1178
|
-
|
|
1266
|
+
// Format-aware: check the storage layout's marker key. Tar
|
|
1267
|
+
// bundles store under <bid>/bundle.tar; directory bundles store
|
|
1268
|
+
// under <bid>/manifest.json. Operators with a mixed bundle set
|
|
1269
|
+
// (some tar, some directory) get true for either.
|
|
1270
|
+
var tarKey = bundleId + TAR_KEY_SUFFIX;
|
|
1271
|
+
var dirKey = bundleId + "/manifest.json";
|
|
1272
|
+
if (await adapter.hasKey(tarKey)) return true;
|
|
1273
|
+
if (await adapter.hasKey(dirKey)) return true;
|
|
1274
|
+
return false;
|
|
1179
1275
|
},
|
|
1180
1276
|
};
|
|
1181
1277
|
}
|
|
@@ -1244,3 +1340,91 @@ bundleAdapterStorage.fsAdapter = function (fsOpts) {
|
|
|
1244
1340
|
},
|
|
1245
1341
|
};
|
|
1246
1342
|
};
|
|
1343
|
+
|
|
1344
|
+
// ---- v0.12.8: migrate ----------------------------------------------------
|
|
1345
|
+
|
|
1346
|
+
/**
|
|
1347
|
+
* @primitive b.backup.migrate
|
|
1348
|
+
* @signature b.backup.migrate(opts)
|
|
1349
|
+
* @since 0.12.8
|
|
1350
|
+
* @status stable
|
|
1351
|
+
* @related b.backup.bundleAdapterStorage
|
|
1352
|
+
*
|
|
1353
|
+
* One-shot helper that walks an operator's directory-tree-format
|
|
1354
|
+
* bundle (v0.12.7 layout) and writes the same content as a tar-format
|
|
1355
|
+
* bundle via the v0.12.8 `bundleAdapterStorage`. Idempotent: re-
|
|
1356
|
+
* running on an already-migrated bundle is a no-op. Source stays in
|
|
1357
|
+
* place by default; operators with explicit transition windows opt
|
|
1358
|
+
* into the inline replace via `deleteSourceOnSuccess: true`.
|
|
1359
|
+
*
|
|
1360
|
+
* @opts
|
|
1361
|
+
* from: bundleAdapterStorage with format: "directory",
|
|
1362
|
+
* to: bundleAdapterStorage with format: "tar",
|
|
1363
|
+
* bundleId: string (single-bundle migrate; omit to migrate all),
|
|
1364
|
+
* deleteSourceOnSuccess: boolean (default false; explicit opt-in),
|
|
1365
|
+
*
|
|
1366
|
+
* @example
|
|
1367
|
+
* var from = b.backup.bundleAdapterStorage({
|
|
1368
|
+
* adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: "/var/backups-v7" }),
|
|
1369
|
+
* format: "directory",
|
|
1370
|
+
* });
|
|
1371
|
+
* var to = b.backup.bundleAdapterStorage({
|
|
1372
|
+
* adapter: b.backup.bundleAdapterStorage.fsAdapter({ root: "/var/backups-v8" }),
|
|
1373
|
+
* format: "tar",
|
|
1374
|
+
* });
|
|
1375
|
+
* await b.backup.migrate({ from: from, to: to });
|
|
1376
|
+
*/
|
|
1377
|
+
async function migrate(opts) {
|
|
1378
|
+
opts = opts || {};
|
|
1379
|
+
if (!opts.from || typeof opts.from.readBundle !== "function" ||
|
|
1380
|
+
typeof opts.from.listBundles !== "function") {
|
|
1381
|
+
throw new BackupError("backup/bad-from",
|
|
1382
|
+
"migrate: opts.from must be a storage backend (got " + typeof opts.from + ")");
|
|
1383
|
+
}
|
|
1384
|
+
if (!opts.to || typeof opts.to.writeBundle !== "function" ||
|
|
1385
|
+
typeof opts.to.hasBundle !== "function") {
|
|
1386
|
+
throw new BackupError("backup/bad-to",
|
|
1387
|
+
"migrate: opts.to must be a storage backend (got " + typeof opts.to + ")");
|
|
1388
|
+
}
|
|
1389
|
+
var ids;
|
|
1390
|
+
if (opts.bundleId) {
|
|
1391
|
+
if (!_isValidBundleId(opts.bundleId)) {
|
|
1392
|
+
throw new BackupError("backup/bad-bundle-id",
|
|
1393
|
+
"migrate: bundleId must match the framework's timestamp+suffix format");
|
|
1394
|
+
}
|
|
1395
|
+
ids = [opts.bundleId];
|
|
1396
|
+
} else {
|
|
1397
|
+
var list = await opts.from.listBundles();
|
|
1398
|
+
ids = list.map(function (b) { return b.bundleId; });
|
|
1399
|
+
}
|
|
1400
|
+
var migrated = 0;
|
|
1401
|
+
var skipped = 0;
|
|
1402
|
+
for (var i = 0; i < ids.length; i += 1) {
|
|
1403
|
+
var bid = ids[i];
|
|
1404
|
+
// Idempotency: skip if destination already has the bundle.
|
|
1405
|
+
if (await opts.to.hasBundle(bid)) {
|
|
1406
|
+
skipped += 1;
|
|
1407
|
+
continue;
|
|
1408
|
+
}
|
|
1409
|
+
// Stage source-bundle into a tmp dir, then write via destination.
|
|
1410
|
+
var tmpDir = nodeFs.mkdtempSync(nodePath.join(os.tmpdir(),
|
|
1411
|
+
"blamejs-backup-migrate-" + bid + "-"));
|
|
1412
|
+
var stageDir = nodePath.join(tmpDir, "bundle");
|
|
1413
|
+
try {
|
|
1414
|
+
await opts.from.readBundle(bid, stageDir);
|
|
1415
|
+
await opts.to.writeBundle(bid, stageDir);
|
|
1416
|
+
migrated += 1;
|
|
1417
|
+
if (opts.deleteSourceOnSuccess === true) {
|
|
1418
|
+
if (typeof opts.from.deleteBundle === "function") {
|
|
1419
|
+
await opts.from.deleteBundle(bid);
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
} finally {
|
|
1423
|
+
try { nodeFs.rmSync(tmpDir, { recursive: true, force: true }); }
|
|
1424
|
+
catch (_e) { /* drop-silent */ }
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
return { migrated: migrated, skipped: skipped, total: ids.length };
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
|
package/lib/guard-archive.js
CHANGED
|
@@ -902,6 +902,7 @@ module.exports = {
|
|
|
902
902
|
inspect: inspect,
|
|
903
903
|
zipBombPolicy: zipBombPolicy,
|
|
904
904
|
entryTypePolicy: entryTypePolicy,
|
|
905
|
+
tarEntryPolicy: tarEntryPolicy,
|
|
905
906
|
};
|
|
906
907
|
|
|
907
908
|
// ---- v0.12.7 extensions ---------------------------------------------------
|
|
@@ -1039,3 +1040,42 @@ function entryTypePolicy(opts) {
|
|
|
1039
1040
|
sockets: opts.sockets === true,
|
|
1040
1041
|
});
|
|
1041
1042
|
}
|
|
1043
|
+
|
|
1044
|
+
/**
|
|
1045
|
+
* @primitive b.guardArchive.tarEntryPolicy
|
|
1046
|
+
* @signature b.guardArchive.tarEntryPolicy(opts)
|
|
1047
|
+
* @since 0.12.8
|
|
1048
|
+
* @status stable
|
|
1049
|
+
* @related b.guardArchive.entryTypePolicy, b.archive.read.tar
|
|
1050
|
+
*
|
|
1051
|
+
* Tar-specific entry-type policy. Same shape as `entryTypePolicy`
|
|
1052
|
+
* but explicitly named for tar's typeflag vocabulary (1=hardlink,
|
|
1053
|
+
* 2=symlink, 3=char-device, 4=block-device, 6=FIFO, 7=contiguous-
|
|
1054
|
+
* file) so call sites read clearly when the operator's intent is
|
|
1055
|
+
* tar-specific. Defaults refuse every dangerous typeflag. Operators
|
|
1056
|
+
* opting symlinks / hardlinks in get the link target routed through
|
|
1057
|
+
* `b.guardFilename.verifyExtractionPath`'s realpath-on-target check
|
|
1058
|
+
* (defends CVE-2026-23745 / 24842 node-tar path-resolution divergence
|
|
1059
|
+
* class).
|
|
1060
|
+
*
|
|
1061
|
+
* @opts
|
|
1062
|
+
* symlinks: false,
|
|
1063
|
+
* hardlinks: false,
|
|
1064
|
+
* devices: false,
|
|
1065
|
+
* fifos: false,
|
|
1066
|
+
* sockets: false,
|
|
1067
|
+
*
|
|
1068
|
+
* @example
|
|
1069
|
+
* var policy = b.guardArchive.tarEntryPolicy({ symlinks: true });
|
|
1070
|
+
* await b.safeArchive.extract({
|
|
1071
|
+
* source, destination, entryTypePolicy: policy,
|
|
1072
|
+
* allowDangerous: { symlinks: true },
|
|
1073
|
+
* });
|
|
1074
|
+
*/
|
|
1075
|
+
function tarEntryPolicy(opts) {
|
|
1076
|
+
// Same shape as entryTypePolicy; aliased for tar-specific call-site
|
|
1077
|
+
// readability. The implementation is intentionally identical — the
|
|
1078
|
+
// policy-object shape is format-neutral, only the typeflag mapping
|
|
1079
|
+
// in the reader differs.
|
|
1080
|
+
return entryTypePolicy(opts);
|
|
1081
|
+
}
|
package/lib/safe-archive.js
CHANGED
|
@@ -45,6 +45,7 @@ var SafeArchiveError = defineClass("SafeArchiveError", { alwaysPermanent: true }
|
|
|
45
45
|
|
|
46
46
|
var archiveRead = lazyRequire(function () { return require("./archive-read"); });
|
|
47
47
|
var archiveAdapters = lazyRequire(function () { return require("./archive-adapters"); });
|
|
48
|
+
var archiveTarRead = lazyRequire(function () { return require("./archive-tar-read"); });
|
|
48
49
|
|
|
49
50
|
// ---- Format sniffing ----------------------------------------------------
|
|
50
51
|
|
|
@@ -178,18 +179,30 @@ async function extract(opts) {
|
|
|
178
179
|
var sniff = await _sniffMagic(source);
|
|
179
180
|
format = sniff.format;
|
|
180
181
|
}
|
|
181
|
-
|
|
182
|
+
var reader;
|
|
183
|
+
if (format === "zip") {
|
|
184
|
+
reader = archiveRead().zip(source, {
|
|
185
|
+
bombPolicy: opts.bombPolicy,
|
|
186
|
+
entryTypePolicy: opts.entryTypePolicy,
|
|
187
|
+
guardProfile: opts.guardProfile,
|
|
188
|
+
audit: opts.audit,
|
|
189
|
+
});
|
|
190
|
+
} else if (format === "tar") {
|
|
191
|
+
reader = archiveTarRead().tar(source, {
|
|
192
|
+
bombPolicy: opts.bombPolicy,
|
|
193
|
+
entryTypePolicy: opts.entryTypePolicy,
|
|
194
|
+
guardProfile: opts.guardProfile,
|
|
195
|
+
audit: opts.audit,
|
|
196
|
+
});
|
|
197
|
+
} else {
|
|
182
198
|
throw new SafeArchiveError("safe-archive/format-unsupported",
|
|
183
|
-
"extract: format=" + JSON.stringify(format) + " — v0.12.
|
|
184
|
-
"(
|
|
199
|
+
"extract: format=" + JSON.stringify(format) + " — v0.12.8 ships ZIP + tar " +
|
|
200
|
+
"(gz lands v0.12.9, encryptPacked-wrap lands v0.12.10)");
|
|
185
201
|
}
|
|
186
|
-
var
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
guardProfile: opts.guardProfile,
|
|
190
|
-
audit: opts.audit,
|
|
202
|
+
var result = await reader.extract({
|
|
203
|
+
destination: opts.destination,
|
|
204
|
+
allowDangerous: opts.allowDangerous,
|
|
191
205
|
});
|
|
192
|
-
var result = await reader.extract({ destination: opts.destination });
|
|
193
206
|
return Object.assign({ format: format }, result);
|
|
194
207
|
} finally {
|
|
195
208
|
if (typeof source.close === "function" && typeof opts.source === "string") {
|
|
@@ -238,14 +251,21 @@ async function inspect(opts) {
|
|
|
238
251
|
var sniff = await _sniffMagic(source);
|
|
239
252
|
format = sniff.format;
|
|
240
253
|
}
|
|
241
|
-
|
|
254
|
+
var reader;
|
|
255
|
+
if (format === "zip") {
|
|
256
|
+
reader = archiveRead().zip(source, {
|
|
257
|
+
bombPolicy: opts.bombPolicy,
|
|
258
|
+
audit: opts.audit,
|
|
259
|
+
});
|
|
260
|
+
} else if (format === "tar") {
|
|
261
|
+
reader = archiveTarRead().tar(source, {
|
|
262
|
+
bombPolicy: opts.bombPolicy,
|
|
263
|
+
audit: opts.audit,
|
|
264
|
+
});
|
|
265
|
+
} else {
|
|
242
266
|
throw new SafeArchiveError("safe-archive/format-unsupported",
|
|
243
|
-
"inspect: format=" + JSON.stringify(format) + " — v0.12.
|
|
267
|
+
"inspect: format=" + JSON.stringify(format) + " — v0.12.8 ships ZIP + tar");
|
|
244
268
|
}
|
|
245
|
-
var reader = archiveRead().zip(source, {
|
|
246
|
-
bombPolicy: opts.bombPolicy,
|
|
247
|
-
audit: opts.audit,
|
|
248
|
-
});
|
|
249
269
|
var entries = await reader.inspect();
|
|
250
270
|
var totalCompressed = 0;
|
|
251
271
|
var totalUncompressed = 0;
|
package/package.json
CHANGED
package/sbom.cdx.json
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
|
|
3
3
|
"bomFormat": "CycloneDX",
|
|
4
4
|
"specVersion": "1.5",
|
|
5
|
-
"serialNumber": "urn:uuid:
|
|
5
|
+
"serialNumber": "urn:uuid:4e14c3b7-7b58-4756-ba67-d2bcef61b25b",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-05-
|
|
8
|
+
"timestamp": "2026-05-23T16:36:21.469Z",
|
|
9
9
|
"lifecycles": [
|
|
10
10
|
{
|
|
11
11
|
"phase": "build"
|
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
}
|
|
20
20
|
],
|
|
21
21
|
"component": {
|
|
22
|
-
"bom-ref": "@blamejs/core@0.12.
|
|
22
|
+
"bom-ref": "@blamejs/core@0.12.8",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "blamejs",
|
|
25
|
-
"version": "0.12.
|
|
25
|
+
"version": "0.12.8",
|
|
26
26
|
"scope": "required",
|
|
27
27
|
"author": "blamejs contributors",
|
|
28
28
|
"description": "The Node framework that owns its stack.",
|
|
29
|
-
"purl": "pkg:npm/%40blamejs/core@0.12.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/core@0.12.8",
|
|
30
30
|
"properties": [],
|
|
31
31
|
"externalReferences": [
|
|
32
32
|
{
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"components": [],
|
|
55
55
|
"dependencies": [
|
|
56
56
|
{
|
|
57
|
-
"ref": "@blamejs/core@0.12.
|
|
57
|
+
"ref": "@blamejs/core@0.12.8",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|