anthonyharrison/lib4sbom

GitHub: anthonyharrison/lib4sbom

lib4sbom 是一个用于解析、生成和验证 SPDX 与 CycloneDX 格式软件物料清单的 Python 库,提供统一的 SBOM 数据抽象层。

Stars: 39 | Forks: 19

# Lib4SBOM Lib4SBOM 是一个用于解析和生成软件物料清单 (SBOM) 的库。它支持以 [SPDX](https://www.spdx.org) 和 [CycloneDX](https://www.cyclonedx.org) 格式创建的 SBOM。 它的开发基于这样一个假设:无论底层格式如何,拥有一个通用的 SBOM 抽象对开发者来说将是有用的。 提供以下功能: - 生成 TagValue、JSON 和 YAML 格式的 SPDX SBOM - 生成 JSON 格式的 CycloneDX SBOM - 解析 TagValue、JSON、YAML、XML 和 RDF 格式的 SPDX SBOM - 验证 JSON 和 XML 格式的 CycloneDX SBOM - 验证 TagValue、JSON、YAML、XML 和 RDF 格式的 SPDX SBOM - 解析 JSON 和 XML 格式的 CycloneDX SBOM - 创建和操作 SBOM 文件对象 - 创建和操作 SBOM 包对象 - 创建和操作 SBOM 依赖关系对象 - 创建和操作漏洞对象 - 创建和操作软件服务对象 - 创建和操作加密对象 - 生成的 SBOM 可以输出到文件或控制台 - 解析嵌入在 Intoto 证明中的 SBOM - 解析嵌入在 Protobom 对象中的 SPDX 或 CycloneDX SBOM ## 安装 使用以下命令进行安装: `pip install lib4sbom` 或者,直接克隆仓库并使用以下命令安装依赖项: `pip install -U -r requirements.txt` 该工具需要较新版本的 Python 3 (3.9+)。建议使用 Python 虚拟环境,特别 是如果您正在使用不同版本的 python。`virtualenv` 是一个用于设置虚拟 Python 环境的工具, 它允许您在单个环境中设置该工具的所有依赖项,或者设置不同的环境以便 使用不同版本的 Python 进行测试。 ## API ### SBOMParser SBOMParser 模块提供了解析 SPDX 或 CycloneDX 格式 SBOM 的方法,并 返回 SBOM 中的文件、包和关系信息。 实现的重点是无论 SBOM 格式如何,都提供一组通用的 SBOM 数据。 支持以下格式和版本的 SBOM | SBOM Type | Version | Format | | --------- |---------|----------| | SPDX | 2.2 | TagValue | | SPDX | 2.2 | JSON | | SPDX | 2.2 | YAML | | SPDX | 2.2 | RDF | | SPDX | 2.2 | XML | | SPDX | 2.3 | TagValue | | SPDX | 2.3 | JSON | | SPDX | 2.3 | YAML | | SPDX | 2.3 | RDF | | SPDX | 2.3 | XML | | SPDX | 3.0 | JSON-LD | | CycloneDX | 1.4 | JSON | | CycloneDX | 1.4 | XML | | CycloneDX | 1.5 | JSON | | CycloneDX | 1.5 | XML | | CycloneDX | 1.6 | JSON | | CycloneDX | 1.6 | XML | | CycloneDX | 1.7 | JSON | | CycloneDX | 1.7 | XML | **注意**,对 SPDX RDF 和 XML 格式的支持仅限于少数包属性。 **注意**,解析作为 [In-Toto](https://in-toto.io/) 语句嵌入的 SBOM 的支持仅适用于 SPDX 文档。 _class_ **SBOMParser**(_sbom_type='auto_') 这将创建一个简单的 SBOM 解析器对象。可以指定一个可选参数 _sbom_type_, 它表示 SBOM 的类型(spdx、cyclonedx 或 auto)。默认值为 auto,在这种 情况下,解析器将使用以下文件名约定自动识别 SBOM 类型。 | SBOM | Format | Filename extension | | --------- |----------|--------------------| | SPDX | TagValue | .spdx | | SPDX | JSON | .spdx.json | | SPDX | JSON-LD | .json | | SPDX | YAML | .spdx.yaml | | SPDX | YAML | .spdx.yml | | SPDX | RDF | .spdx.rdf | | SPDX | XML | .spdx.xml | | CycloneDX | JSON | .json | | CycloneDX | JSON | .cdx.json | | CycloneDX | JSON | .bom.json | | CycloneDX | XML | .xml | | CycloneDX | XML | .cdx.xml | | CycloneDX | XML | .bom..xml | 解析器将检查是否由正确的解析器处理了正确的 JSON 文件。 提交给 CycloneDX 解析器的 SPDX JSON 文件将导致没有数据被处理。 解析过程中的错误将导致引发 SBOMParserException 异常。 **方法** parse_file(filename) 解析 SBOM 文件。如果文件不存在,则引发 FileNotFoundError 异常。 如果在解析文件过程中发生错误,则引发 SBOMParserException 异常。 parse_string(sbom_string) 从 sbom_string 解析 SBOM 内容。 如果在解析文件过程中发生错误,则引发 SBOMParserException 异常。 get_files() 从解析的 SBOM 中返回文件元素列表 get_packages() 从解析的 SBOM 中返回包元素列表 get_relationships() 从解析的 SBOM 中返回关系元素 get_vulnerabilities() 从解析的 SBOM 中返回漏洞元素 get_services() 从解析的 SBOM 中返回软件服务元素 get_type() 返回 SBOM 的类型(spdx 或 cyclonedx) **示例** 以下示例中使用了一个测试 SBOM 文件 (test_sbom.spdx)。 ``` SPDXVersion: SPDX-2.2 DataLicense: CC0-1.0 SPDXID: SPDXRef-DOCUMENT DocumentName: virtualenv DocumentNamespace: http://spdx.org/spdxdocs/virtualenv-b7ac9cce-efe8-4fe7-a544-100e6a5664e6 LicenseListVersion: 3.18 Creator: Tool: sbom4python-0.4.0 Created: 2022-11-16T10:14:26Z CreatorComment: This document has been automatically generated. ##### PackageName: virtualenv SPDXID: SPDXRef-Package-1-virtualenv PackageSupplier: Person: Bernat_Gabor PackageVersion: 20.16.7 PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageLicenseConcluded: MIT PackageLicenseDeclared: MIT PackageCopyrightText: NOASSERTION ExternalRef: PACKAGE-MANAGER purl pkg:pypi/virtualenv@20.16.7 ##### PackageName: distlib SPDXID: SPDXRef-Package-2-distlib PackageSupplier: Person: Vinay_Sajip PackageVersion: 0.3.6 PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION ExternalRef: PACKAGE-MANAGER purl pkg:pypi/distlib@0.3.6 ##### PackageName: filelock SPDXID: SPDXRef-Package-3-filelock PackageSupplier: Person: Benedikt_Schmitt PackageVersion: 3.8.0 PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageLicenseConcluded: Unlicense PackageLicenseDeclared: Unlicense PackageCopyrightText: NOASSERTION ExternalRef: PACKAGE-MANAGER purl pkg:pypi/filelock@3.8.0 ##### PackageName: platformdirs SPDXID: SPDXRef-Package-4-platformdirs PackageSupplier: NOASSERTION PackageVersion: 2.5.4 PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION ExternalRef: PACKAGE-MANAGER purl pkg:pypi/platformdirs@2.5.4 Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-1-virtualenv Relationship: SPDXRef-Package-1-virtualenv CONTAINS SPDXRef-Package-2-distlib Relationship: SPDXRef-Package-1-virtualenv CONTAINS SPDXRef-Package-3-filelock Relationship: SPDXRef-Package-1-virtualenv CONTAINS SPDXRef-Package-4-platformdirs ``` 以下代码示例展示了 SBOMParser 模块的使用。 ``` >>> from lib4sbom.parser import SBOMParser >>> test_parser = SBOMParser() >>> print (f"SBOM type {test_parser.get_type()}") SBOM type auto >>> test_parser.parse_file("test_sbom.spdx") >>> print (f"SBOM type {test_parser.get_type()}") SBOM type spdx >>> sbom_files = test_parser.get_files() >>> print (sbom_files) [] >>> sbom_packages = test_parser.get_packages() >>> print (sbom_packages) [{'name': 'virtualenv', 'type': 'library', 'id': 'SPDXRef-Package-1-virtualenv', 'supplier_type': 'Person', 'supplier': 'Bernat_Gabor', 'version': '20.16.7', 'downloadlocation': 'NOASSERTION', 'filesanalysis': 'false', 'licenseconcluded': 'MIT', 'licensedeclared': 'MIT', 'externalreference': [['PACKAGE-MANAGER', 'purl', 'pkg:pypi/virtualenv@20.16.7']]}, {'name': 'distlib', 'type': 'library', 'id': 'SPDXRef-Package-2-distlib', 'supplier_type': 'Person', 'supplier': 'Vinay_Sajip', 'version': '0.3.6', 'downloadlocation': 'NOASSERTION', 'filesanalysis': 'false', 'licenseconcluded': 'NOASSERTION', 'licensedeclared': 'NOASSERTION', 'externalreference': [['PACKAGE-MANAGER', 'purl', 'pkg:pypi/distlib@0.3.6']]}, {'name': 'filelock', 'type': 'library', 'id': 'SPDXRef-Package-3-filelock', 'supplier_type': 'Person', 'supplier': 'Benedikt_Schmitt', 'version': '3.8.0', 'downloadlocation': 'NOASSERTION', 'filesanalysis': 'false', 'licenseconcluded': 'Unlicense', 'licensedeclared': 'Unlicense', 'externalreference': [['PACKAGE-MANAGER', 'purl', 'pkg:pypi/filelock@3.8.0']]}, {'name': 'platformdirs', 'type': 'library', 'id': 'SPDXRef-Package-4-platformdirs', 'supplier_type': 'Organization', 'supplier': 'Unknown', 'version': '2.5.4', 'downloadlocation': 'NOASSERTION', 'filesanalysis': 'false', 'licenseconcluded': 'NOASSERTION', 'licensedeclared': 'NOASSERTION', 'externalreference': [['PACKAGE-MANAGER', 'purl', 'pkg:pypi/platformdirs@2.5.4']]}] >>> print (len(sbom_packages)) 4 >>> sbom_packages[0] {'name': 'virtualenv', 'type': 'library', 'id': 'SPDXRef-Package-1-virtualenv', 'supplier_type': 'Person', 'supplier': 'Bernat_Gabor', 'version': '20.16.7', 'downloadlocation': 'NOASSERTION', 'filesanalysis': 'false', 'licenseconcluded': 'MIT', 'licensedeclared': 'MIT', 'externalreference': [['PACKAGE-MANAGER', 'purl', 'pkg:pypi/virtualenv@20.16.7']]} >>> sbom_relationships = test_parser.get_relationships() >>> print (sbom_relationships) [{'source': 'TestDocument', 'type': 'DESCRIBES', 'target': 'virtualenv', 'source_id': 'SPDXRef-DOCUMENT', 'target_id': 'SPDXRef-Package-1-virtualenv'}, {'source': 'virtualenv', 'type': 'CONTAINS', 'target': 'distlib', 'source_id': 'SPDXRef-Package-1-virtualenv', 'target_id': 'SPDXRef-Package-2-distlib'}, {'source': 'virtualenv', 'type': 'CONTAINS', 'target': 'filelock', 'source_id': 'SPDXRef-Package-1-virtualenv', 'target_id': 'SPDXRef-Package-3-filelock'}, {'source': 'virtualenv', 'type': 'CONTAINS', 'target': 'platformdirs', 'source_id': 'SPDXRef-Package-1-virtualenv', 'target_id': 'SPDXRef-Package-4-platformdirs'}] >>> sbom_relationships[2] {'source': 'virtualenv', 'type': 'CONTAINS', 'target': 'filelock', 'source_id': 'SPDXRef-Package-1-virtualenv', 'target_id': 'SPDXRef-Package-3-filelock'} >>> ``` _class_ **SBOMValidator**(_sbom_type='auto', version=None, debug=False_) 这将创建一个简单的 SBOM 验证器对象。 可以指定可选参数 _sbom_type_,它表示 SBOM 的类型(spdx、cyclonedx 或 auto)。默认值为 auto,在这种 情况下,解析器将使用以下文件名约定自动识别 SBOM 类型。 | SBOM | Format | Filename extension | | --------- |----------|--------------------| | SPDX | TagValue | .spdx | | SPDX | JSON | .spdx.json | | SPDX | JSON-LD | .json | | SPDX | YAML | .spdx.yaml | | SPDX | YAML | .spdx.yml | | SPDX | RDF | .spdx.rdf | | SPDX | XML | .spdx.xml | | CycloneDX | JSON | .json | | CycloneDX | JSON | .cdx.json | | CycloneDX | JSON | .bom.json | | CycloneDX | XML | .xml | | CycloneDX | XML | .cdx.xml | | CycloneDX | XML | .bom.xml | 可选参数 _version_ 可用于指定要验证的 SBOM 的单个版本,例如 "1.6"。 可选参数 _debug_ 可用于生成调试输出。 **注意** 要验证 3.0 版本格式的 SPDX SBOM,必须明确指定版本, **方法** validate_file(filename) 验证 SBOM 文件。如果文件不存在,则引发 FileNotFoundError 异常。 验证器将检查是否由正确的解析器处理了正确的 JSON 文件。 提交给 CycloneDX 解析器的 SPDX JSON 文件将导致没有数据被处理。 如果在验证文件过程中发生错误,则引发 SBOMValidatorException 异常。 返回值是一个表示 SBOM 类型 and 版本的字典。例如 {"SPDX" : 2.3}。 如果 SBOM 验证失败,返回值是 SBOM 类型和布尔值,例如 {"SPDX" : False}。 如果无法验证 SBOM,返回值是 SBOM 类型和 "Unknown",即 {"SPDX" : "Unknown"}。 验证规则: - SPDX JSON 和 YAML 文件的验证依据是 SPDX JSON schema。 - SPDX TagValue、RDF 和 XML 文件的验证仅仅是检测是否存在有效的 SDPX 规范版本。 - CycloneDX JSON 文件的验证依据是 CycloneDX JSON schema。 - CycloneDX XML 文件的验证依据是 CycloneDX XML schema。 ### SBOMGenerator SBOMGenerator 模块提供了以 SPDX 或 CycloneDX 格式生成 SBOM 的方法。 实现的重点是无论 SBOM 类型和格式如何,都提供单一接口。 可以生成以下格式的 SBOM | SBOM Type | Version | Format | | --------- |---------| ----------| | SPDX | 2.2 | Tag | | SPDX | 2.2 | JSON | | SPDX | 2.2 | YAML | | SPDX | 2.3 | Tag | | SPDX | 2.3 | JSON | | SPDX | 2.3 | YAML | | SPDX | 3.0 | JSON-LD | | CycloneDX | 1.4 | JSON | | CycloneDX | 1.5 | JSON | | CycloneDX | 1.6 | JSON | | CycloneDX | 1.7 | JSON | CycloneDX 的默认版本是 1.7。但是,可以通过将环境变量 LIB4SBOM_CYCLONEDX_VERSION 设置为 "1.4"、"1.5" 或 "1.6" 来覆盖该版本。 SPDX 的默认版本是 2.3。但是,可以通过将环境变量 LIB4SBOM_SPDX_VERSION 设置为 "SPDX-2.2" 来覆盖该版本。 **注意** 要生成 3.0 格式的 SPDX SBOM,必须设置环境变量 LIB4SBOM_SPDX3。 可以通过设置环境变量 SBOM_ORGANIZATION 来设置创建 SBOM 的组织。这可以通过在 SBOM 文档中设置 Metadata_Supplier 属性的值来覆盖。 _class_ **SBOMGenerator**(_validate_license: True, sbom_type="spdx", format="tag", application="lib4sbom", version="0.1"_) 这将创建一个简单的 SBOM 生成器对象。可以指定以下可选参数: _validate_license_ 指示是否根据 [SPDX license identifiers](https://spdx.org/licenses/) 集合验证许可证信息。此选项仅适用于 SPDX SBOM, 因为这对于 CycloneDX SBOM 是强制性的。 _sbom_type_ 指示要生成的 SBOM 的类型。有效选项为 spdx 或 cyclonedx。对 SPDX3 的支持目前处于实验阶段,但可以通过将 sbom_type 设置为 spdx3 来启用。 _format_ 指示要生成的 SBOM 的格式。有效选项为 Tag、JSON 或 YAML。如果指定了无效的格式, 则假设默认格式为 JSON。如果为 SBOM 类型指定了不支持的格式(例如 CycloneDX 的 Tag 或 YAML),则采用默认 格式(SPDX 为 Tag,CycloneDX 为 JSON)。 _application_ 和 _version_ 指定创建 SBOM 的工具的名称和版本。如果未指定,则应用程序名称为 'lib4sbom',版本为 '0.1'。 **方法** _generate(project_name, sbom_data, filename = "", send_to_output = True)_ 该方法生成 SBOM 文件。参数为 _project_name_ 指定项目的名称 _sbom_data_ 包含要用于生成的 SBOM 数据。它包含要包含在 SBOM 中的包、文件和关系的详细信息。 _filename_ 是要生成的文件的名称。默认情况下,输出将生成到控制台。 _send_to_output_ 指示是否将输出发送到文件名。 get_sbom() 以请求的格式返回生成的 SBOM get_type() 返回生成的 SBOM 的类型(spdx 或 cyclonedx) get_format() 返回生成的 SBOM 的格式(tag、json 或 yaml 之一) **示例** 以下代码示例展示了 SBOMGenerator 模块的使用, 将 SBOM 从 Tag Value 格式转换为 YAML 格式。输出发送到控制台。 ``` >>> from lib4sbom.parser import SBOMParser >>> test_parser = SBOMParser() >>> test_parser.parse_file("test_sbom.spdx") >>> from lib4sbom.generator import SBOMGenerator >>> test_generator = SBOMGenerator(format="yaml") >>> test_generator.get_type() 'spdx' >>> test_generator.get_format() 'yaml' >>> test_generator.generate("TestApp",test_parser.get_sbom()) SPDXID: SPDXRef-DOCUMENT creationInfo: comment: This document has been automatically generated. created: '2023-01-24T13:51:36Z' creators: - 'Tool: lib4sbom-0.1.0' licenseListVersion: '3.18' dataLicense: CC0-1.0 documentNamespace: http://spdx.org/spdxdocs/TestDocument-817c4e4c-eac4-49d9-bc41-65f0972edce8 name: TestDocument ... - relatedSpdxElement: SPDXRef-Package-4-platformdirs relationshipType: DESCRIBES spdxElementId: SPDXRef-DOCUMENT - relatedSpdxElement: SPDXRef-Package-2-distlib relationshipType: CONTAINS spdxElementId: SPDXRef-Package-1-virtualenv - relatedSpdxElement: SPDXRef-Package-3-filelock relationshipType: CONTAINS spdxElementId: SPDXRef-Package-1-virtualenv - relatedSpdxElement: SPDXRef-Package-4-platformdirs relationshipType: CONTAINS spdxElementId: SPDXRef-Package-1-virtualenv spdxVersion: SPDX-2.3 >>> test_generator.get_sbom() {'SPDXID': 'SPDXRef-DOCUMENT', 'spdxVersion': 'SPDX-2.3', 'creationInfo': {'comment': 'This document has been automatically generated.', 'creators': ['Tool: lib4sbom-0.1.0'], 'created': '2023-01-24T13:51:36Z', 'licenseListVersion': '3.18'}, 'name': 'TestDocument', 'dataLicense': 'CC0-1.0', 'documentNamespace': 'http://spdx.org/spdxdocs/TestDocument-817c4e4c-eac4-49d9-bc41-65f0972edce8', 'packages': [{'SPDXID': 'SPDXRef-Package-1-virtualenv', 'name': 'virtualenv', 'versionInfo': '20.16.7', 'supplier': 'Person: Bernat_Gabor', 'downloadLocation': 'NONE', 'filesAnalyzed': 'false', 'licenseConcluded': 'MIT', 'licenseDeclared': 'MIT', 'copyrightText': 'NOASSERTION', 'externalRefs': [{'referenceCategory': 'PACKAGE-MANAGER', 'referenceType': 'purl', 'referenceLocator': 'pkg:pypi/virtualenv@20.16.7'}]}, {'SPDXID': 'SPDXRef-Package-2-distlib', 'name': 'distlib', 'versionInfo': '0.3.6', 'supplier': 'Person: Vinay_Sajip', 'downloadLocation': 'NONE', 'filesAnalyzed': 'false', 'licenseConcluded': 'NOASSERTION', 'licenseDeclared': 'NOASSERTION', 'copyrightText': 'NOASSERTION', 'externalRefs': [{'referenceCategory': 'PACKAGE-MANAGER', 'referenceType': 'purl', 'referenceLocator': 'pkg:pypi/distlib@0.3.6'}]}, {'SPDXID': 'SPDXRef-Package-3-filelock', 'name': 'filelock', 'versionInfo': '3.8.0', 'supplier': 'Person: Benedikt_Schmitt', 'downloadLocation': 'NONE', 'filesAnalyzed': 'false', 'licenseConcluded': 'Unlicense', 'licenseDeclared': 'Unlicense', 'copyrightText': 'NOASSERTION', 'externalRefs': [{'referenceCategory': 'PACKAGE-MANAGER', 'referenceType': 'purl', 'referenceLocator': 'pkg:pypi/filelock@3.8.0'}]}, {'SPDXID': 'SPDXRef-Package-4-platformdirs', 'name': 'platformdirs', 'versionInfo': '2.5.4', 'supplier': 'Organization: Unknown', 'downloadLocation': 'NONE', 'filesAnalyzed': 'false', 'licenseConcluded': 'NOASSERTION', 'licenseDeclared': 'NOASSERTION', 'copyrightText': 'NOASSERTION', 'externalRefs': [{'referenceCategory': 'PACKAGE-MANAGER', 'referenceType': 'purl', 'referenceLocator': 'pkg:pypi/platformdirs@2.5.4'}]}], 'relationships': [{'spdxElementId': 'SPDXRef-DOCUMENT', 'relatedSpdxElement': 'SPDXRef-Package-1-virtualenv', 'relationshipType': 'DESCRIBES'}, {'spdxElementId': 'SPDXRef-DOCUMENT', 'relatedSpdxElement': 'SPDXRef-Package-2-distlib', 'relationshipType': 'DESCRIBES'}, {'spdxElementId': 'SPDXRef-DOCUMENT', 'relatedSpdxElement': 'SPDXRef-Package-3-filelock', 'relationshipType': 'DESCRIBES'}, {'spdxElementId': 'SPDXRef-DOCUMENT', 'relatedSpdxElement': 'SPDXRef-Package-4-platformdirs', 'relationshipType': 'DESCRIBES'}, {'spdxElementId': 'SPDXRef-Package-1-virtualenv', 'relatedSpdxElement': 'SPDXRef-Package-2-distlib', 'relationshipType': 'CONTAINS'}, {'spdxElementId': 'SPDXRef-Package-1-virtualenv', 'relatedSpdxElement': 'SPDXRef-Package-3-filelock', 'relationshipType': 'CONTAINS'}, {'spdxElementId': 'SPDXRef-Package-1-virtualenv', 'relatedSpdxElement': 'SPDXRef-Package-4-platformdirs', 'relationshipType': 'CONTAINS'}]} >>> ``` ### SBOMOutput _class_ **SBOMOutput**(_filename="", output_format="tag"_) 这将创建一个简单的 SBOM 输出对象。可以指定以下可选参数: _filename_ 指示要生成的 SBOM 的输出目标。如果提供了有效的文件路径并且可以创建文件,则输出将到文件,否则 将输出到控制台。 _output_format_ 指示要生成的 SBOM 的格式。有效选项为 Tag、JSON 或 YAML。如果指定了无效的格式, 则假设默认格式为 Tag。 **方法** generate_output(dataset) 输出 SBOM 文件。参数为 _dataset_ 包含输出格式的 SBOM 数据。如果 SBOM 数据不是 output_format 参数指定的格式,则不会生成输出。 **注意 有效的数据集通常由 SBOMGenerator 类生成,并通过调用 get_sbom() 方法获得。** get_type() 返回生成的 SBOM 的目标。文件或控制台 get_format() 返回生成的 SBOM 的格式。Tag、JSON 或 YAML 之一。 **示例** 以下代码示例展示了 SBOMOutput 模块的使用。 ``` >>> from lib4sbom.parser import SBOMParser >>> test_parser = SBOMParser() >>> test_parser.parse_file("test_sbom.spdx") >>> from lib4sbom.generator import SBOMGenerator >>> test_generator = SBOMGenerator(format="json") >>> test_generator.generate("TestApp",test_parser.get_sbom()) >>> from lib4sbom.output import SBOMOutput >>> sbom_output = SBOMOutput(filename="testapp.json", output_format="json") >>> sbom_output.generate_output(test_generator.get_sbom()) >>> ``` ### SBOM _class_ **SBOM**() 这将创建一个简单的 SBOM 对象。此对象包含要包含在 SBOM 中的所有项目,包括 组件和关系。留给操作 SBOM 对象的应用程序根据每个属性的存在情况应用适当的验证。 **方法** **_Setter 方法_** 对于以下属性,提供了 **_set_attribute(value)_** 方法。请注意,属性名称始终为 _小写_。 例如 set_type()。除非另有说明,否则该方法仅接受一个值参数。在指出的地方,可以定义属性的多个实例。 | Attribute | Multiple | Note | |-------------------|----------|------| | Version | No | (1) | | Type | No | (2) | | Uuid | No | (3) | | Bom_Version | No | | **注意** 1. 这与类型属性指定的 SBOM 规范的版本有关。例如 CycloneDX 为 1.4,SPDX 为 SPDX-2.3。 2. 这是指 SBOM 的类型,即 SPDX 或 CycloneDX。 3. 这与 SBOM 的唯一标识符有关。 **_Getter 方法_** get_sbom() 以字典形式返回 SBOM 对象。 **示例** ``` >>> from lib4sbom.sbom import SBOM >>> sbom = SBOM() >>> sbom.set_type(sbom_type='cyclonedx') >>> sbom.set_version("1.4") >>> sbom.set_uuid("urn:uuid:My_uuid_1234") >>> sbom.set_bom_version("2") >>> sbom.get_type() 'cyclonedx' >>> from lib4sbom.data.document import SBOMDocument >>> my_doc = SBOMDocument() >>> my_doc.set_metadata_type("firmware") >>> sbom.add_document(my_doc.get_document()) ``` ### SBOMDocument 对象 _class_ **SBOMDocument**() 这将创建一个简单的 SBOMDocument 对象。此对象包含可以与 SBOM 关联的属性值。 这包括名称、标识符、文件类型、校验和和许可证信息等属性。由于每个属性都是可选的,因此留给操作 SBOMFile 对象的应用程序根据每个属性的存在情况应用适当的验证。 **方法** **_Setter 方法_** 对于以下属性,提供了 **_set_attribute(value)_** 方法。请注意,属性名称始终为 _小写_。 例如 set_filetype()。属性名称与 SPDX 规范中 File Object 的属性一致。除非 另有说明,否则该方法仅接受一个值参数。在指出的地方,可以定义属性的多个实例。 | Attribute | Multiple | Note | |-------------------|----------|------| | Name | No | | | Id | No | | | DataLicense | No | | | Metadata_Type | No | (1) | | Metadata_Supplier | No | | | Metadata_Version | No | | | Bom_Version | No | | **注意** 1. 这与 SBOM 描述的组件类型有关。此属性仅用于 CycloneDX SBOM。 还有一个额外的 setter 方法 **set_value**(_attribute, value_),它允许设置任何属性。 `set_value("language", "Rust")` **_Getter 方法_** get_document() 以列表形式返回 SBOMDocument 对象。 get_name() 返回 SBOMDocument 对象的名称,如果 SBOMDocument 对象实例中不存在该属性,则返回默认值。 get_value(attribute) 返回属性的值。如果 SBOMDocument 对象实例中不存在该属性,则返回默认值。 **示例** ``` >>> from lib4sbom.data.document import SBOMDocument >>> sbom_document = SBOMDocument() >>> sbom_document.set_name("test_file") >>> sbom_document.set_metadata_type("firmware") >>> sbom_document.get_name() 'test_file' >>> from lib4sbom.sbom import SBOM >>> my_sbom = SBOM() >>> my_sbom.add_document(sbom_document.get_document()) ``` ### SBOMFile 对象 _class_ **SBOMFile**() 这将创建一个简单的 SBOM 文件对象。此对象包含可以与 SBOM 中的文件工件关联的属性值。 这包括名称、标识符、文件类型、校验和和许可证信息等属性。由于每个属性都是可选的,因此留给操作 SBOMFile 对象的应用程序根据每个属性的存在情况应用适当的验证。 **方法** **_Setter 方法_** 对于以下属性,提供了 **_set_attribute(value)_** 方法。请注意,属性名称始终为 _小写_。 例如 set_filetype()。属性名称与 SPDX 规范中 File Object 的属性一致。除非 另有说明,否则该方法仅接受一个值参数。在指出的地方,可以定义属性的多个实例。 | Attribute | Multiple | Note | |-------------------|----------|------| | Name | No | | | Id | No | | | FileType | Yes | | | Checksum | Yes | (1) | | LicenseConcluded | No | | | LicenceInfoInFile | Yes | | | LicenceComment | No | | | CopyrightText | No | | | Comment | No | | | Notice | No | | | Contributor | Yes | | | Attribution | No | | **注意** 1. set_checksum 方法接受两个参数:校验和算法(例如 SHA256)和实际校验和值(作为字符串) 还有一个额外的 setter 方法 **set_value**(_attribute, value_),它允许设置任何属性。 `set_value("language", "Rust")` **_Getter 方法_** get_file() 以字典形式返回 SBOMFile 对象。属性的值作为字符串返回,除非 允许属性的多个实例,在这种情况下,属性的值作为 List 返回。 get_name() 返回 SBOMFile 对象的名称,如果 SBOMFile 对象实例中不存在 'name' 属性,则返回 None。 get_value(attribute) 返回属性的值。如果 SBOMFile 对象实例中不存在该属性,则返回默认值。 _**Utility 方法**_ initialise() 重新初始化 SBOMFile 对象。与该对象关联的所有数据将被删除。 **示例** ``` >>> from lib4sbom.data.file import SBOMFile >>> sbom_file = SBOMFile() >>> sbom_files = {} >>> sbom_file.initialise() >>> sbom_file.set_name("test_file.c") >>> sbom_file.set_licenseconcluded("MIT") >>> file_hash = <<< some calculation >>> >>> sbom_file.set_checksum("SHA1", file_hash) >>> sbom_file.set_id("SPDXRef-File-0001") >>> sbom_files[sbom_file.get_name()] = sbom_file.get_file() >>> sbom_file.initialise() >>> sbom_file.set_name("makefile") >>> sbom_file.set_licenseconcluded("NOASSERTION") >>> sbom_file.set_id("SPDXRef-File-0002") >>> sbom_files[sbom_file.get_name()] = sbom_file.get_file() >>> from lib4sbom.sbom import SBOM >>> my_sbom = SBOM() >>> my_sbom.add_files(sbom_files) ``` ### SBOMPackage 对象 _class_ **SBOMPackage**() 这将创建一个简单的 SBOM 包对象。此对象包含可以与 SBOM 中的包或组件工件关联的属性值。 这包括名称、标识符、供应商、版本和许可证信息等属性。由于每个属性都是可选的,因此留给操作 SBOMPackage 对象的应用程序根据每个属性的存在情况应用适当的验证。 **_Setter 方法_** 对于以下属性,提供了 **_set_attribute(value)_** 方法。请注意,属性名称始终为 _小写_。 例如 set_version()。属性名称与 SPDX 规范中 Package Object 的属性一致。除非 另有说明,否则该方法仅接受一个值参数。在指出的地方,可以定义属性的多个实例。 | Attribute | Multiple | Note | |-------------------|----------|------| | Name | No | | | Id | No | | | Type | No | (1) | | Checksum | Yes | (2) | | LicenseConcluded | No | | | LicenseDeclared | No | (3) | | LicenceInfoInFile | Yes | | | LicenceComments | No | | | FilesAnalysis | No | | | CopyrightText | No | | | Comment | No | | | Originator | No | | | Supplier | No | | | Version | No | | | Homepage | No | | | Property | Yes | (4) | | DownloadLocation | No | | | Description | No | | | ExternalReference | Yes | (5) | | Cpe | No | | | Purl | No | (6) | | Summary | No | | | SourceInfo | No | | | Filename | No | | **注意** 1. set_type 方法用于指示包的用途(例如 Application、Library、Operating-System)。 2. set_checksum 方法接受两个参数:校验和算法(例如 SHA256)和实际校验和值(作为字符串) 3. set_licensedeclared 方法接受一个可选的第二个参数,即许可证名称。在这种情况下,第一个参数 license 被假定为许可证文本而不是许可证标识。 4. set_property 方法接受两个参数,即属性名称和值。 5. set_externalreference 方法接受三个参数,即类别(SECURITY 或 PACKAGE_MANAGER)、类型(cpe22Type、cpe23Type 或 purl)以及与类型对应的元素。 6. set_cpe 接受一个可选的第二个参数,即 CPE 类型(默认为 cpeType23)。 还有一个额外的 setter 方法 **set_value**(_attribute, value_),它允许设置任何属性。 `set_value("language", "Rust")` **_Getter 方法_** get_package() 以字典形式返回 SBOMPackage 对象。属性的值作为字符串返回,除非允许属性的多个实例,在这种情况下,属性的值作为 List 返回。 get_name() 返回 SBOMPackage 对象的名称,如果 SBOMPackage 对象实例中不存在 'name' 属性,则返回 None。 get_value(attribute) 返回属性的值。如果 SBOMPackage 对象实例中不存在该属性,则返回默认值。 get_purl() 以字符串形式返回包的 PURL 标识符,如果未定义 PURL 元素,则返回 None。 get_cpe() 以字符串形式返回包的 CPE 标识符,如果未定义 CPE 元素,则返回 None。 **_Utility 方法_** initialise() 重新初始化 SBOMPackage 对象。与该对象关联的所有数据将被删除。 **示例** ``` >>> from lib4sbom.data.package import SBOMPackage >>> sbom_packages = {} >>> my_package = SBOMPackage() >>> my_package.set_name("glibc") >>> my_package.set_version("2.15") >>> my_package.set_supplier("organisation","gnu") >>> my_package.set_licensedeclared("GPL3") >>> sbom_packages[(my_package.get_name(), my_package.get_value('version'))] = my_package.get_package() >>> my_package.initialise() >>> my_package.set_name("tomcat") >>> my_package.set_version("9.0.46") >>> my_package.set_supplier("organisation","apache") >>> my_package.set_licensedeclared("Apache-2.0") >>> sbom_packages[(my_package.get_name(), my_package.get_value('version'))] = my_package.get_package() >>> from lib4sbom.sbom import SBOM >>> my_sbom = SBOM() >>> my_sbom.add_packages(sbom_packages) ``` ### SBOMRelationship 对象 _class_ **SBOMRelationship**() 这将创建一个简单的 SBOMRelationship 对象,用于显示 SBOM 中两个项目之间的关系。 由于存在多种类型的关系,留给操作 SBOMRelationship 对象的应用程序应用适当的验证以确保关系的语义正确。 **_Setter 方法_** set_relationship (source, type, target) _source_ 和 _target_ 是定义关系的组件的唯一标识符。 _type_ 是定义的关系类型。 **_Getter 方法_** get_relationship() 以字典形式返回 SBOMRelationship 对象。 **示例** ``` >>> from lib4sbom.data.relationship import SBOMRelationship >>> sbom_relationships = [] >>> my_relationship = SBOMRelationship() >>> my_relationship.set_relationship("Package-1","CONTAINS", "Package-2") >>> sbom_relationships.append(my_relationship) >>> from lib4sbom.sbom import SBOM >>> my_sbom = SBOM() >>> my_sbom.add_relationships(sbom_relationships) ``` ### Vulnerability 对象 _class_ **Vulnerability**(validation = None) 这将创建一个简单的漏洞对象,用于定义漏洞的详细信息,通常用于 SBOM 中指定的组件。由于指定漏洞状态的方式有多种,留给操作 Vulnerability 对象的应用程序应用适当的验证以确保漏洞的语义正确。 可以指定以下可选参数: _validation_ 指示是否根据 [OpenVEX](https://openvex.dev)、[CycloneDX](https://www.cyclonedx.org) 或 [CSAF](https://docs.oasis-open.org/csaf/csaf/v2.0/csaf-v2.0.html) 规范验证状态字段。 **注意** 漏洞对象仅包含在 CyclonedDX SBOM 中 **_Setter 方法_** 对于以下属性,提供了 **_set_attribute(value)_** 方法。请注意,属性名称始终为 _小写_。 例如 set_release()。每个方法接受一个值参数。不允许属性的多个实例。 | Attribute | Multiple | Note | |-------------------|----------|------| | Name | No | | | Id | No | (1) | | Release | No | | | Status | No | (2) | | Comment | No | (3) | | Description | No | (4) | **注意** 1. set_id 方法用于指示漏洞的身份,例如 CVE-2021-44228 2. set_status 用于指示漏洞的状态。状态值的验证可以根据 创建 Vulnerability 对象时指定的可选参数 _validation_ 选择性地执行。无效状态由 None 值指示。 3. set_comment 方法用于提供额外信息以支持状态值,例如简要理由 4. set_description 方法用于描述漏洞。 还有一个额外的 setter 方法 **set_value**(_attribute, value_),它允许设置任何属性。 `set_value("bom-ref", "rust@1.2.3")` **_Getter 方法_** get_vulnerability() 以字典形式返回漏洞对象。 **示例** ``` >>> from lib4sbom.data.vulnerability import Vulnerability >>> vulnerabilities = [] >>> vulnerability = Vulnerability(validation="cyclonedx") >>> vulnerability.set_id("CVE-2023-1235") >>> vulnerability.set_name("rust") >>> vulnerability.set_release("1.2.3") >>> vulnerability.set_value("bom-ref", "rust@1.2.3") >>> vulnerability.set_status("in_triage") >>> vulnerabilities.append(vulnerability.get_vulnerability()) >>> from lib4sbom.sbom import SBOM >>> my_sbom = SBOM() >>> my_sbom.add_vulnerabilities(vulnerabilities) ``` ### Services 对象 _class_ **SBOMService**(validation = None) 这将创建一个简单的软件服务对象,用于定义软件服务的详细信息。 由于指定服务的方式有多种,留给操作 服务对象的应用程序应用适当的验证以确保服务的语义正确。 **注意** 服务对象仅包含在 CyclonedDX SBOM 中 **_Setter 方法_** 对于以下属性,提供了 **_set_attribute(value)_** 方法。请注意,属性名称始终为 _小写_。 例如 set_release()。每个方法接受一个值参数。不允许属性的多个实例。 | Attribute | Multiple | Note | |------------------|----------|------| | Name | No | | | Id | No | (1) | | Version | No | | | Provider | No | (2) | | Endpoint | Yes | | | Data | Yes | (3) | | Property | Yes | (4) | | License | Yes | | | Exernalreference | Yes | (5) | | Description | No | | **注意** 1. set_id 方法用于指示服务的身份。如果未指定,将自动生成一个 id。 2. set_provider 用于指定服务提供商的详细信息。可以指定多个参数(name、url、contactname、email address 和 phone),至少必须指定一个。 3. set_data 方法用于提供额外信息以描述正在交换的数据。有两个强制性参数 flow type("Inbound"、"Outbound"、"Bi-directional" 或 "Unknown")和 classification,以及两个可选参数 name 和 description。 4. set_property 方法接受两个参数,即属性名称和值。 5. set_externalreference 方法接受三个参数:URL、被引用的信息类型和可选注释。 还有一个额外的 setter 方法 **set_value**(_attribute, value_),它允许设置任何属性。 `set_value("trustzone", "Data_DMZ")**_Getter 方法_** get_service() 以字典形式返回服务对象。 **示例** ``` >>> from lib4sbom.data.service import SBOMService >>> sbom_services = {} >>> my_service=SBOMService() >>> my_service.set_name("Microsoft 365") >>> my_service.set_version("2022.04") >>> my_service.set_provider(name="Microsoft Inc.", contact="Fred Flintstone", email="fred@micrsoft.com") >>> my_service.set_description("Business productivity suite") >>> my_service.set_value("authenticated",True) >>> my_service.set_endpoint("www.microsoft.com") >>> my_service.set_endpoint("www.microsoft.com/owa") >>> my_service.set_data("Bi-directional","None",description="document") >>> my_service.set_data("outbound","PII",name="User information") >>> my_service.set_license("Apache-2.0") >>> my_service.set_license("MIT") >>> my_service.set_property("Data_Location","EU") >>> my_service.set_externalreference("https://www.microsoft.com","Website", "Company website") >>> sbom_services[(my_service.get_name(), my_service.get_value('version'))] = my_service.get_service() >>> from lib4sbom.sbom import SBOM >>> my_sbom = SBOM() >>> my_sbom.add_services(sbom_services) ``` ### Cryptpgraphy 对象 _class_ **SBOMCryptography**(validation = None) 这将创建一个简单的加密对象,用于定义加密项目(算法、证书、协议或相关材料)的详细信息。 由于指定加密对象的方式有多种,留给操作 该对象的应用程序应用适当的验证以确保语义正确。强烈 建议参考 [CycloneDX guide to CBOMs](https://cyclonedx.org/guides/OWASP_CycloneDX-Authoritative-Guide-to-CBOM-en.pdf)。 **注意** 加密对象仅包含在 CyclonedDX SBOM 中,并且是组件的属性。 **_Setter 方法_** 必须调用 **set_type** 方法来定义要定义的加密对象的类型。此方法接受要创建的对象类型('algorithm'、'certificate'、'protocol' 或 'related-crypto-material' 之一)。 为每种类型提供支持方法,如下所示: - Algorithm - set_algorithm - set_keysize - Certificate - set_certificate - set_format - set_date - set_state - set_asset - Protocol - set_version - Material - set_property - set_value 下面的示例提供了有关如何使用每种方法的指导。 **_Getter 方法_** get_cryptography() 以字典形式返回加密对象。 **示例** ``` from lib4sbom.data.cryptography import SBOMCryptoography from lib4sbom.data.package import SBOMPackage my_package = SBOMPackage() my_crypto = SBOMCryptography() # 随组件包含 crypto my_package.initialise() my_package.set_name("RSA-PKCS1-1.5-SHA-256-2048") my_package.set_type("cryptographic-asset") my_crypto.initialise() my_crypto.set_oid("1.3.4.5.6") my_crypto.set_type("algorithm","signature") my_crypto.set_keysize("2048") my_crypto.set_algorithm("RSASSA-PKCS1") my_crypto.set_value("elipticCurve","bn/bn158") # 向组件添加 crypto 元素 my_package.set_value("crypto", my_crypto.get_cryptography()) sbom_packages[ (my_package.get_name(), my_package.get_value("version")) ] = my_package.get_package() # 随组件包含 crypto my_package.initialise() my_package.set_name("Wikipedia-cert",) my_package.set_type("cryptographic-asset") my_crypto.initialise() my_crypto.set_type("certificate") my_crypto.set_certificate(subject = "C=US, ST=California, O=San Fransico, O=Wikipedia", issuer='C=BE, O=GlbalSign, CN=Acme') my_crypto.set_state("pre-activation") my_crypto.set_date("create", "2026-02-13") my_crypto.set_date("activate", "2026-02-14") my_crypto.set_asset("publickey","abcd") my_crypto.set_format("X.509") my_package.set_value("crypto", my_crypto.get_cryptography()) sbom_packages[ (my_package.get_name(), my_package.get_value("version")) ] = my_package.get_package() # 随组件包含 crypto my_package.initialise() my_package.set_name("Wikipedia",) my_package.set_type("cryptographic-asset") my_crypto.initialise() my_crypto.set_type("protocol", "tls") my_crypto.set_version("1.3") my_crypto.set_asset("publickey","abcd") my_package.set_value("crypto", my_crypto.get_cryptography()) sbom_packages[ (my_package.get_name(), my_package.get_value("version")) ] = my_package.get_package() # 随组件包含 crypto my_package.initialise() my_package.set_name("WikipediaData",) my_package.set_type("cryptographic-asset") my_crypto.initialise() my_crypto.set_type("related-crypto-material", "private-key") my_crypto.set_state("active") my_crypto.set_date("activate", "2026-02-16") my_crypto.set_asset("privatekey","abcd") my_package.set_value("crypto", my_crypto.get_cryptography()) sbom_packages[ (my_package.get_name(), my_package.get_value("version")) ] = my_package.get_package() ``` ## 示例 _examples_ 子目录中包含许多示例脚本。 ## 实现说明 在处理 SBOM 文件时做出了以下设计决策: 1. 假设 SBOM 是有效的并包含语法有效的数据。 2. 在 SPDX 格式中,工具假定包的名称位于包的版本和许可证之前。 3. 在 SPDX 格式中,当前实现目前不处理多行元素。 4. 在处理和验证许可证时,应用程序将使用一组同义词尝试将某些许可证标识符映射到正确的 [SPDX License Identifiers](https://spdx.org/licenses/)。但是, 提醒工具的使用者,他们应该断言工具提供的任何数据的质量,特别是在许可证标识符已被修改的情况下。 5. 当解析具有同名和同版本的组件的多个实例的 SBOM 时,仅保留组件的一个实例。如果需要保留 多个实例,请考虑确保组件名称是唯一的。 6. 在验证 SPDX 格式的 SBOM 时,由于没有发布官方 schema,验证仅限于检查某些强制字段的存在。 ## 未来开发 1. 支持更高版本的 SPDX (3.0)。 2. 增强 SBOM 数据的验证以检查所有强制元素。 3. 跨模块实现 Python 类型。 4. 将打包基础设施从 setup.py 迁移。 5. 利用第三方 SPDX 和 CycloneDX 解析器和生成器 6. 增加对 SPDX XML 和 RDF 格式的进一步支持 7. 添加 CycloneDX XML 文档的生成器。 8. 实施测试套件。 ## 许可证 根据 Apache 2.0 许可证授权。 该工具使用 [SPDX Licenses List](https://github.com/spdx/license-list-data) 的本地副本,该副本根据 [Creative Commons Attribution 3.0 (CC-BY-3.0)](http://creativecommons.org/licenses/by/3.0/) 发布。 该工具使用 CycloneDX schema 的本地副本,该副本根据 [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) 发布 该工具使用源自 [Blue Oak Council's License List](https://blueoakcouncil.org/list) 的信息,该信息根据 [Creative Commons Attribution 1.0 (CC-BY-1.0)](https://creativecommons.org/licenses/by/1.0/) 发布。 ## 限制 该工具旨在支持软件开发。该工具的有用性取决于提供给 工具的 SBOM 数据。遗憾的是,该工具无法确定此类 SBOM 文件的有效性或完整性;因此提醒工具的使用者, 他们应该断言提供给工具的任何数据的质量。 解析无效的 SBOM 文件可能会导致不可预测的结果。 ## 反馈与贡献 可以通过 GitHub Issues 报告错误和功能请求。
标签:CycloneDX, DevSecOps, GPT, OpenSSF, Python, SBOM, SBOM生成, SBOM解析, SPDX, WebSocket, 上游代理, 人工智能安全, 依赖分析, 包管理, 合规性, 后端开发, 文档安全, 无后门, 漏洞管理, 硬件无关, 组件解析, 跌倒检测, 软件物料清单