diff options
| author | Joshua Watt <JPEWhacker@gmail.com> | 2021-09-01 08:44:45 -0500 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2021-09-03 09:53:28 +0100 |
| commit | 0b871c57b8c3e45fd64d10037a32033d4a347d67 (patch) | |
| tree | 9860f64e2453bc409bcf83f0e01c14f87d0e2817 | |
| parent | 69faca3df61409927c312e6f060faee945de0373 (diff) | |
| download | poky-0b871c57b8c3e45fd64d10037a32033d4a347d67.tar.gz | |
classes/create-spdx: Add runtime dependency mapping
(From OE-Core rev: 82f3229bce41dc101c79865033432161dac269d8)
Signed-off-by: Joshua Watt <JPEWhacker@gmail.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
| -rw-r--r-- | meta/classes/create-spdx.bbclass | 179 | ||||
| -rw-r--r-- | meta/lib/oe/sbom.py | 5 |
2 files changed, 181 insertions, 3 deletions
diff --git a/meta/classes/create-spdx.bbclass b/meta/classes/create-spdx.bbclass index 14caae8a50..28a2e64f52 100644 --- a/meta/classes/create-spdx.bbclass +++ b/meta/classes/create-spdx.bbclass | |||
| @@ -13,6 +13,8 @@ SPDXDIR ??= "${WORKDIR}/spdx" | |||
| 13 | SPDXDEPLOY = "${SPDXDIR}/deploy" | 13 | SPDXDEPLOY = "${SPDXDIR}/deploy" |
| 14 | SPDXWORK = "${SPDXDIR}/work" | 14 | SPDXWORK = "${SPDXDIR}/work" |
| 15 | 15 | ||
| 16 | SPDXRUNTIMEDEPLOY = "${SPDXDIR}/runtime-deploy" | ||
| 17 | |||
| 16 | SPDX_INCLUDE_SOURCES ??= "0" | 18 | SPDX_INCLUDE_SOURCES ??= "0" |
| 17 | SPDX_INCLUDE_PACKAGED ??= "0" | 19 | SPDX_INCLUDE_PACKAGED ??= "0" |
| 18 | SPDX_ARCHIVE_SOURCES ??= "0" | 20 | SPDX_ARCHIVE_SOURCES ??= "0" |
| @@ -486,6 +488,163 @@ do_create_spdx[cleandirs] = "${SPDXDEPLOY} ${SPDXWORK}" | |||
| 486 | do_create_spdx[depends] += "${PATCHDEPENDENCY}" | 488 | do_create_spdx[depends] += "${PATCHDEPENDENCY}" |
| 487 | do_create_spdx[deptask] = "do_create_spdx" | 489 | do_create_spdx[deptask] = "do_create_spdx" |
| 488 | 490 | ||
| 491 | def collect_package_providers(d): | ||
| 492 | from pathlib import Path | ||
| 493 | import oe.sbom | ||
| 494 | import oe.spdx | ||
| 495 | import json | ||
| 496 | |||
| 497 | deploy_dir_spdx = Path(d.getVar("DEPLOY_DIR_SPDX")) | ||
| 498 | |||
| 499 | providers = {} | ||
| 500 | |||
| 501 | taskdepdata = d.getVar("BB_TASKDEPDATA", False) | ||
| 502 | deps = sorted(set( | ||
| 503 | dep[0] for dep in taskdepdata.values() if | ||
| 504 | dep[1] == "do_create_spdx" and dep[0] != d.getVar("PN") | ||
| 505 | )) | ||
| 506 | deps.append(d.getVar("PN")) | ||
| 507 | |||
| 508 | for dep_pn in deps: | ||
| 509 | recipe_data = oe.packagedata.read_pkgdata(dep_pn, d) | ||
| 510 | |||
| 511 | for pkg in recipe_data.get("PACKAGES", "").split(): | ||
| 512 | |||
| 513 | pkg_data = oe.packagedata.read_subpkgdata_dict(pkg, d) | ||
| 514 | rprovides = set(n for n, _ in bb.utils.explode_dep_versions2(pkg_data.get("RPROVIDES", "")).items()) | ||
| 515 | rprovides.add(pkg) | ||
| 516 | |||
| 517 | for r in rprovides: | ||
| 518 | providers[r] = pkg | ||
| 519 | |||
| 520 | return providers | ||
| 521 | |||
| 522 | collect_package_providers[vardepsexclude] += "BB_TASKDEPDATA" | ||
| 523 | |||
| 524 | python do_create_runtime_spdx() { | ||
| 525 | from datetime import datetime, timezone | ||
| 526 | import oe.sbom | ||
| 527 | import oe.spdx | ||
| 528 | import oe.packagedata | ||
| 529 | from pathlib import Path | ||
| 530 | |||
| 531 | deploy_dir_spdx = Path(d.getVar("DEPLOY_DIR_SPDX")) | ||
| 532 | spdx_deploy = Path(d.getVar("SPDXRUNTIMEDEPLOY")) | ||
| 533 | |||
| 534 | creation_time = datetime.now(tz=timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") | ||
| 535 | |||
| 536 | providers = collect_package_providers(d) | ||
| 537 | |||
| 538 | bb.build.exec_func("read_subpackage_metadata", d) | ||
| 539 | |||
| 540 | dep_package_cache = {} | ||
| 541 | |||
| 542 | pkgdest = Path(d.getVar("PKGDEST")) | ||
| 543 | for package in d.getVar("PACKAGES").split(): | ||
| 544 | localdata = bb.data.createCopy(d) | ||
| 545 | pkg_name = d.getVar("PKG:%s" % package) or package | ||
| 546 | localdata.setVar("PKG", pkg_name) | ||
| 547 | localdata.setVar('OVERRIDES', d.getVar("OVERRIDES", False) + ":" + package) | ||
| 548 | |||
| 549 | if not oe.packagedata.packaged(package, localdata): | ||
| 550 | continue | ||
| 551 | |||
| 552 | pkg_spdx_path = deploy_dir_spdx / "packages" / (pkg_name + ".spdx.json") | ||
| 553 | |||
| 554 | package_doc, package_doc_sha1 = oe.sbom.read_doc(pkg_spdx_path) | ||
| 555 | |||
| 556 | for p in package_doc.packages: | ||
| 557 | if p.name == pkg_name: | ||
| 558 | spdx_package = p | ||
| 559 | break | ||
| 560 | else: | ||
| 561 | bb.fatal("Package '%s' not found in %s" % (pkg_name, pkg_spdx_path)) | ||
| 562 | |||
| 563 | runtime_doc = oe.spdx.SPDXDocument() | ||
| 564 | runtime_doc.name = "runtime-" + pkg_name | ||
| 565 | runtime_doc.documentNamespace = get_doc_namespace(localdata, runtime_doc) | ||
| 566 | runtime_doc.creationInfo.created = creation_time | ||
| 567 | runtime_doc.creationInfo.comment = "This document was created by analyzing package runtime dependencies." | ||
| 568 | runtime_doc.creationInfo.creators.append("Tool: OpenEmbedded Core create-spdx.bbclass") | ||
| 569 | runtime_doc.creationInfo.creators.append("Organization: OpenEmbedded ()") | ||
| 570 | runtime_doc.creationInfo.creators.append("Person: N/A ()") | ||
| 571 | |||
| 572 | package_ref = oe.spdx.SPDXExternalDocumentRef() | ||
| 573 | package_ref.externalDocumentId = "DocumentRef-package" | ||
| 574 | package_ref.spdxDocument = package_doc.documentNamespace | ||
| 575 | package_ref.checksum.algorithm = "SHA1" | ||
| 576 | package_ref.checksum.checksumValue = package_doc_sha1 | ||
| 577 | |||
| 578 | runtime_doc.externalDocumentRefs.append(package_ref) | ||
| 579 | |||
| 580 | runtime_doc.add_relationship( | ||
| 581 | runtime_doc.SPDXID, | ||
| 582 | "AMENDS", | ||
| 583 | "%s:%s" % (package_ref.externalDocumentId, package_doc.SPDXID) | ||
| 584 | ) | ||
| 585 | |||
| 586 | deps = bb.utils.explode_dep_versions2(localdata.getVar("RDEPENDS") or "") | ||
| 587 | seen_deps = set() | ||
| 588 | for dep, _ in deps.items(): | ||
| 589 | if dep in seen_deps: | ||
| 590 | continue | ||
| 591 | |||
| 592 | dep = providers[dep] | ||
| 593 | |||
| 594 | if not oe.packagedata.packaged(dep, localdata): | ||
| 595 | continue | ||
| 596 | |||
| 597 | dep_pkg_data = oe.packagedata.read_subpkgdata_dict(dep, d) | ||
| 598 | dep_pkg = dep_pkg_data["PKG"] | ||
| 599 | |||
| 600 | if dep in dep_package_cache: | ||
| 601 | (dep_spdx_package, dep_package_ref) = dep_package_cache[dep] | ||
| 602 | else: | ||
| 603 | dep_path = deploy_dir_spdx / "packages" / ("%s.spdx.json" % dep_pkg) | ||
| 604 | |||
| 605 | spdx_dep_doc, spdx_dep_sha1 = oe.sbom.read_doc(dep_path) | ||
| 606 | |||
| 607 | for pkg in spdx_dep_doc.packages: | ||
| 608 | if pkg.name == dep_pkg: | ||
| 609 | dep_spdx_package = pkg | ||
| 610 | break | ||
| 611 | else: | ||
| 612 | bb.fatal("Package '%s' not found in %s" % (dep_pkg, dep_path)) | ||
| 613 | |||
| 614 | dep_package_ref = oe.spdx.SPDXExternalDocumentRef() | ||
| 615 | dep_package_ref.externalDocumentId = "DocumentRef-runtime-dependency-" + spdx_dep_doc.name | ||
| 616 | dep_package_ref.spdxDocument = spdx_dep_doc.documentNamespace | ||
| 617 | dep_package_ref.checksum.algorithm = "SHA1" | ||
| 618 | dep_package_ref.checksum.checksumValue = spdx_dep_sha1 | ||
| 619 | |||
| 620 | dep_package_cache[dep] = (dep_spdx_package, dep_package_ref) | ||
| 621 | |||
| 622 | runtime_doc.externalDocumentRefs.append(dep_package_ref) | ||
| 623 | |||
| 624 | runtime_doc.add_relationship( | ||
| 625 | "%s:%s" % (dep_package_ref.externalDocumentId, dep_spdx_package.SPDXID), | ||
| 626 | "RUNTIME_DEPENDENCY_OF", | ||
| 627 | "%s:%s" % (package_ref.externalDocumentId, spdx_package.SPDXID) | ||
| 628 | ) | ||
| 629 | seen_deps.add(dep) | ||
| 630 | |||
| 631 | oe.sbom.write_doc(d, runtime_doc, "runtime", spdx_deploy) | ||
| 632 | } | ||
| 633 | |||
| 634 | addtask do_create_runtime_spdx after do_create_spdx before do_build do_rm_work | ||
| 635 | SSTATETASKS += "do_create_runtime_spdx" | ||
| 636 | do_create_runtime_spdx[sstate-inputdirs] = "${SPDXRUNTIMEDEPLOY}" | ||
| 637 | do_create_runtime_spdx[sstate-outputdirs] = "${DEPLOY_DIR_SPDX}" | ||
| 638 | |||
| 639 | python do_create_runtime_spdx_setscene () { | ||
| 640 | sstate_setscene(d) | ||
| 641 | } | ||
| 642 | addtask do_create_runtime_spdx_setscene | ||
| 643 | |||
| 644 | do_create_runtime_spdx[dirs] = "${SPDXRUNTIMEDEPLOY}" | ||
| 645 | do_create_runtime_spdx[cleandirs] = "${SPDXRUNTIMEDEPLOY}" | ||
| 646 | do_create_runtime_spdx[rdeptask] = "do_create_spdx" | ||
| 647 | |||
| 489 | def spdx_get_src(d): | 648 | def spdx_get_src(d): |
| 490 | """ | 649 | """ |
| 491 | save patched source of the recipe in SPDX_WORKDIR. | 650 | save patched source of the recipe in SPDX_WORKDIR. |
| @@ -537,7 +696,7 @@ def spdx_get_src(d): | |||
| 537 | finally: | 696 | finally: |
| 538 | d.setVar("WORKDIR", workdir) | 697 | d.setVar("WORKDIR", workdir) |
| 539 | 698 | ||
| 540 | do_rootfs[recrdeptask] += "do_create_spdx" | 699 | do_rootfs[recrdeptask] += "do_create_spdx do_create_runtime_spdx" |
| 541 | 700 | ||
| 542 | ROOTFS_POSTUNINSTALL_COMMAND =+ "image_combine_spdx ; " | 701 | ROOTFS_POSTUNINSTALL_COMMAND =+ "image_combine_spdx ; " |
| 543 | python image_combine_spdx() { | 702 | python image_combine_spdx() { |
| @@ -598,6 +757,24 @@ python image_combine_spdx() { | |||
| 598 | else: | 757 | else: |
| 599 | bb.fatal("Unable to find package with name '%s' in SPDX file %s" % (name, pkg_spdx_path)) | 758 | bb.fatal("Unable to find package with name '%s' in SPDX file %s" % (name, pkg_spdx_path)) |
| 600 | 759 | ||
| 760 | runtime_spdx_path = deploy_dir_spdx / "runtime" / ("runtime-" + name + ".spdx.json") | ||
| 761 | runtime_doc, runtime_doc_sha1 = oe.sbom.read_doc(runtime_spdx_path) | ||
| 762 | |||
| 763 | runtime_ref = oe.spdx.SPDXExternalDocumentRef() | ||
| 764 | runtime_ref.externalDocumentId = "DocumentRef-%s" % runtime_doc.name | ||
| 765 | runtime_ref.spdxDocument = runtime_doc.documentNamespace | ||
| 766 | runtime_ref.checksum.algorithm = "SHA1" | ||
| 767 | runtime_ref.checksum.checksumValue = runtime_doc_sha1 | ||
| 768 | |||
| 769 | # "OTHER" isn't ideal here, but I can't find a relationship that makes sense | ||
| 770 | doc.externalDocumentRefs.append(runtime_ref) | ||
| 771 | doc.add_relationship( | ||
| 772 | image, | ||
| 773 | "OTHER", | ||
| 774 | "%s:%s" % (runtime_ref.externalDocumentId, runtime_doc.SPDXID), | ||
| 775 | comment="Runtime dependencies for %s" % name | ||
| 776 | ) | ||
| 777 | |||
| 601 | image_spdx_path = imgdeploydir / (image_name + ".spdx.json") | 778 | image_spdx_path = imgdeploydir / (image_name + ".spdx.json") |
| 602 | 779 | ||
| 603 | with image_spdx_path.open("wb") as f: | 780 | with image_spdx_path.open("wb") as f: |
diff --git a/meta/lib/oe/sbom.py b/meta/lib/oe/sbom.py index 294feee10b..848812c0b7 100644 --- a/meta/lib/oe/sbom.py +++ b/meta/lib/oe/sbom.py | |||
| @@ -28,10 +28,11 @@ def get_image_spdxid(img): | |||
| 28 | return "SPDXRef-Image-%s" % img | 28 | return "SPDXRef-Image-%s" % img |
| 29 | 29 | ||
| 30 | 30 | ||
| 31 | def write_doc(d, spdx_doc, subdir): | 31 | def write_doc(d, spdx_doc, subdir, spdx_deploy=None): |
| 32 | from pathlib import Path | 32 | from pathlib import Path |
| 33 | 33 | ||
| 34 | spdx_deploy = Path(d.getVar("SPDXDEPLOY")) | 34 | if spdx_deploy is None: |
| 35 | spdx_deploy = Path(d.getVar("SPDXDEPLOY")) | ||
| 35 | 36 | ||
| 36 | dest = spdx_deploy / subdir / (spdx_doc.name + ".spdx.json") | 37 | dest = spdx_deploy / subdir / (spdx_doc.name + ".spdx.json") |
| 37 | dest.parent.mkdir(exist_ok=True, parents=True) | 38 | dest.parent.mkdir(exist_ok=True, parents=True) |
