scripts/contrib: Add oe-image-files-spdx script

Adds a template for a python project that processes the SPDX 3.0.1
output from a build and lists all the files on the root file system with
their checksums

This is intended to be an example to show how to deal with the SPDX data
to do common tasks.

(From OE-Core rev: 3d9c5588ce6181b519810e3378b55826ffcaee49)

Signed-off-by: Joshua Watt <JPEWhacker@gmail.com>
Signed-off-by: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
Joshua Watt 2025-02-11 08:03:25 -07:00 committed by Richard Purdie
parent 837d41f078
commit 36be59464c
6 changed files with 143 additions and 0 deletions

View File

@ -0,0 +1,8 @@
*.spdx.json
*.pyc
*.bak
*.swp
*.swo
*.swn
venv/*
.venv/*

View File

@ -0,0 +1,24 @@
# OE Image Files from SBoM
This is an example python script that will list the packaged files with their
checksums based on the SPDX 3.0.1 SBoM.
It can be used as a template for other programs to investigate output based on
OE SPDX SBoMs
## Installation
This project can be installed using an virtual environment:
```
python3 -m venv .venv
.venv/bin/activate
python3 -m pip install -e '.[dev]'
```
## Usage
After installing, the `oe-image-files` program can be used to show the files, e.g.:
```
oe-image-files core-image-minimal-qemux86-64.rootfs.spdx.json
```

View File

@ -0,0 +1,23 @@
[project]
name = "oe-image-files"
description = "Displays all packaged files on the root file system"
dynamic = ["version"]
requires-python = ">= 3.8"
readme = "README.md"
dependencies = [
"spdx_python_model @ git+https://github.com/spdx/spdx-python-model.git@aa40861f11d1b5d20edba7101835341a70d91179",
]
[project.scripts]
oe-image-files = "oe_image_files:main"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.version]
path = "src/oe_image_files/version.py"
[tool.hatch.metadata]
allow-direct-references = true

View File

@ -0,0 +1 @@
from .main import main

View File

@ -0,0 +1,86 @@
# SPDX-License-Identifier: MIT
import argparse
from pathlib import Path
from spdx_python_model import v3_0_1 as spdx_3_0_1
from .version import VERSION
def main():
parser = argparse.ArgumentParser(
description="Show the packaged files and checksums in an OE image from the SPDX SBoM"
)
parser.add_argument("file", help="SPDX 3 input file", type=Path)
parser.add_argument("--version", "-V", action="version", version=VERSION)
args = parser.parse_args()
# Load SPDX data from file into a new object set
objset = spdx_3_0_1.SHACLObjectSet()
with args.file.open("r") as f:
d = spdx_3_0_1.JSONLDDeserializer()
d.read(f, objset)
# Find the top level SPDX Document object
for o in objset.foreach_type(spdx_3_0_1.SpdxDocument):
doc = o
break
else:
print("ERROR: No SPDX Document found!")
return 1
# Find the root SBoM in the document
for o in doc.rootElement:
if isinstance(o, spdx_3_0_1.software_Sbom):
sbom = o
break
else:
print("ERROR: SBoM not found in document")
return 1
# Find the root file system package in the SBoM
for o in sbom.rootElement:
if (
isinstance(o, spdx_3_0_1.software_Package)
and o.software_primaryPurpose == spdx_3_0_1.software_SoftwarePurpose.archive
):
root_package = o
break
else:
print("ERROR: Package not found in document")
return 1
# Find all relationships of type "contains" that go FROM the root file
# system
files = []
for rel in objset.foreach_type(spdx_3_0_1.Relationship):
if not rel.relationshipType == spdx_3_0_1.RelationshipType.contains:
continue
if not rel.from_ is root_package:
continue
# Iterate over all files in the TO of the relationship
for o in rel.to:
if not isinstance(o, spdx_3_0_1.software_File):
continue
# Find the SHA 256 hash of the file (if any)
for h in o.verifiedUsing:
if (
isinstance(h, spdx_3_0_1.Hash)
and h.algorithm == spdx_3_0_1.HashAlgorithm.sha256
):
files.append((o.name, h.hashValue))
break
else:
files.append((o.name, ""))
# Print files
files.sort(key=lambda x: x[0])
for name, hash_val in files:
print(f"{name} - {hash_val}")
return 0

View File

@ -0,0 +1 @@
VERSION = "0.0.1"