@cyclonedx/cdxgen 10.4.0 → 10.4.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/analyzer.js +10 -13
- package/bin/cdxgen.js +2 -1
- package/bin/repl.js +4 -4
- package/bin/verify.js +3 -4
- package/binary.js +19 -19
- package/cbomutils.js +2 -2
- package/display.js +6 -7
- package/docker.js +57 -64
- package/envcontext.js +6 -7
- package/evinser.js +33 -33
- package/index.js +924 -1011
- package/package.json +4 -4
- package/postgen.js +3 -6
- package/protobom.test.js +1 -1
- package/types/analyzer.d.ts.map +1 -1
- package/types/binary.d.ts.map +1 -1
- package/types/db.d.ts +2 -1
- package/types/db.d.ts.map +1 -1
- package/types/display.d.ts.map +1 -1
- package/types/docker.d.ts +1 -1
- package/types/docker.d.ts.map +1 -1
- package/types/evinser.d.ts +12 -12
- package/types/evinser.d.ts.map +1 -1
- package/types/index.d.ts.map +1 -1
- package/types/postgen.d.ts.map +1 -1
- package/types/utils.d.ts +25 -1
- package/types/utils.d.ts.map +1 -1
- package/types/validator.d.ts.map +1 -1
- package/utils.js +260 -323
- package/utils.test.js +11 -8
- package/validator.js +11 -14
package/analyzer.js
CHANGED
|
@@ -72,9 +72,7 @@ const getAllFiles = (deep, dir, extn, files, result, regex) => {
|
|
|
72
72
|
result,
|
|
73
73
|
regex,
|
|
74
74
|
);
|
|
75
|
-
} catch (error) {
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
75
|
+
} catch (error) {}
|
|
78
76
|
} else {
|
|
79
77
|
if (regex.test(file)) {
|
|
80
78
|
result.push(file);
|
|
@@ -143,8 +141,8 @@ const setFileRef = (
|
|
|
143
141
|
exportedModules,
|
|
144
142
|
isExternal: true,
|
|
145
143
|
fileName: fileRelativeLoc,
|
|
146
|
-
lineNumber: sourceLoc
|
|
147
|
-
columnNumber: sourceLoc
|
|
144
|
+
lineNumber: sourceLoc?.line ? sourceLoc.line : undefined,
|
|
145
|
+
columnNumber: sourceLoc?.column ? sourceLoc.column : undefined,
|
|
148
146
|
};
|
|
149
147
|
// replace relative imports with full path
|
|
150
148
|
let moduleFullPath = pathway;
|
|
@@ -169,7 +167,7 @@ const setFileRef = (
|
|
|
169
167
|
allImports[modPkg] = allImports[modPkg] || new Set();
|
|
170
168
|
allImports[modPkg].add(occurrence);
|
|
171
169
|
}
|
|
172
|
-
if (exportedModules
|
|
170
|
+
if (exportedModules?.length) {
|
|
173
171
|
moduleFullPath = moduleFullPath
|
|
174
172
|
.replace("node_modules/", "")
|
|
175
173
|
.replace("dist/", "")
|
|
@@ -194,7 +192,7 @@ const fileToParseableCode = (file) => {
|
|
|
194
192
|
.replace(vueCommentRegex, (match) => match.replaceAll(/\S/g, " "))
|
|
195
193
|
.replace(
|
|
196
194
|
vueCleaningRegex,
|
|
197
|
-
(match) => match.replaceAll(/\S/g, " ").substring(1)
|
|
195
|
+
(match) => `${match.replaceAll(/\S/g, " ").substring(1)};`,
|
|
198
196
|
)
|
|
199
197
|
.replace(
|
|
200
198
|
vueBindRegex,
|
|
@@ -203,7 +201,7 @@ const fileToParseableCode = (file) => {
|
|
|
203
201
|
)
|
|
204
202
|
.replace(
|
|
205
203
|
vuePropRegex,
|
|
206
|
-
(match, grA, grB) =>
|
|
204
|
+
(match, grA, grB) => ` ${grA.replace(/[.:@]/g, " ")}${grB}`,
|
|
207
205
|
)
|
|
208
206
|
.replace(
|
|
209
207
|
vueTemplateRegex,
|
|
@@ -222,7 +220,7 @@ const parseFileASTTree = (src, file, allImports, allExports) => {
|
|
|
222
220
|
const ast = parse(fileToParseableCode(file), babelParserOptions);
|
|
223
221
|
traverse.default(ast, {
|
|
224
222
|
ImportDeclaration: (path) => {
|
|
225
|
-
if (path
|
|
223
|
+
if (path?.node) {
|
|
226
224
|
setFileRef(
|
|
227
225
|
allImports,
|
|
228
226
|
allExports,
|
|
@@ -236,8 +234,7 @@ const parseFileASTTree = (src, file, allImports, allExports) => {
|
|
|
236
234
|
// For require('') statements
|
|
237
235
|
Identifier: (path) => {
|
|
238
236
|
if (
|
|
239
|
-
path &&
|
|
240
|
-
path.node &&
|
|
237
|
+
path?.node &&
|
|
241
238
|
path.node.name === "require" &&
|
|
242
239
|
path.parent.type === "CallExpression"
|
|
243
240
|
) {
|
|
@@ -246,7 +243,7 @@ const parseFileASTTree = (src, file, allImports, allExports) => {
|
|
|
246
243
|
},
|
|
247
244
|
// Use for dynamic imports like routes.jsx
|
|
248
245
|
CallExpression: (path) => {
|
|
249
|
-
if (path
|
|
246
|
+
if (path?.node && path.node.callee.type === "Import") {
|
|
250
247
|
setFileRef(allImports, allExports, src, file, path.node.arguments[0]);
|
|
251
248
|
}
|
|
252
249
|
},
|
|
@@ -256,7 +253,7 @@ const parseFileASTTree = (src, file, allImports, allExports) => {
|
|
|
256
253
|
},
|
|
257
254
|
ExportNamedDeclaration: (path) => {
|
|
258
255
|
// ensure there is a path export
|
|
259
|
-
if (path
|
|
256
|
+
if (path?.node?.source) {
|
|
260
257
|
setFileRef(
|
|
261
258
|
allImports,
|
|
262
259
|
allExports,
|
package/bin/cdxgen.js
CHANGED
|
@@ -591,7 +591,7 @@ const checkPermissions = (filePath) => {
|
|
|
591
591
|
}
|
|
592
592
|
// bom ns mapping
|
|
593
593
|
if (bomNSData.nsMapping && Object.keys(bomNSData.nsMapping).length) {
|
|
594
|
-
const nsFile = jsonFile
|
|
594
|
+
const nsFile = `${jsonFile}.map`;
|
|
595
595
|
fs.writeFileSync(nsFile, JSON.stringify(bomNSData.nsMapping));
|
|
596
596
|
}
|
|
597
597
|
} else if (!options.print) {
|
|
@@ -646,6 +646,7 @@ const checkPermissions = (filePath) => {
|
|
|
646
646
|
}
|
|
647
647
|
}
|
|
648
648
|
// Automatically submit the bom data
|
|
649
|
+
// biome-ignore lint/suspicious/noDoubleEquals: yargs passes true for empty values
|
|
649
650
|
if (options.serverUrl && options.serverUrl != true && options.apiKey) {
|
|
650
651
|
try {
|
|
651
652
|
const dbody = await submitBom(options, bomNSData.bomJson);
|
package/bin/repl.js
CHANGED
|
@@ -58,7 +58,7 @@ if (!process.env.CDXGEN_REPL_HISTORY && !fs.existsSync(historyConfigDir)) {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
export const importSbom = (sbomOrPath) => {
|
|
61
|
-
if (sbomOrPath
|
|
61
|
+
if (sbomOrPath?.endsWith(".json") && fs.existsSync(sbomOrPath)) {
|
|
62
62
|
try {
|
|
63
63
|
sbom = JSON.parse(fs.readFileSync(sbomOrPath, "utf-8"));
|
|
64
64
|
console.log(`✅ SBOM imported successfully from ${sbomOrPath}`);
|
|
@@ -298,12 +298,12 @@ cdxgenRepl.defineCommand("update", {
|
|
|
298
298
|
return;
|
|
299
299
|
}
|
|
300
300
|
if (!updateSpec.startsWith("|")) {
|
|
301
|
-
updateSpec =
|
|
301
|
+
updateSpec = `|${updateSpec}`;
|
|
302
302
|
}
|
|
303
303
|
if (!updateSpec.endsWith("|")) {
|
|
304
|
-
updateSpec = updateSpec
|
|
304
|
+
updateSpec = `${updateSpec}|`;
|
|
305
305
|
}
|
|
306
|
-
updateSpec =
|
|
306
|
+
updateSpec = `$ ~> ${updateSpec}`;
|
|
307
307
|
const expression = jsonata(updateSpec);
|
|
308
308
|
const newSbom = await expression.evaluate(sbom);
|
|
309
309
|
if (newSbom && newSbom.components.length <= sbom.components.length) {
|
package/bin/verify.js
CHANGED
|
@@ -61,10 +61,9 @@ for (const comp of bomJson.components) {
|
|
|
61
61
|
if (hasInvalidComp) {
|
|
62
62
|
process.exit(1);
|
|
63
63
|
}
|
|
64
|
-
const bomSignature =
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
: undefined;
|
|
64
|
+
const bomSignature = bomJson.signature?.value
|
|
65
|
+
? bomJson.signature.value
|
|
66
|
+
: undefined;
|
|
68
67
|
if (!bomSignature) {
|
|
69
68
|
console.log("No signature was found!");
|
|
70
69
|
} else {
|
package/binary.js
CHANGED
|
@@ -83,7 +83,7 @@ if (
|
|
|
83
83
|
dirName,
|
|
84
84
|
"node_modules",
|
|
85
85
|
"@cyclonedx",
|
|
86
|
-
|
|
86
|
+
`cdxgen-plugins-bin${pluginsBinSuffix}`,
|
|
87
87
|
"plugins",
|
|
88
88
|
),
|
|
89
89
|
) &&
|
|
@@ -92,7 +92,7 @@ if (
|
|
|
92
92
|
dirName,
|
|
93
93
|
"node_modules",
|
|
94
94
|
"@cyclonedx",
|
|
95
|
-
|
|
95
|
+
`cdxgen-plugins-bin${pluginsBinSuffix}`,
|
|
96
96
|
"plugins",
|
|
97
97
|
"goversion",
|
|
98
98
|
),
|
|
@@ -102,7 +102,7 @@ if (
|
|
|
102
102
|
dirName,
|
|
103
103
|
"node_modules",
|
|
104
104
|
"@cyclonedx",
|
|
105
|
-
|
|
105
|
+
`cdxgen-plugins-bin${pluginsBinSuffix}`,
|
|
106
106
|
"plugins",
|
|
107
107
|
);
|
|
108
108
|
}
|
|
@@ -120,7 +120,7 @@ if (!CDXGEN_PLUGINS_DIR) {
|
|
|
120
120
|
if (result) {
|
|
121
121
|
const stdout = result.stdout;
|
|
122
122
|
if (stdout) {
|
|
123
|
-
globalNodePath = Buffer.from(stdout).toString().trim()
|
|
123
|
+
globalNodePath = `${Buffer.from(stdout).toString().trim()}/`;
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
}
|
|
@@ -128,7 +128,7 @@ if (!CDXGEN_PLUGINS_DIR) {
|
|
|
128
128
|
const globalPlugins = join(
|
|
129
129
|
globalNodePath,
|
|
130
130
|
"@cyclonedx",
|
|
131
|
-
|
|
131
|
+
`cdxgen-plugins-bin${pluginsBinSuffix}`,
|
|
132
132
|
"plugins",
|
|
133
133
|
);
|
|
134
134
|
if (existsSync(globalPlugins)) {
|
|
@@ -153,7 +153,7 @@ if (existsSync(join(CDXGEN_PLUGINS_DIR, "goversion"))) {
|
|
|
153
153
|
GOVERSION_BIN = join(
|
|
154
154
|
CDXGEN_PLUGINS_DIR,
|
|
155
155
|
"goversion",
|
|
156
|
-
|
|
156
|
+
`goversion-${platform}-${arch}${extn}`,
|
|
157
157
|
);
|
|
158
158
|
}
|
|
159
159
|
let TRIVY_BIN = null;
|
|
@@ -161,7 +161,7 @@ if (existsSync(join(CDXGEN_PLUGINS_DIR, "trivy"))) {
|
|
|
161
161
|
TRIVY_BIN = join(
|
|
162
162
|
CDXGEN_PLUGINS_DIR,
|
|
163
163
|
"trivy",
|
|
164
|
-
|
|
164
|
+
`trivy-cdxgen-${platform}-${arch}${extn}`,
|
|
165
165
|
);
|
|
166
166
|
} else if (process.env.TRIVY_CMD) {
|
|
167
167
|
TRIVY_BIN = process.env.TRIVY_CMD;
|
|
@@ -171,7 +171,7 @@ if (existsSync(join(CDXGEN_PLUGINS_DIR, "cargo-auditable"))) {
|
|
|
171
171
|
CARGO_AUDITABLE_BIN = join(
|
|
172
172
|
CDXGEN_PLUGINS_DIR,
|
|
173
173
|
"cargo-auditable",
|
|
174
|
-
|
|
174
|
+
`cargo-auditable-cdxgen-${platform}-${arch}${extn}`,
|
|
175
175
|
);
|
|
176
176
|
} else if (process.env.CARGO_AUDITABLE_CMD) {
|
|
177
177
|
CARGO_AUDITABLE_BIN = process.env.CARGO_AUDITABLE_CMD;
|
|
@@ -181,7 +181,7 @@ if (existsSync(join(CDXGEN_PLUGINS_DIR, "osquery"))) {
|
|
|
181
181
|
OSQUERY_BIN = join(
|
|
182
182
|
CDXGEN_PLUGINS_DIR,
|
|
183
183
|
"osquery",
|
|
184
|
-
|
|
184
|
+
`osqueryi-${platform}-${arch}${extn}`,
|
|
185
185
|
);
|
|
186
186
|
// osqueryi-darwin-amd64.app/Contents/MacOS/osqueryd
|
|
187
187
|
if (platform === "darwin") {
|
|
@@ -199,7 +199,7 @@ if (existsSync(join(CDXGEN_PLUGINS_DIR, "dosai"))) {
|
|
|
199
199
|
DOSAI_BIN = join(
|
|
200
200
|
CDXGEN_PLUGINS_DIR,
|
|
201
201
|
"dosai",
|
|
202
|
-
|
|
202
|
+
`dosai-${platformToUse}-${arch}${extn}`,
|
|
203
203
|
);
|
|
204
204
|
} else if (process.env.DOSAI_CMD) {
|
|
205
205
|
DOSAI_BIN = process.env.DOSAI_CMD;
|
|
@@ -389,7 +389,7 @@ export function getOSPackages(src) {
|
|
|
389
389
|
// ignore errors
|
|
390
390
|
}
|
|
391
391
|
// Clean up
|
|
392
|
-
if (tempDir
|
|
392
|
+
if (tempDir?.startsWith(tmpdir())) {
|
|
393
393
|
if (DEBUG_MODE) {
|
|
394
394
|
console.log(`Cleaning up ${tempDir}`);
|
|
395
395
|
}
|
|
@@ -451,13 +451,13 @@ export function getOSPackages(src) {
|
|
|
451
451
|
break;
|
|
452
452
|
}
|
|
453
453
|
if (osReleaseData["VERSION_ID"]) {
|
|
454
|
-
distro_id = distro_id
|
|
454
|
+
distro_id = `${distro_id}-${osReleaseData["VERSION_ID"]}`;
|
|
455
455
|
}
|
|
456
456
|
const tmpDependencies = {};
|
|
457
457
|
(tmpBom.dependencies || []).forEach((d) => {
|
|
458
458
|
tmpDependencies[d.ref] = d.dependsOn;
|
|
459
459
|
});
|
|
460
|
-
if (tmpBom
|
|
460
|
+
if (tmpBom?.components) {
|
|
461
461
|
for (const comp of tmpBom.components) {
|
|
462
462
|
if (comp.purl) {
|
|
463
463
|
// Retain go components alone from trivy
|
|
@@ -497,10 +497,10 @@ export function getOSPackages(src) {
|
|
|
497
497
|
purlObj.namespace = group;
|
|
498
498
|
}
|
|
499
499
|
purlObj.qualifiers = purlObj.qualifiers || {};
|
|
500
|
-
if (distro_id
|
|
500
|
+
if (distro_id?.length) {
|
|
501
501
|
purlObj.qualifiers["distro"] = distro_id;
|
|
502
502
|
}
|
|
503
|
-
if (distro_codename
|
|
503
|
+
if (distro_codename?.length) {
|
|
504
504
|
purlObj.qualifiers["distro_name"] = distro_codename;
|
|
505
505
|
}
|
|
506
506
|
// Bug fix for mageia and oracle linux
|
|
@@ -509,7 +509,7 @@ export function getOSPackages(src) {
|
|
|
509
509
|
purlObj["type"] = purl_type;
|
|
510
510
|
purlObj["namespace"] = "";
|
|
511
511
|
comp.group = "";
|
|
512
|
-
if (comp.purl
|
|
512
|
+
if (comp.purl?.includes(".mga")) {
|
|
513
513
|
purlObj["namespace"] = "mageia";
|
|
514
514
|
comp.group = "mageia";
|
|
515
515
|
purlObj.qualifiers["distro"] = "mageia";
|
|
@@ -529,7 +529,7 @@ export function getOSPackages(src) {
|
|
|
529
529
|
allTypes.add(purlObj.type);
|
|
530
530
|
}
|
|
531
531
|
// Prefix distro codename for ubuntu
|
|
532
|
-
if (purlObj.qualifiers
|
|
532
|
+
if (purlObj.qualifiers?.distro) {
|
|
533
533
|
allTypes.add(purlObj.qualifiers.distro);
|
|
534
534
|
if (OS_DISTRO_ALIAS[purlObj.qualifiers.distro]) {
|
|
535
535
|
distro_codename =
|
|
@@ -537,7 +537,7 @@ export function getOSPackages(src) {
|
|
|
537
537
|
} else if (group === "alpine") {
|
|
538
538
|
const dtmpA = purlObj.qualifiers.distro.split(".");
|
|
539
539
|
if (dtmpA && dtmpA.length > 2) {
|
|
540
|
-
distro_codename = dtmpA[0]
|
|
540
|
+
distro_codename = `${dtmpA[0]}.${dtmpA[1]}`;
|
|
541
541
|
}
|
|
542
542
|
} else if (group === "photon") {
|
|
543
543
|
const dtmpA = purlObj.qualifiers.distro.split("-");
|
|
@@ -699,7 +699,7 @@ const retrieveDependencies = (tmpDependencies, origBomRef, comp) => {
|
|
|
699
699
|
export function executeOsQuery(query) {
|
|
700
700
|
if (OSQUERY_BIN) {
|
|
701
701
|
if (!query.endsWith(";")) {
|
|
702
|
-
query = query
|
|
702
|
+
query = `${query};`;
|
|
703
703
|
}
|
|
704
704
|
const args = ["--json", query];
|
|
705
705
|
// On darwin, we need to disable the safety check and run cdxgen with sudo
|
package/cbomutils.js
CHANGED
|
@@ -26,10 +26,10 @@ export function collectOSCryptoLibs(options) {
|
|
|
26
26
|
results,
|
|
27
27
|
false,
|
|
28
28
|
);
|
|
29
|
-
if (dlist
|
|
29
|
+
if (dlist?.length) {
|
|
30
30
|
osPkgsList = osPkgsList.concat(dlist);
|
|
31
31
|
// Should we downgrade from cryptographic-asset to data for < 1.6 spec
|
|
32
|
-
if (options
|
|
32
|
+
if (options?.specVersion && options.specVersion < 1.6) {
|
|
33
33
|
for (const apkg of osPkgsList) {
|
|
34
34
|
if (apkg.type === "cryptographic-asset") {
|
|
35
35
|
apkg.type = "data";
|
package/display.js
CHANGED
|
@@ -17,8 +17,7 @@ export const printTable = (bomJson) => {
|
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
19
|
if (
|
|
20
|
-
bomJson.metadata &&
|
|
21
|
-
bomJson.metadata.component &&
|
|
20
|
+
bomJson.metadata?.component &&
|
|
22
21
|
["operating-system", "platform"].includes(bomJson.metadata.component.type)
|
|
23
22
|
) {
|
|
24
23
|
return printOSTable(bomJson);
|
|
@@ -109,7 +108,7 @@ const locationComparator = (a, b) => {
|
|
|
109
108
|
const tmpA = a.split("#");
|
|
110
109
|
const tmpB = b.split("#");
|
|
111
110
|
if (tmpA.length === 2 && tmpB.length === 2) {
|
|
112
|
-
if (tmpA[0]
|
|
111
|
+
if (tmpA[0] === tmpB[0]) {
|
|
113
112
|
return tmpA[1] - tmpB[1];
|
|
114
113
|
}
|
|
115
114
|
}
|
|
@@ -162,7 +161,7 @@ export const printCallStack = (bomJson) => {
|
|
|
162
161
|
const frames = Array.from(
|
|
163
162
|
new Set(
|
|
164
163
|
comp.evidence.callstack.frames.map(
|
|
165
|
-
(c) => `${c.fullFilename}${c.line ?
|
|
164
|
+
(c) => `${c.fullFilename}${c.line ? `#${c.line}` : ""}`,
|
|
166
165
|
),
|
|
167
166
|
),
|
|
168
167
|
).sort(locationComparator);
|
|
@@ -199,7 +198,7 @@ export const printDependencyTree = (bomJson) => {
|
|
|
199
198
|
}
|
|
200
199
|
const depMap = {};
|
|
201
200
|
for (const d of dependencies) {
|
|
202
|
-
if (d.dependsOn
|
|
201
|
+
if (d.dependsOn?.length) {
|
|
203
202
|
depMap[d.ref] = d.dependsOn.sort();
|
|
204
203
|
}
|
|
205
204
|
}
|
|
@@ -261,7 +260,7 @@ const recursePrint = (depMap, subtree, level, shownList, treeGraphics) => {
|
|
|
261
260
|
level > 0
|
|
262
261
|
) {
|
|
263
262
|
treeGraphics.push(
|
|
264
|
-
`${levelPrefix(level, i
|
|
263
|
+
`${levelPrefix(level, i === listToUse.length - 1)}${refStr}`,
|
|
265
264
|
);
|
|
266
265
|
shownList.push(refStr.toLowerCase());
|
|
267
266
|
if (l && depMap[refStr]) {
|
|
@@ -299,7 +298,7 @@ export const printReachables = (sliceArtefacts) => {
|
|
|
299
298
|
);
|
|
300
299
|
const data = [["Package URL", "Reachable Flows"]];
|
|
301
300
|
for (const apurl of Object.keys(sortedPurls)) {
|
|
302
|
-
data.push([apurl,
|
|
301
|
+
data.push([apurl, `${sortedPurls[apurl]}`]);
|
|
303
302
|
}
|
|
304
303
|
const config = {
|
|
305
304
|
header: {
|
package/docker.js
CHANGED
|
@@ -59,7 +59,7 @@ const registry_auth_keys = {};
|
|
|
59
59
|
*/
|
|
60
60
|
export const getDirs = (dirPath, dirName, hidden = false, recurse = true) => {
|
|
61
61
|
try {
|
|
62
|
-
return globSync(recurse ? "**/" :
|
|
62
|
+
return globSync(recurse ? "**/" : `${dirName}`, {
|
|
63
63
|
cwd: dirPath,
|
|
64
64
|
absolute: true,
|
|
65
65
|
nocase: true,
|
|
@@ -181,7 +181,8 @@ const getDefaultOptions = (forRegistry) => {
|
|
|
181
181
|
};
|
|
182
182
|
authTokenSet = true;
|
|
183
183
|
break;
|
|
184
|
-
}
|
|
184
|
+
}
|
|
185
|
+
if (configJson.credsStore) {
|
|
185
186
|
const helperAuthToken = getCredsFromHelper(
|
|
186
187
|
configJson.credsStore,
|
|
187
188
|
serverAddress,
|
|
@@ -222,7 +223,7 @@ const getDefaultOptions = (forRegistry) => {
|
|
|
222
223
|
}
|
|
223
224
|
}
|
|
224
225
|
const userInfo = _userInfo();
|
|
225
|
-
opts.podmanPrefixUrl = isWin ? "" :
|
|
226
|
+
opts.podmanPrefixUrl = isWin ? "" : "http://unix:/run/podman/podman.sock:";
|
|
226
227
|
opts.podmanRootlessPrefixUrl = isWin
|
|
227
228
|
? ""
|
|
228
229
|
: `http://unix:/run/user/${userInfo.uid}/podman/podman.sock:`;
|
|
@@ -288,7 +289,8 @@ const getDefaultOptions = (forRegistry) => {
|
|
|
288
289
|
export const getConnection = async (options, forRegistry) => {
|
|
289
290
|
if (isContainerd) {
|
|
290
291
|
return undefined;
|
|
291
|
-
}
|
|
292
|
+
}
|
|
293
|
+
if (!dockerConn) {
|
|
292
294
|
const defaultOptions = getDefaultOptions(forRegistry);
|
|
293
295
|
const opts = Object.assign(
|
|
294
296
|
{},
|
|
@@ -381,7 +383,7 @@ export const getConnection = async (options, forRegistry) => {
|
|
|
381
383
|
return dockerConn;
|
|
382
384
|
};
|
|
383
385
|
|
|
384
|
-
export const makeRequest = async (path, method
|
|
386
|
+
export const makeRequest = async (path, method, forRegistry) => {
|
|
385
387
|
const client = await getConnection({}, forRegistry);
|
|
386
388
|
if (!client) {
|
|
387
389
|
return undefined;
|
|
@@ -451,7 +453,7 @@ export const parseImageName = (fullImageName) => {
|
|
|
451
453
|
tmpA[0].includes(":")
|
|
452
454
|
) {
|
|
453
455
|
nameObj.registry = tmpA[0];
|
|
454
|
-
fullImageName = fullImageName.replace(tmpA[0]
|
|
456
|
+
fullImageName = fullImageName.replace(`${tmpA[0]}/`, "");
|
|
455
457
|
}
|
|
456
458
|
}
|
|
457
459
|
|
|
@@ -460,7 +462,7 @@ export const parseImageName = (fullImageName) => {
|
|
|
460
462
|
const tmpA = fullImageName.split("@sha256:");
|
|
461
463
|
if (tmpA.length > 1) {
|
|
462
464
|
nameObj.digest = tmpA[tmpA.length - 1];
|
|
463
|
-
fullImageName = fullImageName.replace(
|
|
465
|
+
fullImageName = fullImageName.replace(`@sha256:${nameObj.digest}`, "");
|
|
464
466
|
}
|
|
465
467
|
}
|
|
466
468
|
|
|
@@ -469,7 +471,7 @@ export const parseImageName = (fullImageName) => {
|
|
|
469
471
|
const tmpA = fullImageName.split(":");
|
|
470
472
|
if (tmpA.length > 1) {
|
|
471
473
|
nameObj.tag = tmpA[tmpA.length - 1];
|
|
472
|
-
fullImageName = fullImageName.replace(
|
|
474
|
+
fullImageName = fullImageName.replace(`:${nameObj.tag}`, "");
|
|
473
475
|
}
|
|
474
476
|
}
|
|
475
477
|
|
|
@@ -482,7 +484,7 @@ export const parseImageName = (fullImageName) => {
|
|
|
482
484
|
const tmpA = fullImageName.split("/");
|
|
483
485
|
if (tmpA.length > 1) {
|
|
484
486
|
nameObj.name = tmpA[tmpA.length - 1];
|
|
485
|
-
nameObj.group = fullImageName.replace(
|
|
487
|
+
nameObj.group = fullImageName.replace(`/${tmpA[tmpA.length - 1]}`, "");
|
|
486
488
|
}
|
|
487
489
|
}
|
|
488
490
|
|
|
@@ -516,7 +518,7 @@ export const getImage = async (fullImageName) => {
|
|
|
516
518
|
: `${repo}:${tag !== "" ? tag : ":latest"}`;
|
|
517
519
|
// Fetch only the latest tag if none is specified
|
|
518
520
|
if (tag === "" && digest === "") {
|
|
519
|
-
fullImageName = fullImageName
|
|
521
|
+
fullImageName = `${fullImageName}:latest`;
|
|
520
522
|
}
|
|
521
523
|
if (isContainerd) {
|
|
522
524
|
console.log(
|
|
@@ -530,14 +532,11 @@ export const getImage = async (fullImageName) => {
|
|
|
530
532
|
encoding: "utf-8",
|
|
531
533
|
});
|
|
532
534
|
if (result.status !== 0 || result.error) {
|
|
533
|
-
if (
|
|
534
|
-
result.stderr &&
|
|
535
|
-
result.stderr.includes("docker daemon is not running")
|
|
536
|
-
) {
|
|
535
|
+
if (result.stderr?.includes("docker daemon is not running")) {
|
|
537
536
|
console.log(
|
|
538
537
|
"Ensure Docker for Desktop is running as an administrator with 'Exposing daemon on TCP without TLS' setting turned on.",
|
|
539
538
|
);
|
|
540
|
-
} else if (result.stderr
|
|
539
|
+
} else if (result.stderr?.includes("not found")) {
|
|
541
540
|
console.log(
|
|
542
541
|
"Set the environment variable DOCKER_CMD to use an alternative command such as nerdctl or podman.",
|
|
543
542
|
);
|
|
@@ -545,29 +544,26 @@ export const getImage = async (fullImageName) => {
|
|
|
545
544
|
console.log(result.stderr);
|
|
546
545
|
}
|
|
547
546
|
return localData;
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
} else {
|
|
563
|
-
return inspectData;
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
} catch (err) {
|
|
567
|
-
// continue regardless of error
|
|
568
|
-
console.log(err);
|
|
547
|
+
}
|
|
548
|
+
result = spawnSync(dockerCmd, ["inspect", fullImageName], {
|
|
549
|
+
encoding: "utf-8",
|
|
550
|
+
});
|
|
551
|
+
if (result.status !== 0 || result.error) {
|
|
552
|
+
console.log(result.stderr);
|
|
553
|
+
return localData;
|
|
554
|
+
}
|
|
555
|
+
try {
|
|
556
|
+
const stdout = result.stdout;
|
|
557
|
+
if (stdout) {
|
|
558
|
+
const inspectData = JSON.parse(Buffer.from(stdout).toString());
|
|
559
|
+
if (inspectData && Array.isArray(inspectData)) {
|
|
560
|
+
return inspectData[0];
|
|
569
561
|
}
|
|
562
|
+
return inspectData;
|
|
570
563
|
}
|
|
564
|
+
} catch (err) {
|
|
565
|
+
// continue regardless of error
|
|
566
|
+
console.log(err);
|
|
571
567
|
}
|
|
572
568
|
}
|
|
573
569
|
try {
|
|
@@ -792,7 +788,8 @@ export const exportArchive = async (fullImageName) => {
|
|
|
792
788
|
};
|
|
793
789
|
exportData.pkgPathList = getPkgPathList(exportData, lastWorkingDir);
|
|
794
790
|
return exportData;
|
|
795
|
-
}
|
|
791
|
+
}
|
|
792
|
+
if (existsSync(manifestFile)) {
|
|
796
793
|
// docker manifest file
|
|
797
794
|
return await extractFromManifest(
|
|
798
795
|
manifestFile,
|
|
@@ -800,9 +797,8 @@ export const exportArchive = async (fullImageName) => {
|
|
|
800
797
|
tempDir,
|
|
801
798
|
allLayersExplodedDir,
|
|
802
799
|
);
|
|
803
|
-
} else {
|
|
804
|
-
console.log(`Unable to extract image archive to ${tempDir}`);
|
|
805
800
|
}
|
|
801
|
+
console.log(`Unable to extract image archive to ${tempDir}`);
|
|
806
802
|
} catch (err) {
|
|
807
803
|
console.log(err);
|
|
808
804
|
}
|
|
@@ -842,7 +838,7 @@ export const extractFromManifest = async (
|
|
|
842
838
|
const layers = manifest[manifest.length - 1]["Layers"] || [];
|
|
843
839
|
if (!layers.length && existsSync(tempDir)) {
|
|
844
840
|
const blobFiles = readdirSync(join(tempDir, "blobs", "sha256"));
|
|
845
|
-
if (blobFiles
|
|
841
|
+
if (blobFiles?.length) {
|
|
846
842
|
for (const blobf of blobFiles) {
|
|
847
843
|
layers.push(join("blobs", "sha256", blobf));
|
|
848
844
|
}
|
|
@@ -892,10 +888,9 @@ export const extractFromManifest = async (
|
|
|
892
888
|
encoding: "utf-8",
|
|
893
889
|
}),
|
|
894
890
|
);
|
|
895
|
-
lastWorkingDir =
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
: "";
|
|
891
|
+
lastWorkingDir = lastLayerConfig.config?.WorkingDir
|
|
892
|
+
? join(allLayersExplodedDir, lastLayerConfig.config.WorkingDir)
|
|
893
|
+
: "";
|
|
899
894
|
} catch (err) {
|
|
900
895
|
console.log(err);
|
|
901
896
|
}
|
|
@@ -926,7 +921,7 @@ export const exportImage = async (fullImageName) => {
|
|
|
926
921
|
const { registry, tag, digest } = parseImageName(fullImageName);
|
|
927
922
|
// Fetch only the latest tag if none is specified
|
|
928
923
|
if (tag === "" && digest === "") {
|
|
929
|
-
fullImageName = fullImageName
|
|
924
|
+
fullImageName = `${fullImageName}:latest`;
|
|
930
925
|
}
|
|
931
926
|
const tempDir = mkdtempSync(join(tmpdir(), "docker-images-"));
|
|
932
927
|
const allLayersExplodedDir = join(tempDir, "all-layers");
|
|
@@ -951,20 +946,19 @@ export const exportImage = async (fullImageName) => {
|
|
|
951
946
|
console.log(result.stdout, result.stderr);
|
|
952
947
|
}
|
|
953
948
|
return localData;
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
}
|
|
949
|
+
}
|
|
950
|
+
await extractTar(imageTarFile, tempDir);
|
|
951
|
+
if (DEBUG_MODE) {
|
|
952
|
+
console.log(`Cleaning up ${imageTarFile}`);
|
|
953
|
+
}
|
|
954
|
+
if (rmSync) {
|
|
955
|
+
rmSync(imageTarFile, { force: true });
|
|
962
956
|
}
|
|
963
957
|
} else {
|
|
964
958
|
const client = await getConnection({}, registry);
|
|
965
959
|
try {
|
|
966
960
|
if (DEBUG_MODE) {
|
|
967
|
-
if (registry
|
|
961
|
+
if (registry?.trim().length) {
|
|
968
962
|
console.log(
|
|
969
963
|
`About to export image ${fullImageName} from ${registry} to ${tempDir}`,
|
|
970
964
|
);
|
|
@@ -986,7 +980,7 @@ export const exportImage = async (fullImageName) => {
|
|
|
986
980
|
}),
|
|
987
981
|
);
|
|
988
982
|
} catch (err) {
|
|
989
|
-
if (localData
|
|
983
|
+
if (localData?.Id) {
|
|
990
984
|
console.log(`Retrying with ${localData.Id}`);
|
|
991
985
|
try {
|
|
992
986
|
await stream.pipeline(
|
|
@@ -1032,9 +1026,8 @@ export const exportImage = async (fullImageName) => {
|
|
|
1032
1026
|
tempDir,
|
|
1033
1027
|
allLayersExplodedDir,
|
|
1034
1028
|
);
|
|
1035
|
-
} else {
|
|
1036
|
-
console.log(`Unable to export image to ${tempDir}`);
|
|
1037
1029
|
}
|
|
1030
|
+
console.log(`Unable to export image to ${tempDir}`);
|
|
1038
1031
|
return undefined;
|
|
1039
1032
|
};
|
|
1040
1033
|
|
|
@@ -1084,10 +1077,10 @@ export const getPkgPathList = (exportData, lastWorkingDir) => {
|
|
|
1084
1077
|
knownSysPaths.push(join(allLayersDir, "ProgramData"));
|
|
1085
1078
|
}
|
|
1086
1079
|
const pyInstalls = getDirs(allLayersDir, "Python*/", false, false);
|
|
1087
|
-
if (pyInstalls
|
|
1080
|
+
if (pyInstalls?.length) {
|
|
1088
1081
|
for (const pyiPath of pyInstalls) {
|
|
1089
1082
|
const pyDirs = getOnlyDirs(pyiPath, "site-packages");
|
|
1090
|
-
if (pyDirs
|
|
1083
|
+
if (pyDirs?.length) {
|
|
1091
1084
|
pathList = pathList.concat(pyDirs);
|
|
1092
1085
|
}
|
|
1093
1086
|
}
|
|
@@ -1120,19 +1113,19 @@ export const getPkgPathList = (exportData, lastWorkingDir) => {
|
|
|
1120
1113
|
for (const wpath of knownSysPaths) {
|
|
1121
1114
|
pathList = pathList.concat(wpath);
|
|
1122
1115
|
const pyDirs = getOnlyDirs(wpath, "site-packages");
|
|
1123
|
-
if (pyDirs
|
|
1116
|
+
if (pyDirs?.length) {
|
|
1124
1117
|
pathList = pathList.concat(pyDirs);
|
|
1125
1118
|
}
|
|
1126
1119
|
const gemsDirs = getOnlyDirs(wpath, "gems");
|
|
1127
|
-
if (gemsDirs
|
|
1120
|
+
if (gemsDirs?.length) {
|
|
1128
1121
|
pathList = pathList.concat(gemsDirs);
|
|
1129
1122
|
}
|
|
1130
1123
|
const cargoDirs = getOnlyDirs(wpath, ".cargo");
|
|
1131
|
-
if (cargoDirs
|
|
1124
|
+
if (cargoDirs?.length) {
|
|
1132
1125
|
pathList = pathList.concat(cargoDirs);
|
|
1133
1126
|
}
|
|
1134
1127
|
const composerDirs = getOnlyDirs(wpath, ".composer");
|
|
1135
|
-
if (composerDirs
|
|
1128
|
+
if (composerDirs?.length) {
|
|
1136
1129
|
pathList = pathList.concat(composerDirs);
|
|
1137
1130
|
}
|
|
1138
1131
|
}
|
|
@@ -1156,7 +1149,7 @@ export const getCredsFromHelper = (exeSuffix, serverAddress) => {
|
|
|
1156
1149
|
}
|
|
1157
1150
|
let credHelperExe = `docker-credential-${exeSuffix}`;
|
|
1158
1151
|
if (isWin) {
|
|
1159
|
-
credHelperExe = credHelperExe
|
|
1152
|
+
credHelperExe = `${credHelperExe}.exe`;
|
|
1160
1153
|
}
|
|
1161
1154
|
const result = spawnSync(credHelperExe, ["get"], {
|
|
1162
1155
|
input: serverAddress,
|