diff --git a/src/providers/python_uv.js b/src/providers/python_uv.js index c96b0956..1052ad05 100644 --- a/src/providers/python_uv.js +++ b/src/providers/python_uv.js @@ -28,12 +28,52 @@ export default class Python_uv extends Base_pyproject { * @param {string} workspaceDir - workspace root (for resolving editable install paths) * @param {object} parsed - parsed pyproject.toml * @param {Object} opts - * @returns {Promise<{directDeps: string[], graph: Map}>} + * @returns {Promise<{directDeps: string[], graph: Map}>} */ async _getDependencyData(manifestDir, workspaceDir, parsed, opts) { let projectName = this._getProjectName(parsed) let uvOutput = this._getUvExportOutput(manifestDir, opts) - return this._parseUvExport(uvOutput, projectName, workspaceDir) + let { directDeps, graph } = await this._parseUvExport(uvOutput, projectName, workspaceDir) + this._attachHashesFromLockFile(path.join(workspaceDir, 'uv.lock'), graph) + return { directDeps, graph } + } + + /** + * Parse uv.lock and attach SHA-256 hashes to graph entries. + * @param {string} lockFilePath - path to uv.lock + * @param {Map} graph + */ + _attachHashesFromLockFile(lockFilePath, graph) { + let lockContent + try { + lockContent = fs.readFileSync(lockFilePath, 'utf-8') + } catch (e) { + console.error(`uv: could not read lock file ${lockFilePath}: ${e.message}`) + return + } + + let parsed + try { + parsed = parseToml(lockContent) + } catch (e) { + console.error(`uv: could not parse lock file ${lockFilePath}: ${e.message}`) + return + } + + let packages = parsed.package + if (!Array.isArray(packages)) { return } + + for (let pkg of packages) { + if (!pkg.name) { continue } + let hashStr = pkg.sdist?.hash || pkg.wheels?.[0]?.hash + if (!hashStr || !hashStr.startsWith('sha256:')) { continue } + + let key = this._canonicalize(pkg.name) + let entry = graph.get(key) + if (!entry || entry.hashes) { continue } + + entry.hashes = [{alg: "SHA-256", content: hashStr.slice(7)}] + } } /** diff --git a/test/providers/tst_manifests/pyproject/pep621_ignore_and_extras/expected_component_sbom.json b/test/providers/tst_manifests/pyproject/pep621_ignore_and_extras/expected_component_sbom.json index 3ddae63d..6f4270c9 100644 --- a/test/providers/tst_manifests/pyproject/pep621_ignore_and_extras/expected_component_sbom.json +++ b/test/providers/tst_manifests/pyproject/pep621_ignore_and_extras/expected_component_sbom.json @@ -18,21 +18,39 @@ "version": "2.0.3", "purl": "pkg:pypi/flask@2.0.3", "type": "library", - "bom-ref": "pkg:pypi/flask@2.0.3" + "bom-ref": "pkg:pypi/flask@2.0.3", + "hashes": [ + { + "alg": "SHA-256", + "content": "e1120c228ca2f553b470df4a5fa927ab66258467526069981b3eb0a91902687d" + } + ] }, { "name": "requests", "version": "2.25.1", "purl": "pkg:pypi/requests@2.25.1", "type": "library", - "bom-ref": "pkg:pypi/requests@2.25.1" + "bom-ref": "pkg:pypi/requests@2.25.1", + "hashes": [ + { + "alg": "SHA-256", + "content": "27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804" + } + ] }, { "name": "typing-extensions", "version": "4.1.1", "purl": "pkg:pypi/typing-extensions@4.1.1", "type": "library", - "bom-ref": "pkg:pypi/typing-extensions@4.1.1" + "bom-ref": "pkg:pypi/typing-extensions@4.1.1", + "hashes": [ + { + "alg": "SHA-256", + "content": "1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42" + } + ] } ], "dependencies": [ diff --git a/test/providers/tst_manifests/pyproject/pep621_ignore_and_extras/expected_stack_sbom.json b/test/providers/tst_manifests/pyproject/pep621_ignore_and_extras/expected_stack_sbom.json index f53d47df..86d604f9 100644 --- a/test/providers/tst_manifests/pyproject/pep621_ignore_and_extras/expected_stack_sbom.json +++ b/test/providers/tst_manifests/pyproject/pep621_ignore_and_extras/expected_stack_sbom.json @@ -18,77 +18,143 @@ "version": "2.0.3", "purl": "pkg:pypi/flask@2.0.3", "type": "library", - "bom-ref": "pkg:pypi/flask@2.0.3" + "bom-ref": "pkg:pypi/flask@2.0.3", + "hashes": [ + { + "alg": "SHA-256", + "content": "e1120c228ca2f553b470df4a5fa927ab66258467526069981b3eb0a91902687d" + } + ] }, { "name": "requests", "version": "2.25.1", "purl": "pkg:pypi/requests@2.25.1", "type": "library", - "bom-ref": "pkg:pypi/requests@2.25.1" + "bom-ref": "pkg:pypi/requests@2.25.1", + "hashes": [ + { + "alg": "SHA-256", + "content": "27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804" + } + ] }, { "name": "typing-extensions", "version": "4.1.1", "purl": "pkg:pypi/typing-extensions@4.1.1", "type": "library", - "bom-ref": "pkg:pypi/typing-extensions@4.1.1" + "bom-ref": "pkg:pypi/typing-extensions@4.1.1", + "hashes": [ + { + "alg": "SHA-256", + "content": "1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42" + } + ] }, { "name": "click", "version": "8.3.1", "purl": "pkg:pypi/click@8.3.1", "type": "library", - "bom-ref": "pkg:pypi/click@8.3.1" + "bom-ref": "pkg:pypi/click@8.3.1", + "hashes": [ + { + "alg": "SHA-256", + "content": "12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a" + } + ] }, { "name": "itsdangerous", "version": "2.0.1", "purl": "pkg:pypi/itsdangerous@2.0.1", "type": "library", - "bom-ref": "pkg:pypi/itsdangerous@2.0.1" + "bom-ref": "pkg:pypi/itsdangerous@2.0.1", + "hashes": [ + { + "alg": "SHA-256", + "content": "9e724d68fc22902a1435351f84c3fb8623f303fffcc566a4cb952df8c572cff0" + } + ] }, { "name": "jinja2", "version": "3.0.3", "purl": "pkg:pypi/jinja2@3.0.3", "type": "library", - "bom-ref": "pkg:pypi/jinja2@3.0.3" + "bom-ref": "pkg:pypi/jinja2@3.0.3", + "hashes": [ + { + "alg": "SHA-256", + "content": "611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7" + } + ] }, { "name": "werkzeug", "version": "2.0.3", "purl": "pkg:pypi/werkzeug@2.0.3", "type": "library", - "bom-ref": "pkg:pypi/werkzeug@2.0.3" + "bom-ref": "pkg:pypi/werkzeug@2.0.3", + "hashes": [ + { + "alg": "SHA-256", + "content": "b863f8ff057c522164b6067c9e28b041161b4be5ba4d0daceeaa50a163822d3c" + } + ] }, { "name": "certifi", "version": "2023.7.22", "purl": "pkg:pypi/certifi@2023.7.22", "type": "library", - "bom-ref": "pkg:pypi/certifi@2023.7.22" + "bom-ref": "pkg:pypi/certifi@2023.7.22", + "hashes": [ + { + "alg": "SHA-256", + "content": "539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082" + } + ] }, { "name": "chardet", "version": "4.0.0", "purl": "pkg:pypi/chardet@4.0.0", "type": "library", - "bom-ref": "pkg:pypi/chardet@4.0.0" + "bom-ref": "pkg:pypi/chardet@4.0.0", + "hashes": [ + { + "alg": "SHA-256", + "content": "0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa" + } + ] }, { "name": "idna", "version": "2.10", "purl": "pkg:pypi/idna@2.10", "type": "library", - "bom-ref": "pkg:pypi/idna@2.10" + "bom-ref": "pkg:pypi/idna@2.10", + "hashes": [ + { + "alg": "SHA-256", + "content": "b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6" + } + ] }, { "name": "urllib3", "version": "1.26.16", "purl": "pkg:pypi/urllib3@1.26.16", "type": "library", - "bom-ref": "pkg:pypi/urllib3@1.26.16" + "bom-ref": "pkg:pypi/urllib3@1.26.16", + "hashes": [ + { + "alg": "SHA-256", + "content": "8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14" + } + ] } ], "dependencies": [ diff --git a/test/providers/tst_manifests/pyproject/uv_dev_deps/expected_component_sbom.json b/test/providers/tst_manifests/pyproject/uv_dev_deps/expected_component_sbom.json index 024fd437..5549450a 100644 --- a/test/providers/tst_manifests/pyproject/uv_dev_deps/expected_component_sbom.json +++ b/test/providers/tst_manifests/pyproject/uv_dev_deps/expected_component_sbom.json @@ -18,7 +18,13 @@ "version": "2.33.1", "purl": "pkg:pypi/requests@2.33.1", "type": "library", - "bom-ref": "pkg:pypi/requests@2.33.1" + "bom-ref": "pkg:pypi/requests@2.33.1", + "hashes": [ + { + "alg": "SHA-256", + "content": "18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517" + } + ] } ], "dependencies": [ diff --git a/test/providers/tst_manifests/pyproject/uv_dev_deps/expected_stack_sbom.json b/test/providers/tst_manifests/pyproject/uv_dev_deps/expected_stack_sbom.json index a0469c93..9e19ac1b 100644 --- a/test/providers/tst_manifests/pyproject/uv_dev_deps/expected_stack_sbom.json +++ b/test/providers/tst_manifests/pyproject/uv_dev_deps/expected_stack_sbom.json @@ -18,35 +18,65 @@ "version": "2.33.1", "purl": "pkg:pypi/requests@2.33.1", "type": "library", - "bom-ref": "pkg:pypi/requests@2.33.1" + "bom-ref": "pkg:pypi/requests@2.33.1", + "hashes": [ + { + "alg": "SHA-256", + "content": "18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517" + } + ] }, { "name": "certifi", "version": "2026.2.25", "purl": "pkg:pypi/certifi@2026.2.25", "type": "library", - "bom-ref": "pkg:pypi/certifi@2026.2.25" + "bom-ref": "pkg:pypi/certifi@2026.2.25", + "hashes": [ + { + "alg": "SHA-256", + "content": "e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7" + } + ] }, { "name": "charset-normalizer", "version": "3.4.7", "purl": "pkg:pypi/charset-normalizer@3.4.7", "type": "library", - "bom-ref": "pkg:pypi/charset-normalizer@3.4.7" + "bom-ref": "pkg:pypi/charset-normalizer@3.4.7", + "hashes": [ + { + "alg": "SHA-256", + "content": "ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5" + } + ] }, { "name": "idna", "version": "3.11", "purl": "pkg:pypi/idna@3.11", "type": "library", - "bom-ref": "pkg:pypi/idna@3.11" + "bom-ref": "pkg:pypi/idna@3.11", + "hashes": [ + { + "alg": "SHA-256", + "content": "795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902" + } + ] }, { "name": "urllib3", "version": "2.6.3", "purl": "pkg:pypi/urllib3@2.6.3", "type": "library", - "bom-ref": "pkg:pypi/urllib3@2.6.3" + "bom-ref": "pkg:pypi/urllib3@2.6.3", + "hashes": [ + { + "alg": "SHA-256", + "content": "1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed" + } + ] } ], "dependencies": [ diff --git a/test/providers/tst_manifests/pyproject/uv_lock/expected_component_sbom.json b/test/providers/tst_manifests/pyproject/uv_lock/expected_component_sbom.json index b0b1108e..f131b129 100644 --- a/test/providers/tst_manifests/pyproject/uv_lock/expected_component_sbom.json +++ b/test/providers/tst_manifests/pyproject/uv_lock/expected_component_sbom.json @@ -18,14 +18,26 @@ "version": "2.0.3", "purl": "pkg:pypi/flask@2.0.3", "type": "library", - "bom-ref": "pkg:pypi/flask@2.0.3" + "bom-ref": "pkg:pypi/flask@2.0.3", + "hashes": [ + { + "alg": "SHA-256", + "content": "e1120c228ca2f553b470df4a5fa927ab66258467526069981b3eb0a91902687d" + } + ] }, { "name": "requests", "version": "2.25.1", "purl": "pkg:pypi/requests@2.25.1", "type": "library", - "bom-ref": "pkg:pypi/requests@2.25.1" + "bom-ref": "pkg:pypi/requests@2.25.1", + "hashes": [ + { + "alg": "SHA-256", + "content": "27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804" + } + ] } ], "dependencies": [ diff --git a/test/providers/tst_manifests/pyproject/uv_lock/expected_stack_sbom.json b/test/providers/tst_manifests/pyproject/uv_lock/expected_stack_sbom.json index b8211ba4..f433e65c 100644 --- a/test/providers/tst_manifests/pyproject/uv_lock/expected_stack_sbom.json +++ b/test/providers/tst_manifests/pyproject/uv_lock/expected_stack_sbom.json @@ -18,77 +18,143 @@ "version": "2.0.3", "purl": "pkg:pypi/flask@2.0.3", "type": "library", - "bom-ref": "pkg:pypi/flask@2.0.3" + "bom-ref": "pkg:pypi/flask@2.0.3", + "hashes": [ + { + "alg": "SHA-256", + "content": "e1120c228ca2f553b470df4a5fa927ab66258467526069981b3eb0a91902687d" + } + ] }, { "name": "requests", "version": "2.25.1", "purl": "pkg:pypi/requests@2.25.1", "type": "library", - "bom-ref": "pkg:pypi/requests@2.25.1" + "bom-ref": "pkg:pypi/requests@2.25.1", + "hashes": [ + { + "alg": "SHA-256", + "content": "27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804" + } + ] }, { "name": "click", "version": "8.3.1", "purl": "pkg:pypi/click@8.3.1", "type": "library", - "bom-ref": "pkg:pypi/click@8.3.1" + "bom-ref": "pkg:pypi/click@8.3.1", + "hashes": [ + { + "alg": "SHA-256", + "content": "12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a" + } + ] }, { "name": "itsdangerous", "version": "2.0.1", "purl": "pkg:pypi/itsdangerous@2.0.1", "type": "library", - "bom-ref": "pkg:pypi/itsdangerous@2.0.1" + "bom-ref": "pkg:pypi/itsdangerous@2.0.1", + "hashes": [ + { + "alg": "SHA-256", + "content": "9e724d68fc22902a1435351f84c3fb8623f303fffcc566a4cb952df8c572cff0" + } + ] }, { "name": "jinja2", "version": "3.0.3", "purl": "pkg:pypi/jinja2@3.0.3", "type": "library", - "bom-ref": "pkg:pypi/jinja2@3.0.3" + "bom-ref": "pkg:pypi/jinja2@3.0.3", + "hashes": [ + { + "alg": "SHA-256", + "content": "611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7" + } + ] }, { "name": "werkzeug", "version": "2.0.3", "purl": "pkg:pypi/werkzeug@2.0.3", "type": "library", - "bom-ref": "pkg:pypi/werkzeug@2.0.3" + "bom-ref": "pkg:pypi/werkzeug@2.0.3", + "hashes": [ + { + "alg": "SHA-256", + "content": "b863f8ff057c522164b6067c9e28b041161b4be5ba4d0daceeaa50a163822d3c" + } + ] }, { "name": "markupsafe", "version": "2.0.1", "purl": "pkg:pypi/markupsafe@2.0.1", "type": "library", - "bom-ref": "pkg:pypi/markupsafe@2.0.1" + "bom-ref": "pkg:pypi/markupsafe@2.0.1", + "hashes": [ + { + "alg": "SHA-256", + "content": "594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a" + } + ] }, { "name": "certifi", "version": "2023.7.22", "purl": "pkg:pypi/certifi@2023.7.22", "type": "library", - "bom-ref": "pkg:pypi/certifi@2023.7.22" + "bom-ref": "pkg:pypi/certifi@2023.7.22", + "hashes": [ + { + "alg": "SHA-256", + "content": "539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082" + } + ] }, { "name": "chardet", "version": "4.0.0", "purl": "pkg:pypi/chardet@4.0.0", "type": "library", - "bom-ref": "pkg:pypi/chardet@4.0.0" + "bom-ref": "pkg:pypi/chardet@4.0.0", + "hashes": [ + { + "alg": "SHA-256", + "content": "0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa" + } + ] }, { "name": "idna", "version": "2.10", "purl": "pkg:pypi/idna@2.10", "type": "library", - "bom-ref": "pkg:pypi/idna@2.10" + "bom-ref": "pkg:pypi/idna@2.10", + "hashes": [ + { + "alg": "SHA-256", + "content": "b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6" + } + ] }, { "name": "urllib3", "version": "1.26.16", "purl": "pkg:pypi/urllib3@1.26.16", "type": "library", - "bom-ref": "pkg:pypi/urllib3@1.26.16" + "bom-ref": "pkg:pypi/urllib3@1.26.16", + "hashes": [ + { + "alg": "SHA-256", + "content": "8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14" + } + ] } ], "dependencies": [ diff --git a/test/providers/tst_manifests/pyproject/uv_self_ref/expected_component_sbom.json b/test/providers/tst_manifests/pyproject/uv_self_ref/expected_component_sbom.json index 6aacd266..e9e7418f 100644 --- a/test/providers/tst_manifests/pyproject/uv_self_ref/expected_component_sbom.json +++ b/test/providers/tst_manifests/pyproject/uv_self_ref/expected_component_sbom.json @@ -18,42 +18,78 @@ "version": "4.12.2", "purl": "pkg:pypi/beautifulsoup4@4.12.2", "type": "library", - "bom-ref": "pkg:pypi/beautifulsoup4@4.12.2" + "bom-ref": "pkg:pypi/beautifulsoup4@4.12.2", + "hashes": [ + { + "alg": "SHA-256", + "content": "492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da" + } + ] }, { "name": "certifi", "version": "2023.7.22", "purl": "pkg:pypi/certifi@2023.7.22", "type": "library", - "bom-ref": "pkg:pypi/certifi@2023.7.22" + "bom-ref": "pkg:pypi/certifi@2023.7.22", + "hashes": [ + { + "alg": "SHA-256", + "content": "539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082" + } + ] }, { "name": "click", "version": "8.0.4", "purl": "pkg:pypi/click@8.0.4", "type": "library", - "bom-ref": "pkg:pypi/click@8.0.4" + "bom-ref": "pkg:pypi/click@8.0.4", + "hashes": [ + { + "alg": "SHA-256", + "content": "8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb" + } + ] }, { "name": "flask", "version": "2.0.3", "purl": "pkg:pypi/flask@2.0.3", "type": "library", - "bom-ref": "pkg:pypi/flask@2.0.3" + "bom-ref": "pkg:pypi/flask@2.0.3", + "hashes": [ + { + "alg": "SHA-256", + "content": "e1120c228ca2f553b470df4a5fa927ab66258467526069981b3eb0a91902687d" + } + ] }, { "name": "requests", "version": "2.25.1", "purl": "pkg:pypi/requests@2.25.1", "type": "library", - "bom-ref": "pkg:pypi/requests@2.25.1" + "bom-ref": "pkg:pypi/requests@2.25.1", + "hashes": [ + { + "alg": "SHA-256", + "content": "27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804" + } + ] }, { "name": "uvicorn", "version": "0.17.0", "purl": "pkg:pypi/uvicorn@0.17.0", "type": "library", - "bom-ref": "pkg:pypi/uvicorn@0.17.0" + "bom-ref": "pkg:pypi/uvicorn@0.17.0", + "hashes": [ + { + "alg": "SHA-256", + "content": "192c2422b056a3beb512c6c260bf77a7a884204a4ae41856719c1913ead63bbb" + } + ] } ], "dependencies": [ diff --git a/test/providers/tst_manifests/pyproject/uv_self_ref/expected_stack_sbom.json b/test/providers/tst_manifests/pyproject/uv_self_ref/expected_stack_sbom.json index 910748da..74577895 100644 --- a/test/providers/tst_manifests/pyproject/uv_self_ref/expected_stack_sbom.json +++ b/test/providers/tst_manifests/pyproject/uv_self_ref/expected_stack_sbom.json @@ -18,112 +18,208 @@ "version": "4.12.2", "purl": "pkg:pypi/beautifulsoup4@4.12.2", "type": "library", - "bom-ref": "pkg:pypi/beautifulsoup4@4.12.2" + "bom-ref": "pkg:pypi/beautifulsoup4@4.12.2", + "hashes": [ + { + "alg": "SHA-256", + "content": "492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da" + } + ] }, { "name": "certifi", "version": "2023.7.22", "purl": "pkg:pypi/certifi@2023.7.22", "type": "library", - "bom-ref": "pkg:pypi/certifi@2023.7.22" + "bom-ref": "pkg:pypi/certifi@2023.7.22", + "hashes": [ + { + "alg": "SHA-256", + "content": "539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082" + } + ] }, { "name": "click", "version": "8.0.4", "purl": "pkg:pypi/click@8.0.4", "type": "library", - "bom-ref": "pkg:pypi/click@8.0.4" + "bom-ref": "pkg:pypi/click@8.0.4", + "hashes": [ + { + "alg": "SHA-256", + "content": "8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb" + } + ] }, { "name": "flask", "version": "2.0.3", "purl": "pkg:pypi/flask@2.0.3", "type": "library", - "bom-ref": "pkg:pypi/flask@2.0.3" + "bom-ref": "pkg:pypi/flask@2.0.3", + "hashes": [ + { + "alg": "SHA-256", + "content": "e1120c228ca2f553b470df4a5fa927ab66258467526069981b3eb0a91902687d" + } + ] }, { "name": "requests", "version": "2.25.1", "purl": "pkg:pypi/requests@2.25.1", "type": "library", - "bom-ref": "pkg:pypi/requests@2.25.1" + "bom-ref": "pkg:pypi/requests@2.25.1", + "hashes": [ + { + "alg": "SHA-256", + "content": "27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804" + } + ] }, { "name": "uvicorn", "version": "0.17.0", "purl": "pkg:pypi/uvicorn@0.17.0", "type": "library", - "bom-ref": "pkg:pypi/uvicorn@0.17.0" + "bom-ref": "pkg:pypi/uvicorn@0.17.0", + "hashes": [ + { + "alg": "SHA-256", + "content": "192c2422b056a3beb512c6c260bf77a7a884204a4ae41856719c1913ead63bbb" + } + ] }, { "name": "soupsieve", "version": "2.8.3", "purl": "pkg:pypi/soupsieve@2.8.3", "type": "library", - "bom-ref": "pkg:pypi/soupsieve@2.8.3" + "bom-ref": "pkg:pypi/soupsieve@2.8.3", + "hashes": [ + { + "alg": "SHA-256", + "content": "3267f1eeea4251fb42728b6dfb746edc9acaffc4a45b27e19450b676586e8349" + } + ] }, { "name": "itsdangerous", "version": "2.2.0", "purl": "pkg:pypi/itsdangerous@2.2.0", "type": "library", - "bom-ref": "pkg:pypi/itsdangerous@2.2.0" + "bom-ref": "pkg:pypi/itsdangerous@2.2.0", + "hashes": [ + { + "alg": "SHA-256", + "content": "e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173" + } + ] }, { "name": "jinja2", "version": "3.1.6", "purl": "pkg:pypi/jinja2@3.1.6", "type": "library", - "bom-ref": "pkg:pypi/jinja2@3.1.6" + "bom-ref": "pkg:pypi/jinja2@3.1.6", + "hashes": [ + { + "alg": "SHA-256", + "content": "0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d" + } + ] }, { "name": "werkzeug", "version": "3.1.8", "purl": "pkg:pypi/werkzeug@3.1.8", "type": "library", - "bom-ref": "pkg:pypi/werkzeug@3.1.8" + "bom-ref": "pkg:pypi/werkzeug@3.1.8", + "hashes": [ + { + "alg": "SHA-256", + "content": "9bad61a4268dac112f1c5cd4630a56ede601b6ed420300677a869083d70a4c44" + } + ] }, { "name": "markupsafe", "version": "3.0.3", "purl": "pkg:pypi/markupsafe@3.0.3", "type": "library", - "bom-ref": "pkg:pypi/markupsafe@3.0.3" + "bom-ref": "pkg:pypi/markupsafe@3.0.3", + "hashes": [ + { + "alg": "SHA-256", + "content": "722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698" + } + ] }, { "name": "chardet", "version": "4.0.0", "purl": "pkg:pypi/chardet@4.0.0", "type": "library", - "bom-ref": "pkg:pypi/chardet@4.0.0" + "bom-ref": "pkg:pypi/chardet@4.0.0", + "hashes": [ + { + "alg": "SHA-256", + "content": "0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa" + } + ] }, { "name": "idna", "version": "2.10", "purl": "pkg:pypi/idna@2.10", "type": "library", - "bom-ref": "pkg:pypi/idna@2.10" + "bom-ref": "pkg:pypi/idna@2.10", + "hashes": [ + { + "alg": "SHA-256", + "content": "b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6" + } + ] }, { "name": "urllib3", "version": "1.26.20", "purl": "pkg:pypi/urllib3@1.26.20", "type": "library", - "bom-ref": "pkg:pypi/urllib3@1.26.20" + "bom-ref": "pkg:pypi/urllib3@1.26.20", + "hashes": [ + { + "alg": "SHA-256", + "content": "40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32" + } + ] }, { "name": "asgiref", "version": "3.11.1", "purl": "pkg:pypi/asgiref@3.11.1", "type": "library", - "bom-ref": "pkg:pypi/asgiref@3.11.1" + "bom-ref": "pkg:pypi/asgiref@3.11.1", + "hashes": [ + { + "alg": "SHA-256", + "content": "5f184dc43b7e763efe848065441eac62229c9f7b0475f41f80e207a114eda4ce" + } + ] }, { "name": "h11", "version": "0.16.0", "purl": "pkg:pypi/h11@0.16.0", "type": "library", - "bom-ref": "pkg:pypi/h11@0.16.0" + "bom-ref": "pkg:pypi/h11@0.16.0", + "hashes": [ + { + "alg": "SHA-256", + "content": "4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1" + } + ] } ], "dependencies": [ diff --git a/test/providers/tst_manifests/pyproject/uv_workspace/expected_component_sbom.json b/test/providers/tst_manifests/pyproject/uv_workspace/expected_component_sbom.json index 5c56a20c..3d2e69fc 100644 --- a/test/providers/tst_manifests/pyproject/uv_workspace/expected_component_sbom.json +++ b/test/providers/tst_manifests/pyproject/uv_workspace/expected_component_sbom.json @@ -25,7 +25,13 @@ "version": "2.0.3", "purl": "pkg:pypi/flask@2.0.3", "type": "library", - "bom-ref": "pkg:pypi/flask@2.0.3" + "bom-ref": "pkg:pypi/flask@2.0.3", + "hashes": [ + { + "alg": "SHA-256", + "content": "e1120c228ca2f553b470df4a5fa927ab66258467526069981b3eb0a91902687d" + } + ] } ], "dependencies": [ diff --git a/test/providers/tst_manifests/pyproject/uv_workspace/expected_stack_sbom.json b/test/providers/tst_manifests/pyproject/uv_workspace/expected_stack_sbom.json index 273778b7..560bfe9c 100644 --- a/test/providers/tst_manifests/pyproject/uv_workspace/expected_stack_sbom.json +++ b/test/providers/tst_manifests/pyproject/uv_workspace/expected_stack_sbom.json @@ -25,7 +25,13 @@ "version": "2.0.3", "purl": "pkg:pypi/flask@2.0.3", "type": "library", - "bom-ref": "pkg:pypi/flask@2.0.3" + "bom-ref": "pkg:pypi/flask@2.0.3", + "hashes": [ + { + "alg": "SHA-256", + "content": "e1120c228ca2f553b470df4a5fa927ab66258467526069981b3eb0a91902687d" + } + ] }, { "name": "sub-pkg", @@ -39,70 +45,130 @@ "version": "2.33.1", "purl": "pkg:pypi/requests@2.33.1", "type": "library", - "bom-ref": "pkg:pypi/requests@2.33.1" + "bom-ref": "pkg:pypi/requests@2.33.1", + "hashes": [ + { + "alg": "SHA-256", + "content": "18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517" + } + ] }, { "name": "click", "version": "8.3.2", "purl": "pkg:pypi/click@8.3.2", "type": "library", - "bom-ref": "pkg:pypi/click@8.3.2" + "bom-ref": "pkg:pypi/click@8.3.2", + "hashes": [ + { + "alg": "SHA-256", + "content": "14162b8b3b3550a7d479eafa77dfd3c38d9dc8951f6f69c78913a8f9a7540fd5" + } + ] }, { "name": "itsdangerous", "version": "2.2.0", "purl": "pkg:pypi/itsdangerous@2.2.0", "type": "library", - "bom-ref": "pkg:pypi/itsdangerous@2.2.0" + "bom-ref": "pkg:pypi/itsdangerous@2.2.0", + "hashes": [ + { + "alg": "SHA-256", + "content": "e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173" + } + ] }, { "name": "jinja2", "version": "3.1.6", "purl": "pkg:pypi/jinja2@3.1.6", "type": "library", - "bom-ref": "pkg:pypi/jinja2@3.1.6" + "bom-ref": "pkg:pypi/jinja2@3.1.6", + "hashes": [ + { + "alg": "SHA-256", + "content": "0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d" + } + ] }, { "name": "werkzeug", "version": "3.1.8", "purl": "pkg:pypi/werkzeug@3.1.8", "type": "library", - "bom-ref": "pkg:pypi/werkzeug@3.1.8" + "bom-ref": "pkg:pypi/werkzeug@3.1.8", + "hashes": [ + { + "alg": "SHA-256", + "content": "9bad61a4268dac112f1c5cd4630a56ede601b6ed420300677a869083d70a4c44" + } + ] }, { "name": "markupsafe", "version": "3.0.3", "purl": "pkg:pypi/markupsafe@3.0.3", "type": "library", - "bom-ref": "pkg:pypi/markupsafe@3.0.3" + "bom-ref": "pkg:pypi/markupsafe@3.0.3", + "hashes": [ + { + "alg": "SHA-256", + "content": "722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698" + } + ] }, { "name": "certifi", "version": "2026.2.25", "purl": "pkg:pypi/certifi@2026.2.25", "type": "library", - "bom-ref": "pkg:pypi/certifi@2026.2.25" + "bom-ref": "pkg:pypi/certifi@2026.2.25", + "hashes": [ + { + "alg": "SHA-256", + "content": "e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7" + } + ] }, { "name": "charset-normalizer", "version": "3.4.7", "purl": "pkg:pypi/charset-normalizer@3.4.7", "type": "library", - "bom-ref": "pkg:pypi/charset-normalizer@3.4.7" + "bom-ref": "pkg:pypi/charset-normalizer@3.4.7", + "hashes": [ + { + "alg": "SHA-256", + "content": "ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5" + } + ] }, { "name": "idna", "version": "3.11", "purl": "pkg:pypi/idna@3.11", "type": "library", - "bom-ref": "pkg:pypi/idna@3.11" + "bom-ref": "pkg:pypi/idna@3.11", + "hashes": [ + { + "alg": "SHA-256", + "content": "795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902" + } + ] }, { "name": "urllib3", "version": "2.6.3", "purl": "pkg:pypi/urllib3@2.6.3", "type": "library", - "bom-ref": "pkg:pypi/urllib3@2.6.3" + "bom-ref": "pkg:pypi/urllib3@2.6.3", + "hashes": [ + { + "alg": "SHA-256", + "content": "1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed" + } + ] } ], "dependencies": [ diff --git a/test/providers/tst_manifests/pyproject/uv_workspace/packages/mid-pkg/expected_component_sbom.json b/test/providers/tst_manifests/pyproject/uv_workspace/packages/mid-pkg/expected_component_sbom.json index 149a7c8c..6028991b 100644 --- a/test/providers/tst_manifests/pyproject/uv_workspace/packages/mid-pkg/expected_component_sbom.json +++ b/test/providers/tst_manifests/pyproject/uv_workspace/packages/mid-pkg/expected_component_sbom.json @@ -1,36 +1,36 @@ { - "bomFormat": "CycloneDX", - "specVersion": "1.4", - "version": 1, - "metadata": { - "timestamp": "2023-10-01T00:00:00.000Z", - "component": { - "name": "mid-pkg", - "version": "0.1.0", - "purl": "pkg:pypi/mid-pkg@0.1.0", - "type": "application", - "bom-ref": "pkg:pypi/mid-pkg@0.1.0" - } - }, - "components": [ - { - "name": "sub-pkg", - "version": "0.1.0", - "purl": "pkg:pypi/sub-pkg@0.1.0", - "type": "library", - "bom-ref": "pkg:pypi/sub-pkg@0.1.0" - } - ], - "dependencies": [ - { - "ref": "pkg:pypi/mid-pkg@0.1.0", - "dependsOn": [ - "pkg:pypi/sub-pkg@0.1.0" - ] - }, - { - "ref": "pkg:pypi/sub-pkg@0.1.0", - "dependsOn": [] - } - ] + "bomFormat": "CycloneDX", + "specVersion": "1.4", + "version": 1, + "metadata": { + "timestamp": "2023-10-01T00:00:00.000Z", + "component": { + "name": "mid-pkg", + "version": "0.1.0", + "purl": "pkg:pypi/mid-pkg@0.1.0", + "type": "application", + "bom-ref": "pkg:pypi/mid-pkg@0.1.0" + } + }, + "components": [ + { + "name": "sub-pkg", + "version": "0.1.0", + "purl": "pkg:pypi/sub-pkg@0.1.0", + "type": "library", + "bom-ref": "pkg:pypi/sub-pkg@0.1.0" + } + ], + "dependencies": [ + { + "ref": "pkg:pypi/mid-pkg@0.1.0", + "dependsOn": [ + "pkg:pypi/sub-pkg@0.1.0" + ] + }, + { + "ref": "pkg:pypi/sub-pkg@0.1.0", + "dependsOn": [] + } + ] } diff --git a/test/providers/tst_manifests/pyproject/uv_workspace/packages/mid-pkg/expected_stack_sbom.json b/test/providers/tst_manifests/pyproject/uv_workspace/packages/mid-pkg/expected_stack_sbom.json index 0c72587b..ee88d4b8 100644 --- a/test/providers/tst_manifests/pyproject/uv_workspace/packages/mid-pkg/expected_stack_sbom.json +++ b/test/providers/tst_manifests/pyproject/uv_workspace/packages/mid-pkg/expected_stack_sbom.json @@ -1,98 +1,128 @@ { - "bomFormat": "CycloneDX", - "specVersion": "1.4", - "version": 1, - "metadata": { - "timestamp": "2023-10-01T00:00:00.000Z", - "component": { - "name": "mid-pkg", - "version": "0.1.0", - "purl": "pkg:pypi/mid-pkg@0.1.0", - "type": "application", - "bom-ref": "pkg:pypi/mid-pkg@0.1.0" - } - }, - "components": [ - { - "name": "sub-pkg", - "version": "0.1.0", - "purl": "pkg:pypi/sub-pkg@0.1.0", - "type": "library", - "bom-ref": "pkg:pypi/sub-pkg@0.1.0" - }, - { - "name": "requests", - "version": "2.33.1", - "purl": "pkg:pypi/requests@2.33.1", - "type": "library", - "bom-ref": "pkg:pypi/requests@2.33.1" - }, - { - "name": "certifi", - "version": "2026.2.25", - "purl": "pkg:pypi/certifi@2026.2.25", - "type": "library", - "bom-ref": "pkg:pypi/certifi@2026.2.25" - }, - { - "name": "charset-normalizer", - "version": "3.4.7", - "purl": "pkg:pypi/charset-normalizer@3.4.7", - "type": "library", - "bom-ref": "pkg:pypi/charset-normalizer@3.4.7" - }, - { - "name": "idna", - "version": "3.11", - "purl": "pkg:pypi/idna@3.11", - "type": "library", - "bom-ref": "pkg:pypi/idna@3.11" - }, - { - "name": "urllib3", - "version": "2.6.3", - "purl": "pkg:pypi/urllib3@2.6.3", - "type": "library", - "bom-ref": "pkg:pypi/urllib3@2.6.3" - } - ], - "dependencies": [ - { - "ref": "pkg:pypi/mid-pkg@0.1.0", - "dependsOn": [ - "pkg:pypi/sub-pkg@0.1.0" - ] - }, - { - "ref": "pkg:pypi/sub-pkg@0.1.0", - "dependsOn": [ - "pkg:pypi/requests@2.33.1" - ] - }, - { - "ref": "pkg:pypi/requests@2.33.1", - "dependsOn": [ - "pkg:pypi/certifi@2026.2.25", - "pkg:pypi/charset-normalizer@3.4.7", - "pkg:pypi/idna@3.11", - "pkg:pypi/urllib3@2.6.3" - ] - }, - { - "ref": "pkg:pypi/certifi@2026.2.25", - "dependsOn": [] - }, - { - "ref": "pkg:pypi/charset-normalizer@3.4.7", - "dependsOn": [] - }, - { - "ref": "pkg:pypi/idna@3.11", - "dependsOn": [] - }, - { - "ref": "pkg:pypi/urllib3@2.6.3", - "dependsOn": [] - } - ] + "bomFormat": "CycloneDX", + "specVersion": "1.4", + "version": 1, + "metadata": { + "timestamp": "2023-10-01T00:00:00.000Z", + "component": { + "name": "mid-pkg", + "version": "0.1.0", + "purl": "pkg:pypi/mid-pkg@0.1.0", + "type": "application", + "bom-ref": "pkg:pypi/mid-pkg@0.1.0" + } + }, + "components": [ + { + "name": "sub-pkg", + "version": "0.1.0", + "purl": "pkg:pypi/sub-pkg@0.1.0", + "type": "library", + "bom-ref": "pkg:pypi/sub-pkg@0.1.0" + }, + { + "name": "requests", + "version": "2.33.1", + "purl": "pkg:pypi/requests@2.33.1", + "type": "library", + "bom-ref": "pkg:pypi/requests@2.33.1", + "hashes": [ + { + "alg": "SHA-256", + "content": "18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517" + } + ] + }, + { + "name": "certifi", + "version": "2026.2.25", + "purl": "pkg:pypi/certifi@2026.2.25", + "type": "library", + "bom-ref": "pkg:pypi/certifi@2026.2.25", + "hashes": [ + { + "alg": "SHA-256", + "content": "e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7" + } + ] + }, + { + "name": "charset-normalizer", + "version": "3.4.7", + "purl": "pkg:pypi/charset-normalizer@3.4.7", + "type": "library", + "bom-ref": "pkg:pypi/charset-normalizer@3.4.7", + "hashes": [ + { + "alg": "SHA-256", + "content": "ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5" + } + ] + }, + { + "name": "idna", + "version": "3.11", + "purl": "pkg:pypi/idna@3.11", + "type": "library", + "bom-ref": "pkg:pypi/idna@3.11", + "hashes": [ + { + "alg": "SHA-256", + "content": "795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902" + } + ] + }, + { + "name": "urllib3", + "version": "2.6.3", + "purl": "pkg:pypi/urllib3@2.6.3", + "type": "library", + "bom-ref": "pkg:pypi/urllib3@2.6.3", + "hashes": [ + { + "alg": "SHA-256", + "content": "1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed" + } + ] + } + ], + "dependencies": [ + { + "ref": "pkg:pypi/mid-pkg@0.1.0", + "dependsOn": [ + "pkg:pypi/sub-pkg@0.1.0" + ] + }, + { + "ref": "pkg:pypi/sub-pkg@0.1.0", + "dependsOn": [ + "pkg:pypi/requests@2.33.1" + ] + }, + { + "ref": "pkg:pypi/requests@2.33.1", + "dependsOn": [ + "pkg:pypi/certifi@2026.2.25", + "pkg:pypi/charset-normalizer@3.4.7", + "pkg:pypi/idna@3.11", + "pkg:pypi/urllib3@2.6.3" + ] + }, + { + "ref": "pkg:pypi/certifi@2026.2.25", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/charset-normalizer@3.4.7", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/idna@3.11", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/urllib3@2.6.3", + "dependsOn": [] + } + ] } diff --git a/test/providers/tst_manifests/pyproject/uv_workspace/packages/sub-pkg/expected_component_sbom.json b/test/providers/tst_manifests/pyproject/uv_workspace/packages/sub-pkg/expected_component_sbom.json index 6c3f39a5..dcf41afb 100644 --- a/test/providers/tst_manifests/pyproject/uv_workspace/packages/sub-pkg/expected_component_sbom.json +++ b/test/providers/tst_manifests/pyproject/uv_workspace/packages/sub-pkg/expected_component_sbom.json @@ -1,36 +1,42 @@ { - "bomFormat": "CycloneDX", - "specVersion": "1.4", - "version": 1, - "metadata": { - "timestamp": "2023-10-01T00:00:00.000Z", - "component": { - "name": "sub-pkg", - "version": "0.1.0", - "purl": "pkg:pypi/sub-pkg@0.1.0", - "type": "application", - "bom-ref": "pkg:pypi/sub-pkg@0.1.0" - } - }, - "components": [ - { - "name": "requests", - "version": "2.33.1", - "purl": "pkg:pypi/requests@2.33.1", - "type": "library", - "bom-ref": "pkg:pypi/requests@2.33.1" - } - ], - "dependencies": [ - { - "ref": "pkg:pypi/sub-pkg@0.1.0", - "dependsOn": [ - "pkg:pypi/requests@2.33.1" - ] - }, - { - "ref": "pkg:pypi/requests@2.33.1", - "dependsOn": [] - } - ] + "bomFormat": "CycloneDX", + "specVersion": "1.4", + "version": 1, + "metadata": { + "timestamp": "2023-10-01T00:00:00.000Z", + "component": { + "name": "sub-pkg", + "version": "0.1.0", + "purl": "pkg:pypi/sub-pkg@0.1.0", + "type": "application", + "bom-ref": "pkg:pypi/sub-pkg@0.1.0" + } + }, + "components": [ + { + "name": "requests", + "version": "2.33.1", + "purl": "pkg:pypi/requests@2.33.1", + "type": "library", + "bom-ref": "pkg:pypi/requests@2.33.1", + "hashes": [ + { + "alg": "SHA-256", + "content": "18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517" + } + ] + } + ], + "dependencies": [ + { + "ref": "pkg:pypi/sub-pkg@0.1.0", + "dependsOn": [ + "pkg:pypi/requests@2.33.1" + ] + }, + { + "ref": "pkg:pypi/requests@2.33.1", + "dependsOn": [] + } + ] } diff --git a/test/providers/tst_manifests/pyproject/uv_workspace/packages/sub-pkg/expected_stack_sbom.json b/test/providers/tst_manifests/pyproject/uv_workspace/packages/sub-pkg/expected_stack_sbom.json index 62e86b30..0a2f760e 100644 --- a/test/providers/tst_manifests/pyproject/uv_workspace/packages/sub-pkg/expected_stack_sbom.json +++ b/test/providers/tst_manifests/pyproject/uv_workspace/packages/sub-pkg/expected_stack_sbom.json @@ -1,85 +1,115 @@ { - "bomFormat": "CycloneDX", - "specVersion": "1.4", - "version": 1, - "metadata": { - "timestamp": "2023-10-01T00:00:00.000Z", - "component": { - "name": "sub-pkg", - "version": "0.1.0", - "purl": "pkg:pypi/sub-pkg@0.1.0", - "type": "application", - "bom-ref": "pkg:pypi/sub-pkg@0.1.0" - } - }, - "components": [ - { - "name": "requests", - "version": "2.33.1", - "purl": "pkg:pypi/requests@2.33.1", - "type": "library", - "bom-ref": "pkg:pypi/requests@2.33.1" - }, - { - "name": "certifi", - "version": "2026.2.25", - "purl": "pkg:pypi/certifi@2026.2.25", - "type": "library", - "bom-ref": "pkg:pypi/certifi@2026.2.25" - }, - { - "name": "charset-normalizer", - "version": "3.4.7", - "purl": "pkg:pypi/charset-normalizer@3.4.7", - "type": "library", - "bom-ref": "pkg:pypi/charset-normalizer@3.4.7" - }, - { - "name": "idna", - "version": "3.11", - "purl": "pkg:pypi/idna@3.11", - "type": "library", - "bom-ref": "pkg:pypi/idna@3.11" - }, - { - "name": "urllib3", - "version": "2.6.3", - "purl": "pkg:pypi/urllib3@2.6.3", - "type": "library", - "bom-ref": "pkg:pypi/urllib3@2.6.3" - } - ], - "dependencies": [ - { - "ref": "pkg:pypi/sub-pkg@0.1.0", - "dependsOn": [ - "pkg:pypi/requests@2.33.1" - ] - }, - { - "ref": "pkg:pypi/requests@2.33.1", - "dependsOn": [ - "pkg:pypi/certifi@2026.2.25", - "pkg:pypi/charset-normalizer@3.4.7", - "pkg:pypi/idna@3.11", - "pkg:pypi/urllib3@2.6.3" - ] - }, - { - "ref": "pkg:pypi/certifi@2026.2.25", - "dependsOn": [] - }, - { - "ref": "pkg:pypi/charset-normalizer@3.4.7", - "dependsOn": [] - }, - { - "ref": "pkg:pypi/idna@3.11", - "dependsOn": [] - }, - { - "ref": "pkg:pypi/urllib3@2.6.3", - "dependsOn": [] - } - ] + "bomFormat": "CycloneDX", + "specVersion": "1.4", + "version": 1, + "metadata": { + "timestamp": "2023-10-01T00:00:00.000Z", + "component": { + "name": "sub-pkg", + "version": "0.1.0", + "purl": "pkg:pypi/sub-pkg@0.1.0", + "type": "application", + "bom-ref": "pkg:pypi/sub-pkg@0.1.0" + } + }, + "components": [ + { + "name": "requests", + "version": "2.33.1", + "purl": "pkg:pypi/requests@2.33.1", + "type": "library", + "bom-ref": "pkg:pypi/requests@2.33.1", + "hashes": [ + { + "alg": "SHA-256", + "content": "18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517" + } + ] + }, + { + "name": "certifi", + "version": "2026.2.25", + "purl": "pkg:pypi/certifi@2026.2.25", + "type": "library", + "bom-ref": "pkg:pypi/certifi@2026.2.25", + "hashes": [ + { + "alg": "SHA-256", + "content": "e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7" + } + ] + }, + { + "name": "charset-normalizer", + "version": "3.4.7", + "purl": "pkg:pypi/charset-normalizer@3.4.7", + "type": "library", + "bom-ref": "pkg:pypi/charset-normalizer@3.4.7", + "hashes": [ + { + "alg": "SHA-256", + "content": "ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5" + } + ] + }, + { + "name": "idna", + "version": "3.11", + "purl": "pkg:pypi/idna@3.11", + "type": "library", + "bom-ref": "pkg:pypi/idna@3.11", + "hashes": [ + { + "alg": "SHA-256", + "content": "795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902" + } + ] + }, + { + "name": "urllib3", + "version": "2.6.3", + "purl": "pkg:pypi/urllib3@2.6.3", + "type": "library", + "bom-ref": "pkg:pypi/urllib3@2.6.3", + "hashes": [ + { + "alg": "SHA-256", + "content": "1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed" + } + ] + } + ], + "dependencies": [ + { + "ref": "pkg:pypi/sub-pkg@0.1.0", + "dependsOn": [ + "pkg:pypi/requests@2.33.1" + ] + }, + { + "ref": "pkg:pypi/requests@2.33.1", + "dependsOn": [ + "pkg:pypi/certifi@2026.2.25", + "pkg:pypi/charset-normalizer@3.4.7", + "pkg:pypi/idna@3.11", + "pkg:pypi/urllib3@2.6.3" + ] + }, + { + "ref": "pkg:pypi/certifi@2026.2.25", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/charset-normalizer@3.4.7", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/idna@3.11", + "dependsOn": [] + }, + { + "ref": "pkg:pypi/urllib3@2.6.3", + "dependsOn": [] + } + ] }