File: check_licensing_bom

package info (click to toggle)
sbom-toolkit 0.0.20260112
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 128 kB
  • sloc: perl: 599; python: 451; makefile: 13
file content (130 lines) | stat: -rwxr-xr-x 4,142 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/usr/bin/python3

# SPDX-License-Identifier: MPL-2.0
# SPDX-FileCopyrightText: 2021-2025 Collabora Ltd.
# SPDX-FileCopyrightText: 2021-2025 Walter Lozano <walter.lozano@collabora.com>
# SPDX-FileCopyrightText: 2025 Dylan Aïssi <dylan.aissi@collabora.com>

import argparse
import json
import os
import sys

VERBOSE_IMAGE = 0
VERBOSE_PACKAGE = 1
VERBOSE_BINARY = 2
VERBOSE_SOURCE = 3

ERROR_NONE = 0
ERROR_ERROR = 1
ERROR_WARN = 2

PROBLEMATIC_LICENSES_ERRORS = []
PROBLEMATIC_LICENSES_WARNS = ["UNKNOWN", "", "NoInfoFound", "no-info-found"]


class BomChecker:
    def __init__(
        self, bom_file, verbose, error_level=ERROR_NONE, whitelisted_packages=""
    ):
        self.bom_file = bom_file
        self.verbose = verbose
        self.error_level = error_level
        self.error = False
        self.whitelisted_packages = whitelisted_packages

    def check_licenses(
        self, licenses, source_type="image", source_name="", whitelisted=False
    ):
        licenses = set(licenses)
        license_errors = licenses.intersection(PROBLEMATIC_LICENSES_ERRORS)
        license_warnings = licenses.intersection(PROBLEMATIC_LICENSES_WARNS)
        if license_errors:
            if self.error_level >= ERROR_ERROR and not whitelisted:
                self.error = True
            license_errors = " ".join(license_errors)
            print(
                f"ERROR on {source_type} {source_name} license {license_errors} found, whitelisted {whitelisted}"
            )
        if license_warnings:
            if self.error_level >= ERROR_WARN:
                self.error = True
            license_warnings = " ".join(license_warnings)
            print(
                f"WARNING on {source_type} {source_name} license {license_warnings} found, whitelisted {whitelisted}"
            )

    def get_whitelisted_packages(self):
        whitelisted_packages = []
        if not os.path.isfile(self.whitelisted_packages):
            return whitelisted_packages
        with open(self.whitelisted_packages) as wp:
            for line in wp.readlines():
                if line.startswith("#"):
                    continue
                whitelisted_packages.append(line.strip())

        return whitelisted_packages

    def check_bom(self):
        bom = json.load(self.bom_file)
        whitelisted_packages = self.get_whitelisted_packages()

        if (
            len(whitelisted_packages) == 0
            or "packages" not in bom
            or "packages" in bom
            and len(bom["packages"]) == 0
        ):
            self.check_licenses(bom["license"])

        if self.verbose >= VERBOSE_PACKAGE and "packages" in bom:
            for p in bom["packages"]:
                whitelisted = p["name"] in whitelisted_packages
                self.check_licenses(p["license"], "package", p["name"], whitelisted)

                if self.verbose >= VERBOSE_BINARY and "binaries" in p:
                    for b in p["binaries"]:
                        self.check_licenses(
                            b["license"], "binary", b["name"], whitelisted
                        )


def main(argv):
    parser = argparse.ArgumentParser()
    parser.add_argument("bom_file", type=open, help="BOM file to check")
    parser.add_argument(
        "-e",
        "--error-level",
        type=int,
        default=ERROR_NONE,
        help="type of error that triggers a return code unsuccessful 0: none , 1: error, 2: warning",
    )
    parser.add_argument(
        "-w",
        "--whitelisted-packages",
        default="",
        help="file containing a list of whitelisted packages",
    )
    parser.add_argument(
        "-v",
        "--verbose",
        type=int,
        default=VERBOSE_IMAGE,
        help="verbose use in output 0: image, 1: package, 2: binary, 3: source",
    )

    args = parser.parse_args()

    bom_checker = BomChecker(
        args.bom_file, args.verbose, args.error_level, args.whitelisted_packages
    )
    bom_checker.check_bom()

    if bom_checker.error:
        print("BOM check has failed", file=sys.stderr)
        sys.exit(1)


if __name__ == "__main__":
    main(sys.argv[1:])