@cyclonedx/cdxgen 10.3.4 → 10.4.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/README.md +2 -4
- package/analyzer.js +18 -18
- package/bin/cdxgen.js +79 -77
- package/bin/evinse.js +26 -26
- package/bin/repl.js +56 -62
- package/bin/verify.js +9 -9
- package/binary.js +55 -54
- package/cbomutils.js +6 -6
- package/db.js +17 -17
- package/display.js +30 -30
- package/display.test.js +2 -2
- package/docker.js +92 -89
- package/docker.test.js +30 -30
- package/envcontext.js +15 -15
- package/envcontext.test.js +1 -1
- package/evinser.js +94 -93
- package/evinser.test.js +24 -24
- package/index.js +523 -483
- package/package.json +8 -16
- package/piptree.js +6 -6
- package/postgen.js +2 -2
- package/postgen.test.js +5 -5
- package/protobom.js +37 -7
- package/protobom.test.js +6 -6
- package/server.js +16 -16
- package/types/analyzer.d.ts +7 -4
- package/types/binary.d.ts +12 -8
- package/types/cbomutils.d.ts +1 -1
- package/types/db.d.ts +23 -11
- package/types/display.d.ts +1 -1
- package/types/docker.d.ts +52 -32
- package/types/envcontext.d.ts +40 -40
- package/types/evinser.d.ts +3436 -717
- package/types/index.d.ts +66 -40
- package/types/jest.config.d.ts +2 -2
- package/types/piptree.d.ts +6 -2
- package/types/postgen.d.ts +1 -1
- package/types/protobom.d.ts +7 -3
- package/types/protobom.d.ts.map +1 -1
- package/types/server.d.ts +1 -1
- package/types/utils.d.ts +496 -302
- package/types/validator.d.ts +1 -1
- package/utils.js +742 -675
- package/utils.test.js +716 -674
- package/validator.js +20 -17
package/docker.js
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import got from "got";
|
|
2
|
-
import { globSync } from "glob";
|
|
3
|
-
import { parse } from "node:url";
|
|
4
|
-
import stream from "node:stream/promises";
|
|
5
|
-
import process from "node:process";
|
|
6
1
|
import { Buffer } from "node:buffer";
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
7
3
|
import {
|
|
8
4
|
createReadStream,
|
|
9
5
|
existsSync,
|
|
@@ -13,17 +9,21 @@ import {
|
|
|
13
9
|
readFileSync,
|
|
14
10
|
readdirSync,
|
|
15
11
|
rmSync,
|
|
16
|
-
statSync
|
|
12
|
+
statSync,
|
|
17
13
|
} from "node:fs";
|
|
18
|
-
import { join } from "node:path";
|
|
19
14
|
import {
|
|
20
15
|
platform as _platform,
|
|
21
16
|
userInfo as _userInfo,
|
|
22
17
|
homedir,
|
|
23
|
-
tmpdir
|
|
18
|
+
tmpdir,
|
|
24
19
|
} from "node:os";
|
|
20
|
+
import { join } from "node:path";
|
|
21
|
+
import process from "node:process";
|
|
22
|
+
import stream from "node:stream/promises";
|
|
23
|
+
import { parse } from "node:url";
|
|
24
|
+
import { globSync } from "glob";
|
|
25
|
+
import got from "got";
|
|
25
26
|
import { x } from "tar";
|
|
26
|
-
import { spawnSync } from "node:child_process";
|
|
27
27
|
import { DEBUG_MODE, getAllFiles } from "./utils.js";
|
|
28
28
|
|
|
29
29
|
export const isWin = _platform() === "win32";
|
|
@@ -42,7 +42,7 @@ if (
|
|
|
42
42
|
(process.env.CONTAINERD_ADDRESS ||
|
|
43
43
|
(process.env.XDG_RUNTIME_DIR &&
|
|
44
44
|
existsSync(
|
|
45
|
-
join(process.env.XDG_RUNTIME_DIR, "containerd-rootless", "api.sock")
|
|
45
|
+
join(process.env.XDG_RUNTIME_DIR, "containerd-rootless", "api.sock"),
|
|
46
46
|
)))
|
|
47
47
|
) {
|
|
48
48
|
isContainerd = true;
|
|
@@ -65,7 +65,7 @@ export const getDirs = (dirPath, dirName, hidden = false, recurse = true) => {
|
|
|
65
65
|
nocase: true,
|
|
66
66
|
nodir: false,
|
|
67
67
|
follow: false,
|
|
68
|
-
dot: hidden
|
|
68
|
+
dot: hidden,
|
|
69
69
|
});
|
|
70
70
|
} catch (err) {
|
|
71
71
|
return [];
|
|
@@ -107,8 +107,8 @@ export const getOnlyDirs = (srcpath, dirName) => {
|
|
|
107
107
|
console.error(err);
|
|
108
108
|
}
|
|
109
109
|
})
|
|
110
|
-
.filter((p) => p !== undefined)
|
|
111
|
-
)
|
|
110
|
+
.filter((p) => p !== undefined),
|
|
111
|
+
),
|
|
112
112
|
].filter((d) => d.endsWith(dirName));
|
|
113
113
|
};
|
|
114
114
|
|
|
@@ -128,13 +128,13 @@ const getDefaultOptions = (forRegistry) => {
|
|
|
128
128
|
throwHttpErrors: true,
|
|
129
129
|
method: "GET",
|
|
130
130
|
hooks: { beforeError: [] },
|
|
131
|
-
mutableDefaults: true
|
|
131
|
+
mutableDefaults: true,
|
|
132
132
|
};
|
|
133
133
|
const DOCKER_CONFIG = process.env.DOCKER_CONFIG || join(homedir(), ".docker");
|
|
134
134
|
// Support for private registry
|
|
135
135
|
if (process.env.DOCKER_AUTH_CONFIG) {
|
|
136
136
|
opts.headers = {
|
|
137
|
-
"X-Registry-Auth": process.env.DOCKER_AUTH_CONFIG
|
|
137
|
+
"X-Registry-Auth": process.env.DOCKER_AUTH_CONFIG,
|
|
138
138
|
};
|
|
139
139
|
authTokenSet = true;
|
|
140
140
|
}
|
|
@@ -148,7 +148,7 @@ const getDefaultOptions = (forRegistry) => {
|
|
|
148
148
|
const authPayload = {
|
|
149
149
|
username: process.env.DOCKER_USER,
|
|
150
150
|
email: process.env.DOCKER_EMAIL,
|
|
151
|
-
serveraddress: forRegistry
|
|
151
|
+
serveraddress: forRegistry,
|
|
152
152
|
};
|
|
153
153
|
if (process.env.DOCKER_USER === "<token>") {
|
|
154
154
|
authPayload.IdentityToken = process.env.DOCKER_PASSWORD;
|
|
@@ -157,14 +157,14 @@ const getDefaultOptions = (forRegistry) => {
|
|
|
157
157
|
}
|
|
158
158
|
opts.headers = {
|
|
159
159
|
"X-Registry-Auth": Buffer.from(JSON.stringify(authPayload)).toString(
|
|
160
|
-
"base64"
|
|
161
|
-
)
|
|
160
|
+
"base64",
|
|
161
|
+
),
|
|
162
162
|
};
|
|
163
163
|
}
|
|
164
164
|
if (!authTokenSet && existsSync(join(DOCKER_CONFIG, "config.json"))) {
|
|
165
165
|
const configData = readFileSync(
|
|
166
166
|
join(DOCKER_CONFIG, "config.json"),
|
|
167
|
-
"utf-8"
|
|
167
|
+
"utf-8",
|
|
168
168
|
);
|
|
169
169
|
if (configData) {
|
|
170
170
|
try {
|
|
@@ -177,18 +177,18 @@ const getDefaultOptions = (forRegistry) => {
|
|
|
177
177
|
}
|
|
178
178
|
if (configJson.auths[serverAddress].auth) {
|
|
179
179
|
opts.headers = {
|
|
180
|
-
"X-Registry-Auth": configJson.auths[serverAddress].auth
|
|
180
|
+
"X-Registry-Auth": configJson.auths[serverAddress].auth,
|
|
181
181
|
};
|
|
182
182
|
authTokenSet = true;
|
|
183
183
|
break;
|
|
184
184
|
} else if (configJson.credsStore) {
|
|
185
185
|
const helperAuthToken = getCredsFromHelper(
|
|
186
186
|
configJson.credsStore,
|
|
187
|
-
serverAddress
|
|
187
|
+
serverAddress,
|
|
188
188
|
);
|
|
189
189
|
if (helperAuthToken) {
|
|
190
190
|
opts.headers = {
|
|
191
|
-
"X-Registry-Auth": helperAuthToken
|
|
191
|
+
"X-Registry-Auth": helperAuthToken,
|
|
192
192
|
};
|
|
193
193
|
authTokenSet = true;
|
|
194
194
|
break;
|
|
@@ -204,11 +204,11 @@ const getDefaultOptions = (forRegistry) => {
|
|
|
204
204
|
if (configJson.credHelpers[serverAddress]) {
|
|
205
205
|
const helperAuthToken = getCredsFromHelper(
|
|
206
206
|
configJson.credHelpers[serverAddress],
|
|
207
|
-
serverAddress
|
|
207
|
+
serverAddress,
|
|
208
208
|
);
|
|
209
209
|
if (helperAuthToken) {
|
|
210
210
|
opts.headers = {
|
|
211
|
-
"X-Registry-Auth": helperAuthToken
|
|
211
|
+
"X-Registry-Auth": helperAuthToken,
|
|
212
212
|
};
|
|
213
213
|
authTokenSet = true;
|
|
214
214
|
break;
|
|
@@ -263,9 +263,12 @@ const getDefaultOptions = (forRegistry) => {
|
|
|
263
263
|
opts.https = {
|
|
264
264
|
certificate: readFileSync(
|
|
265
265
|
join(process.env.DOCKER_CERT_PATH, "cert.pem"),
|
|
266
|
-
"utf8"
|
|
266
|
+
"utf8",
|
|
267
|
+
),
|
|
268
|
+
key: readFileSync(
|
|
269
|
+
join(process.env.DOCKER_CERT_PATH, "key.pem"),
|
|
270
|
+
"utf8",
|
|
267
271
|
),
|
|
268
|
-
key: readFileSync(join(process.env.DOCKER_CERT_PATH, "key.pem"), "utf8")
|
|
269
272
|
};
|
|
270
273
|
// Disable tls on empty values
|
|
271
274
|
// From the docker docs: Setting the DOCKER_TLS_VERIFY environment variable to any value other than the empty string is equivalent to setting the --tlsverify flag
|
|
@@ -294,9 +297,9 @@ export const getConnection = async (options, forRegistry) => {
|
|
|
294
297
|
throwHttpErrors: defaultOptions.throwHttpErrors,
|
|
295
298
|
method: defaultOptions.method,
|
|
296
299
|
prefixUrl: defaultOptions.prefixUrl,
|
|
297
|
-
headers: defaultOptions.headers
|
|
300
|
+
headers: defaultOptions.headers,
|
|
298
301
|
},
|
|
299
|
-
options
|
|
302
|
+
options,
|
|
300
303
|
);
|
|
301
304
|
try {
|
|
302
305
|
await got.get("_ping", opts);
|
|
@@ -306,7 +309,7 @@ export const getConnection = async (options, forRegistry) => {
|
|
|
306
309
|
console.log("Docker service in rootless mode detected.");
|
|
307
310
|
} else {
|
|
308
311
|
console.log(
|
|
309
|
-
"Docker service in root mode detected. Consider switching to rootless mode to improve security. See https://docs.docker.com/engine/security/rootless/"
|
|
312
|
+
"Docker service in root mode detected. Consider switching to rootless mode to improve security. See https://docs.docker.com/engine/security/rootless/",
|
|
310
313
|
);
|
|
311
314
|
}
|
|
312
315
|
}
|
|
@@ -340,7 +343,7 @@ export const getConnection = async (options, forRegistry) => {
|
|
|
340
343
|
dockerConn = got.extend(opts);
|
|
341
344
|
if (DEBUG_MODE) {
|
|
342
345
|
console.log(
|
|
343
|
-
"Podman in rootless mode detected. Thank you for using podman!"
|
|
346
|
+
"Podman in rootless mode detected. Thank you for using podman!",
|
|
344
347
|
);
|
|
345
348
|
}
|
|
346
349
|
}
|
|
@@ -353,22 +356,22 @@ export const getConnection = async (options, forRegistry) => {
|
|
|
353
356
|
isPodmanRootless = false;
|
|
354
357
|
dockerConn = got.extend(opts);
|
|
355
358
|
console.log(
|
|
356
|
-
"Podman in root mode detected. Consider switching to rootless mode to improve security. See https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md"
|
|
359
|
+
"Podman in root mode detected. Consider switching to rootless mode to improve security. See https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md",
|
|
357
360
|
);
|
|
358
361
|
} catch (err) {
|
|
359
362
|
// console.log(err);
|
|
360
363
|
if (_platform() === "win32") {
|
|
361
364
|
console.warn(
|
|
362
365
|
"Ensure Docker for Desktop is running as an administrator with 'Exposing daemon on TCP without TLS' setting turned on.",
|
|
363
|
-
opts
|
|
366
|
+
opts,
|
|
364
367
|
);
|
|
365
368
|
} else {
|
|
366
369
|
console.warn(
|
|
367
370
|
"Ensure docker/podman service or Docker for Desktop is running.",
|
|
368
|
-
opts
|
|
371
|
+
opts,
|
|
369
372
|
);
|
|
370
373
|
console.log(
|
|
371
|
-
"Check if the post-installation steps were performed correctly as per this documentation https://docs.docker.com/engine/install/linux-postinstall/"
|
|
374
|
+
"Check if the post-installation steps were performed correctly as per this documentation https://docs.docker.com/engine/install/linux-postinstall/",
|
|
372
375
|
);
|
|
373
376
|
}
|
|
374
377
|
}
|
|
@@ -387,7 +390,7 @@ export const makeRequest = async (path, method = "GET", forRegistry) => {
|
|
|
387
390
|
responseType: method === "GET" ? "json" : "buffer",
|
|
388
391
|
resolveBodyOnly: true,
|
|
389
392
|
enableUnixSockets: true,
|
|
390
|
-
method
|
|
393
|
+
method,
|
|
391
394
|
};
|
|
392
395
|
const defaultOptions = getDefaultOptions(forRegistry);
|
|
393
396
|
const opts = Object.assign(
|
|
@@ -397,9 +400,9 @@ export const makeRequest = async (path, method = "GET", forRegistry) => {
|
|
|
397
400
|
throwHttpErrors: defaultOptions.throwHttpErrors,
|
|
398
401
|
method: defaultOptions.method,
|
|
399
402
|
prefixUrl: defaultOptions.prefixUrl,
|
|
400
|
-
headers: defaultOptions.headers
|
|
403
|
+
headers: defaultOptions.headers,
|
|
401
404
|
},
|
|
402
|
-
extraOptions
|
|
405
|
+
extraOptions,
|
|
403
406
|
);
|
|
404
407
|
return await client(path, opts);
|
|
405
408
|
};
|
|
@@ -420,7 +423,7 @@ export const parseImageName = (fullImageName) => {
|
|
|
420
423
|
digest: "",
|
|
421
424
|
platform: "",
|
|
422
425
|
group: "",
|
|
423
|
-
name: ""
|
|
426
|
+
name: "",
|
|
424
427
|
};
|
|
425
428
|
if (!fullImageName) {
|
|
426
429
|
return nameObj;
|
|
@@ -517,14 +520,14 @@ export const getImage = async (fullImageName) => {
|
|
|
517
520
|
}
|
|
518
521
|
if (isContainerd) {
|
|
519
522
|
console.log(
|
|
520
|
-
"containerd/nerdctl is currently unsupported. Export the image manually and run cdxgen against the tar image."
|
|
523
|
+
"containerd/nerdctl is currently unsupported. Export the image manually and run cdxgen against the tar image.",
|
|
521
524
|
);
|
|
522
525
|
return undefined;
|
|
523
526
|
}
|
|
524
527
|
if (needsCliFallback()) {
|
|
525
528
|
const dockerCmd = process.env.DOCKER_CMD || "docker";
|
|
526
529
|
let result = spawnSync(dockerCmd, ["pull", fullImageName], {
|
|
527
|
-
encoding: "utf-8"
|
|
530
|
+
encoding: "utf-8",
|
|
528
531
|
});
|
|
529
532
|
if (result.status !== 0 || result.error) {
|
|
530
533
|
if (
|
|
@@ -532,11 +535,11 @@ export const getImage = async (fullImageName) => {
|
|
|
532
535
|
result.stderr.includes("docker daemon is not running")
|
|
533
536
|
) {
|
|
534
537
|
console.log(
|
|
535
|
-
"Ensure Docker for Desktop is running as an administrator with 'Exposing daemon on TCP without TLS' setting turned on."
|
|
538
|
+
"Ensure Docker for Desktop is running as an administrator with 'Exposing daemon on TCP without TLS' setting turned on.",
|
|
536
539
|
);
|
|
537
540
|
} else if (result.stderr && result.stderr.includes("not found")) {
|
|
538
541
|
console.log(
|
|
539
|
-
"Set the environment variable DOCKER_CMD to use an alternative command such as nerdctl or podman."
|
|
542
|
+
"Set the environment variable DOCKER_CMD to use an alternative command such as nerdctl or podman.",
|
|
540
543
|
);
|
|
541
544
|
} else {
|
|
542
545
|
console.log(result.stderr);
|
|
@@ -544,7 +547,7 @@ export const getImage = async (fullImageName) => {
|
|
|
544
547
|
return localData;
|
|
545
548
|
} else {
|
|
546
549
|
result = spawnSync(dockerCmd, ["inspect", fullImageName], {
|
|
547
|
-
encoding: "utf-8"
|
|
550
|
+
encoding: "utf-8",
|
|
548
551
|
});
|
|
549
552
|
if (result.status !== 0 || result.error) {
|
|
550
553
|
console.log(result.stderr);
|
|
@@ -571,7 +574,7 @@ export const getImage = async (fullImageName) => {
|
|
|
571
574
|
localData = await makeRequest(
|
|
572
575
|
`images/${repoWithTag}/json`,
|
|
573
576
|
"GET",
|
|
574
|
-
registry
|
|
577
|
+
registry,
|
|
575
578
|
);
|
|
576
579
|
if (localData) {
|
|
577
580
|
return localData;
|
|
@@ -586,7 +589,7 @@ export const getImage = async (fullImageName) => {
|
|
|
586
589
|
localData = await makeRequest(
|
|
587
590
|
`images/${fullImageName}/json`,
|
|
588
591
|
"GET",
|
|
589
|
-
registry
|
|
592
|
+
registry,
|
|
590
593
|
);
|
|
591
594
|
if (localData) {
|
|
592
595
|
return localData;
|
|
@@ -596,7 +599,7 @@ export const getImage = async (fullImageName) => {
|
|
|
596
599
|
}
|
|
597
600
|
if (DEBUG_MODE) {
|
|
598
601
|
console.log(
|
|
599
|
-
`Trying to pull the image ${fullImageName} from registry. This might take a while
|
|
602
|
+
`Trying to pull the image ${fullImageName} from registry. This might take a while ...`,
|
|
600
603
|
);
|
|
601
604
|
}
|
|
602
605
|
// If the data is not available locally
|
|
@@ -604,7 +607,7 @@ export const getImage = async (fullImageName) => {
|
|
|
604
607
|
pullData = await makeRequest(
|
|
605
608
|
`images/create?fromImage=${fullImageName}`,
|
|
606
609
|
"POST",
|
|
607
|
-
registry
|
|
610
|
+
registry,
|
|
608
611
|
);
|
|
609
612
|
if (
|
|
610
613
|
pullData &&
|
|
@@ -612,10 +615,10 @@ export const getImage = async (fullImageName) => {
|
|
|
612
615
|
pullData.includes("Error choosing an image from manifest list"))
|
|
613
616
|
) {
|
|
614
617
|
console.warn(
|
|
615
|
-
"You may have to enable experimental settings in docker to support this platform!"
|
|
618
|
+
"You may have to enable experimental settings in docker to support this platform!",
|
|
616
619
|
);
|
|
617
620
|
console.warn(
|
|
618
|
-
"To scan windows images, run cdxgen on a windows server with hyper-v and docker installed. Switch to windows containers in your docker settings."
|
|
621
|
+
"To scan windows images, run cdxgen on a windows server with hyper-v and docker installed. Switch to windows containers in your docker settings.",
|
|
619
622
|
);
|
|
620
623
|
return undefined;
|
|
621
624
|
}
|
|
@@ -627,7 +630,7 @@ export const getImage = async (fullImageName) => {
|
|
|
627
630
|
pullData = await makeRequest(
|
|
628
631
|
`images/create?fromImage=${repoWithTag}`,
|
|
629
632
|
"POST",
|
|
630
|
-
registry
|
|
633
|
+
registry,
|
|
631
634
|
);
|
|
632
635
|
} catch (err) {
|
|
633
636
|
// continue regardless of error
|
|
@@ -640,7 +643,7 @@ export const getImage = async (fullImageName) => {
|
|
|
640
643
|
localData = await makeRequest(
|
|
641
644
|
`images/${repoWithTag}/json`,
|
|
642
645
|
"GET",
|
|
643
|
-
registry
|
|
646
|
+
registry,
|
|
644
647
|
);
|
|
645
648
|
if (localData) {
|
|
646
649
|
return localData;
|
|
@@ -664,7 +667,7 @@ export const getImage = async (fullImageName) => {
|
|
|
664
667
|
localData = await makeRequest(
|
|
665
668
|
`images/${fullImageName}/json`,
|
|
666
669
|
"GET",
|
|
667
|
-
registry
|
|
670
|
+
registry,
|
|
668
671
|
);
|
|
669
672
|
} catch (err) {
|
|
670
673
|
// continue regardless of error
|
|
@@ -673,10 +676,10 @@ export const getImage = async (fullImageName) => {
|
|
|
673
676
|
}
|
|
674
677
|
if (!localData) {
|
|
675
678
|
console.log(
|
|
676
|
-
`Unable to pull ${fullImageName}. Check if the name is valid. Perform any authentication prior to invoking cdxgen
|
|
679
|
+
`Unable to pull ${fullImageName}. Check if the name is valid. Perform any authentication prior to invoking cdxgen.`,
|
|
677
680
|
);
|
|
678
681
|
console.log(
|
|
679
|
-
`Try manually pulling this image using docker pull ${fullImageName}
|
|
682
|
+
`Try manually pulling this image using docker pull ${fullImageName}`,
|
|
680
683
|
);
|
|
681
684
|
}
|
|
682
685
|
return localData;
|
|
@@ -713,25 +716,25 @@ export const extractTar = async (fullImageName, dir) => {
|
|
|
713
716
|
"TapeVolume",
|
|
714
717
|
"SymbolicLink",
|
|
715
718
|
"RenamedOrSymlinked",
|
|
716
|
-
"HardLink"
|
|
719
|
+
"HardLink",
|
|
717
720
|
].includes(entry.type)
|
|
718
721
|
) {
|
|
719
722
|
return false;
|
|
720
723
|
}
|
|
721
724
|
return true;
|
|
722
|
-
}
|
|
723
|
-
})
|
|
725
|
+
},
|
|
726
|
+
}),
|
|
724
727
|
);
|
|
725
728
|
return true;
|
|
726
729
|
} catch (err) {
|
|
727
730
|
if (err.code === "EPERM" && err.syscall === "symlink") {
|
|
728
731
|
console.log(
|
|
729
|
-
"Please run cdxgen from a powershell terminal with admin privileges to create symlinks."
|
|
732
|
+
"Please run cdxgen from a powershell terminal with admin privileges to create symlinks.",
|
|
730
733
|
);
|
|
731
734
|
console.log(err);
|
|
732
735
|
} else if (!["TAR_BAD_ARCHIVE", "TAR_ENTRY_INFO"].includes(err.code)) {
|
|
733
736
|
console.log(
|
|
734
|
-
`Error while extracting image ${fullImageName} to ${dir}. Please file this bug to the cdxgen repo. https://github.com/CycloneDX/cdxgen/issues
|
|
737
|
+
`Error while extracting image ${fullImageName} to ${dir}. Please file this bug to the cdxgen repo. https://github.com/CycloneDX/cdxgen/issues`,
|
|
735
738
|
);
|
|
736
739
|
console.log("------------");
|
|
737
740
|
console.log(err);
|
|
@@ -768,7 +771,7 @@ export const exportArchive = async (fullImageName) => {
|
|
|
768
771
|
if (existsSync(blobsDir)) {
|
|
769
772
|
if (DEBUG_MODE) {
|
|
770
773
|
console.log(
|
|
771
|
-
`Image archive ${fullImageName} successfully exported to directory ${tempDir}
|
|
774
|
+
`Image archive ${fullImageName} successfully exported to directory ${tempDir}`,
|
|
772
775
|
);
|
|
773
776
|
}
|
|
774
777
|
const allBlobs = getAllFiles(blobsDir, "*");
|
|
@@ -785,7 +788,7 @@ export const exportArchive = async (fullImageName) => {
|
|
|
785
788
|
allLayersDir: tempDir,
|
|
786
789
|
allLayersExplodedDir,
|
|
787
790
|
lastLayerConfig,
|
|
788
|
-
lastWorkingDir
|
|
791
|
+
lastWorkingDir,
|
|
789
792
|
};
|
|
790
793
|
exportData.pkgPathList = getPkgPathList(exportData, lastWorkingDir);
|
|
791
794
|
return exportData;
|
|
@@ -795,7 +798,7 @@ export const exportArchive = async (fullImageName) => {
|
|
|
795
798
|
manifestFile,
|
|
796
799
|
{},
|
|
797
800
|
tempDir,
|
|
798
|
-
allLayersExplodedDir
|
|
801
|
+
allLayersExplodedDir,
|
|
799
802
|
);
|
|
800
803
|
} else {
|
|
801
804
|
console.log(`Unable to extract image archive to ${tempDir}`);
|
|
@@ -810,15 +813,15 @@ export const extractFromManifest = async (
|
|
|
810
813
|
manifestFile,
|
|
811
814
|
localData,
|
|
812
815
|
tempDir,
|
|
813
|
-
allLayersExplodedDir
|
|
816
|
+
allLayersExplodedDir,
|
|
814
817
|
) => {
|
|
815
818
|
// Example of manifests
|
|
816
819
|
// [{"Config":"blobs/sha256/dedc100afa8d6718f5ac537730dd4a5ceea3563e695c90f1a8ac6df32c4cb291","RepoTags":["shiftleft/core:latest"],"Layers":["blobs/sha256/eaead16dc43bb8811d4ff450935d607f9ba4baffda4fc110cc402fa43f601d83","blobs/sha256/2039af03c0e17a3025b989335e9414149577fa09e7d0dcbee80155333639d11f"]}]
|
|
817
820
|
// {"schemaVersion":2,"manifests":[{"mediaType":"application/vnd.docker.distribution.manifest.list.v2+json","digest":"sha256:7706ac20c7587081dc7a00e0ec65a6633b0bb3788e0048a3e971d3eae492db63","size":318,"annotations":{"io.containerd.image.name":"docker.io/shiftleft/scan-slim:latest","org.opencontainers.image.ref.name":"latest"}}]}
|
|
818
821
|
let manifest = JSON.parse(
|
|
819
822
|
readFileSync(manifestFile, {
|
|
820
|
-
encoding: "utf-8"
|
|
821
|
-
})
|
|
823
|
+
encoding: "utf-8",
|
|
824
|
+
}),
|
|
822
825
|
);
|
|
823
826
|
let lastLayerConfig = {};
|
|
824
827
|
let lastLayerConfigFile = "";
|
|
@@ -831,7 +834,7 @@ export const extractFromManifest = async (
|
|
|
831
834
|
if (manifest.length !== 1) {
|
|
832
835
|
if (DEBUG_MODE) {
|
|
833
836
|
console.log(
|
|
834
|
-
"Multiple image tags was downloaded. Only the last one would be used"
|
|
837
|
+
"Multiple image tags was downloaded. Only the last one would be used",
|
|
835
838
|
);
|
|
836
839
|
console.log(manifest[manifest.length - 1]);
|
|
837
840
|
}
|
|
@@ -850,7 +853,7 @@ export const extractFromManifest = async (
|
|
|
850
853
|
try {
|
|
851
854
|
if (!lstatSync(join(tempDir, layer)).isFile()) {
|
|
852
855
|
console.log(
|
|
853
|
-
`Skipping layer ${layer} since it is not a readable file
|
|
856
|
+
`Skipping layer ${layer} since it is not a readable file.`,
|
|
854
857
|
);
|
|
855
858
|
continue;
|
|
856
859
|
}
|
|
@@ -879,15 +882,15 @@ export const extractFromManifest = async (
|
|
|
879
882
|
if (lastLayer.includes("layer.tar")) {
|
|
880
883
|
lastLayerConfigFile = join(
|
|
881
884
|
tempDir,
|
|
882
|
-
lastLayer.replace("layer.tar", "json")
|
|
885
|
+
lastLayer.replace("layer.tar", "json"),
|
|
883
886
|
);
|
|
884
887
|
}
|
|
885
888
|
if (lastLayerConfigFile && existsSync(lastLayerConfigFile)) {
|
|
886
889
|
try {
|
|
887
890
|
lastLayerConfig = JSON.parse(
|
|
888
891
|
readFileSync(lastLayerConfigFile, {
|
|
889
|
-
encoding: "utf-8"
|
|
890
|
-
})
|
|
892
|
+
encoding: "utf-8",
|
|
893
|
+
}),
|
|
891
894
|
);
|
|
892
895
|
lastWorkingDir =
|
|
893
896
|
lastLayerConfig.config && lastLayerConfig.config.WorkingDir
|
|
@@ -904,7 +907,7 @@ export const extractFromManifest = async (
|
|
|
904
907
|
allLayersDir: tempDir,
|
|
905
908
|
allLayersExplodedDir,
|
|
906
909
|
lastLayerConfig,
|
|
907
|
-
lastWorkingDir
|
|
910
|
+
lastWorkingDir,
|
|
908
911
|
};
|
|
909
912
|
exportData.pkgPathList = getPkgPathList(exportData, lastWorkingDir);
|
|
910
913
|
return exportData;
|
|
@@ -934,14 +937,14 @@ export const exportImage = async (fullImageName) => {
|
|
|
934
937
|
if (needsCliFallback()) {
|
|
935
938
|
const imageTarFile = join(tempDir, "image.tar");
|
|
936
939
|
console.log(
|
|
937
|
-
`About to export image ${fullImageName} to ${imageTarFile} using docker cli
|
|
940
|
+
`About to export image ${fullImageName} to ${imageTarFile} using docker cli`,
|
|
938
941
|
);
|
|
939
942
|
const result = spawnSync(
|
|
940
943
|
"docker",
|
|
941
944
|
["save", "-o", imageTarFile, fullImageName],
|
|
942
945
|
{
|
|
943
|
-
encoding: "utf-8"
|
|
944
|
-
}
|
|
946
|
+
encoding: "utf-8",
|
|
947
|
+
},
|
|
945
948
|
);
|
|
946
949
|
if (result.status !== 0 || result.error) {
|
|
947
950
|
if (result.stdout || result.stderr) {
|
|
@@ -963,7 +966,7 @@ export const exportImage = async (fullImageName) => {
|
|
|
963
966
|
if (DEBUG_MODE) {
|
|
964
967
|
if (registry && registry.trim().length) {
|
|
965
968
|
console.log(
|
|
966
|
-
`About to export image ${fullImageName} from ${registry} to ${tempDir}
|
|
969
|
+
`About to export image ${fullImageName} from ${registry} to ${tempDir}`,
|
|
967
970
|
);
|
|
968
971
|
} else {
|
|
969
972
|
console.log(`About to export image ${fullImageName} to ${tempDir}`);
|
|
@@ -979,8 +982,8 @@ export const exportImage = async (fullImageName) => {
|
|
|
979
982
|
strict: true,
|
|
980
983
|
C: tempDir,
|
|
981
984
|
portable: true,
|
|
982
|
-
onwarn: () => {}
|
|
983
|
-
})
|
|
985
|
+
onwarn: () => {},
|
|
986
|
+
}),
|
|
984
987
|
);
|
|
985
988
|
} catch (err) {
|
|
986
989
|
if (localData && localData.Id) {
|
|
@@ -996,8 +999,8 @@ export const exportImage = async (fullImageName) => {
|
|
|
996
999
|
strict: true,
|
|
997
1000
|
C: tempDir,
|
|
998
1001
|
portable: true,
|
|
999
|
-
onwarn: () => {}
|
|
1000
|
-
})
|
|
1002
|
+
onwarn: () => {},
|
|
1003
|
+
}),
|
|
1001
1004
|
);
|
|
1002
1005
|
} catch (err) {
|
|
1003
1006
|
console.log(err);
|
|
@@ -1013,13 +1016,13 @@ export const exportImage = async (fullImageName) => {
|
|
|
1013
1016
|
manifestFile = manifestIndexFile;
|
|
1014
1017
|
} else {
|
|
1015
1018
|
console.log(
|
|
1016
|
-
`Manifest file ${manifestFile} was not found after export at ${tempDir}
|
|
1019
|
+
`Manifest file ${manifestFile} was not found after export at ${tempDir}`,
|
|
1017
1020
|
);
|
|
1018
1021
|
return undefined;
|
|
1019
1022
|
}
|
|
1020
1023
|
if (DEBUG_MODE) {
|
|
1021
1024
|
console.log(
|
|
1022
|
-
`Image ${fullImageName} successfully exported to directory ${tempDir}
|
|
1025
|
+
`Image ${fullImageName} successfully exported to directory ${tempDir}`,
|
|
1023
1026
|
);
|
|
1024
1027
|
}
|
|
1025
1028
|
mkdirSync(allLayersExplodedDir);
|
|
@@ -1027,7 +1030,7 @@ export const exportImage = async (fullImageName) => {
|
|
|
1027
1030
|
manifestFile,
|
|
1028
1031
|
localData,
|
|
1029
1032
|
tempDir,
|
|
1030
|
-
allLayersExplodedDir
|
|
1033
|
+
allLayersExplodedDir,
|
|
1031
1034
|
);
|
|
1032
1035
|
} else {
|
|
1033
1036
|
console.log(`Unable to export image to ${tempDir}`);
|
|
@@ -1054,7 +1057,7 @@ export const getPkgPathList = (exportData, lastWorkingDir) => {
|
|
|
1054
1057
|
join(allLayersExplodedDir, "/usr/src"),
|
|
1055
1058
|
join(allLayersExplodedDir, "/var/www/html"),
|
|
1056
1059
|
join(allLayersExplodedDir, "/var/lib"),
|
|
1057
|
-
join(allLayersExplodedDir, "/mnt")
|
|
1060
|
+
join(allLayersExplodedDir, "/mnt"),
|
|
1058
1061
|
];
|
|
1059
1062
|
} else if (allLayersExplodedDir === "") {
|
|
1060
1063
|
knownSysPaths = [
|
|
@@ -1065,7 +1068,7 @@ export const getPkgPathList = (exportData, lastWorkingDir) => {
|
|
|
1065
1068
|
join(allLayersExplodedDir, "/usr/share"),
|
|
1066
1069
|
join(allLayersExplodedDir, "/usr/src"),
|
|
1067
1070
|
join(allLayersExplodedDir, "/var/www/html"),
|
|
1068
|
-
join(allLayersExplodedDir, "/var/lib")
|
|
1071
|
+
join(allLayersExplodedDir, "/var/lib"),
|
|
1069
1072
|
];
|
|
1070
1073
|
}
|
|
1071
1074
|
if (existsSync(join(allLayersDir, "Files"))) {
|
|
@@ -1142,7 +1145,7 @@ export const getPkgPathList = (exportData, lastWorkingDir) => {
|
|
|
1142
1145
|
export const removeImage = async (fullImageName, force = false) => {
|
|
1143
1146
|
const removeData = await makeRequest(
|
|
1144
1147
|
`images/${fullImageName}?force=${force}`,
|
|
1145
|
-
"DELETE"
|
|
1148
|
+
"DELETE",
|
|
1146
1149
|
);
|
|
1147
1150
|
return removeData;
|
|
1148
1151
|
};
|
|
@@ -1157,7 +1160,7 @@ export const getCredsFromHelper = (exeSuffix, serverAddress) => {
|
|
|
1157
1160
|
}
|
|
1158
1161
|
const result = spawnSync(credHelperExe, ["get"], {
|
|
1159
1162
|
input: serverAddress,
|
|
1160
|
-
encoding: "utf-8"
|
|
1163
|
+
encoding: "utf-8",
|
|
1161
1164
|
});
|
|
1162
1165
|
if (result.status !== 0 || result.error) {
|
|
1163
1166
|
console.log(result.stdout, result.stderr);
|
|
@@ -1176,10 +1179,10 @@ export const getCredsFromHelper = (exeSuffix, serverAddress) => {
|
|
|
1176
1179
|
process.env.DOCKER_PASSWORD,
|
|
1177
1180
|
email:
|
|
1178
1181
|
authPayload.email || authPayload.username || process.env.DOCKER_USER,
|
|
1179
|
-
serveraddress: serverAddress
|
|
1182
|
+
serveraddress: serverAddress,
|
|
1180
1183
|
};
|
|
1181
1184
|
const authKey = Buffer.from(JSON.stringify(fixedAuthPayload)).toString(
|
|
1182
|
-
"base64"
|
|
1185
|
+
"base64",
|
|
1183
1186
|
);
|
|
1184
1187
|
registry_auth_keys[serverAddress] = authKey;
|
|
1185
1188
|
return authKey;
|
|
@@ -1211,7 +1214,7 @@ export const addSkippedSrcFiles = (skippedImageSrcs, components) => {
|
|
|
1211
1214
|
) {
|
|
1212
1215
|
co.properties = co.properties.concat({
|
|
1213
1216
|
name: "SrcFile",
|
|
1214
|
-
value: skippedImage.src
|
|
1217
|
+
value: skippedImage.src,
|
|
1215
1218
|
});
|
|
1216
1219
|
}
|
|
1217
1220
|
}
|