@cyclonedx/cdxgen 9.0.1 → 9.1.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyclonedx/cdxgen",
3
- "version": "9.0.1",
3
+ "version": "9.1.1",
4
4
  "description": "Creates CycloneDX Software Bill-of-Materials (SBOM) from source or container image",
5
5
  "homepage": "http://github.com/cyclonedx/cdxgen",
6
6
  "author": "Prabhu Subramanian <prabhu@appthreat.com>",
@@ -36,7 +36,7 @@
36
36
  "scripts": {
37
37
  "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --inject-globals false",
38
38
  "watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch --inject-globals false",
39
- "lint": "eslint index.js utils.js binary.js server.js docker.js *.test.js bin/cdxgen.js",
39
+ "lint": "eslint *.js *.test.js bin/cdxgen.js",
40
40
  "pretty": "prettier --write *.js data/*.json bin/cdxgen.js --trailing-comma=none"
41
41
  },
42
42
  "engines": {
@@ -52,6 +52,8 @@
52
52
  "dependencies": {
53
53
  "@babel/parser": "^7.22.5",
54
54
  "@babel/traverse": "^7.22.5",
55
+ "ajv": "^8.12.0",
56
+ "ajv-formats": "^2.1.1",
55
57
  "cheerio": "^1.0.0-rc.12",
56
58
  "edn-data": "^1.0.0",
57
59
  "glob": "^10.3.0",
@@ -64,7 +66,7 @@
64
66
  "prettify-xml": "^1.2.0",
65
67
  "properties-reader": "^2.2.0",
66
68
  "semver": "^7.5.3",
67
- "ssri": "^8.0.1",
69
+ "ssri": "^10.0.4",
68
70
  "table": "^6.8.1",
69
71
  "tar": "^6.1.15",
70
72
  "uuid": "^9.0.0",
package/piptree.js ADDED
@@ -0,0 +1,136 @@
1
+ /**
2
+ * The idea behind this plugin came from the excellent pipdeptree package
3
+ * https://github.com/tox-dev/pipdeptree
4
+ *
5
+ * We use the internal pip api to construct the dependency tree for modern python + pip environments
6
+ */
7
+ import {
8
+ existsSync,
9
+ mkdtempSync,
10
+ readFileSync,
11
+ rmSync,
12
+ writeFileSync
13
+ } from "node:fs";
14
+ import { join } from "node:path";
15
+ import { tmpdir } from "node:os";
16
+ import { spawnSync } from "node:child_process";
17
+
18
+ const PIP_TREE_PLUGIN_CONTENT = `
19
+ import importlib.metadata as importlib_metadata
20
+ import json
21
+ import sys
22
+
23
+ from pip._internal.metadata import pkg_resources
24
+
25
+
26
+ def frozen_req_from_dist(dist):
27
+ try:
28
+ from pip._internal.operations.freeze import FrozenRequirement
29
+ except ImportError:
30
+ from pip import FrozenRequirement
31
+ try:
32
+ from pip._internal import metadata
33
+
34
+ dist = metadata.pkg_resources.Distribution(dist)
35
+ try:
36
+ fr = FrozenRequirement.from_dist(dist)
37
+ except TypeError:
38
+ fr = FrozenRequirement.from_dist(dist, [])
39
+ return str(fr).strip()
40
+ except ImportError:
41
+ pass
42
+
43
+
44
+ def get_installed_distributions():
45
+ dists = pkg_resources.Environment.from_paths(None).iter_installed_distributions(
46
+ local_only=False,
47
+ skip=(),
48
+ user_only=False,
49
+ )
50
+ return [d._dist for d in dists]
51
+
52
+
53
+ def find_deps(idx, reqs):
54
+ freqs = []
55
+ for r in reqs:
56
+ d = idx.get(r.key)
57
+ r.project_name = d.project_name if d is not None else r.project_name
58
+ specs = sorted(r.specs, reverse=True)
59
+ specs_str = ",".join(["".join(sp) for sp in specs]) if specs else ""
60
+ freqs.append(
61
+ {
62
+ "name": r.project_name,
63
+ "version": importlib_metadata.version(r.key),
64
+ "versionSpecifiers": specs_str,
65
+ "dependencies": find_deps(idx, d.requires()),
66
+ }
67
+ )
68
+ return freqs
69
+
70
+
71
+ def main(argv):
72
+ out_file = "piptree.json" if len(argv) < 2 else argv[-1]
73
+ tree = []
74
+ pkgs = get_installed_distributions()
75
+ idx = {p.key: p for p in pkgs}
76
+ for p in pkgs:
77
+ fr = frozen_req_from_dist(p)
78
+ tmpA = fr.split("==")
79
+ name = tmpA[0]
80
+ if name.startswith("-e"):
81
+ continue
82
+ version = ""
83
+ if len(tmpA) == 2:
84
+ version = tmpA[1]
85
+ tree.append(
86
+ {
87
+ "name": name,
88
+ "version": version,
89
+ "dependencies": find_deps(idx, p.requires()),
90
+ }
91
+ )
92
+ all_deps = {}
93
+ for t in tree:
94
+ for d in t["dependencies"]:
95
+ all_deps[d["name"]] = True
96
+ trimmed_tree = [
97
+ t for t in tree if t["name"] not in all_deps
98
+ ]
99
+ with open(out_file, mode="w", encoding="utf-8") as fp:
100
+ json.dump(trimmed_tree, fp)
101
+
102
+
103
+ if __name__ == "__main__":
104
+ main(sys.argv)
105
+ `;
106
+
107
+ /**
108
+ * Execute the piptree plugin and return the generated tree as json object
109
+ */
110
+ export const getTreeWithPlugin = (env, python_cmd, basePath) => {
111
+ let tree = undefined;
112
+ const tempDir = mkdtempSync(join(tmpdir(), "cdxgen-piptree-"));
113
+ const pipPlugin = join(tempDir, "piptree.py");
114
+ const pipTreeJson = join(tempDir, "piptree.json");
115
+ const pipPluginArgs = [pipPlugin, pipTreeJson];
116
+ writeFileSync(pipPlugin, PIP_TREE_PLUGIN_CONTENT);
117
+ const result = spawnSync(python_cmd, pipPluginArgs, {
118
+ cwd: basePath,
119
+ encoding: "utf-8",
120
+ env
121
+ });
122
+ if (result.status !== 0 || result.error) {
123
+ console.log(result.stdout, result.stderr);
124
+ }
125
+ if (existsSync(pipTreeJson)) {
126
+ tree = JSON.parse(
127
+ readFileSync(pipTreeJson, {
128
+ encoding: "utf-8"
129
+ })
130
+ );
131
+ }
132
+ if (rmSync) {
133
+ rmSync(tempDir, { recursive: true, force: true });
134
+ }
135
+ return tree;
136
+ };
package/server.js CHANGED
@@ -79,7 +79,7 @@ const configureServer = (cdxgenServer) => {
79
79
  cdxgenServer.keepAliveTimeout = 0;
80
80
  };
81
81
 
82
- const start = async (options) => {
82
+ const start = (options) => {
83
83
  console.log("Listening on", options.serverHost, options.serverPort);
84
84
  const cdxgenServer = http
85
85
  .createServer(app)
@@ -89,7 +89,7 @@ const start = async (options) => {
89
89
  const q = url.parse(req.url, true).query;
90
90
  let cleanup = false;
91
91
  options = parseQueryString(q, req.body, options);
92
- let filePath = q.path || q.url || req.body.path || req.body.url;
92
+ const filePath = q.path || q.url || req.body.path || req.body.url;
93
93
  if (!filePath) {
94
94
  res.writeHead(500, { "Content-Type": "application/json" });
95
95
  return res.end(