From 79f77e0a1a5a747110ae371e2be13e4dd44b1b50 Mon Sep 17 00:00:00 2001 From: caio-volpato Date: Tue, 28 Jan 2025 09:42:00 -0300 Subject: [PATCH] Implement iso package listing into a CSV file For IP disclosure proposes create a csv file listing the deb packages included in the ISO file. Story: 2011336 Task: 51624 TEST PLAN PASS: executing the script against a valid input file produces the expected CSV file PASS: executing the script against invalid input file prints warning without producing a failure Change-Id: Ibdda4efe1208e7145da34b468c2cc3490c05d397 --- scripts/build-iso.sh | 3 + scripts/lib/packages_parser.py | 134 +++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100755 scripts/lib/packages_parser.py diff --git a/scripts/build-iso.sh b/scripts/build-iso.sh index 73bacc5..e7b4676 100755 --- a/scripts/build-iso.sh +++ b/scripts/build-iso.sh @@ -36,3 +36,6 @@ if $SIGN_ISO_FORMAL ; then fi notice "building STD ISO" stx_docker_cmd $DRY_RUN_ARG "build-image $build_img_args" + +python3 $(dirname "$0")/lib/packages_parser.py --input "$BUILD_HOME"/localdisk/workdir/starlingx/packages.yaml --csv-dest "$BUILD_HOME"/localdisk/deploy/iso-packages.csv || true +# errors on the script are ignored \ No newline at end of file diff --git a/scripts/lib/packages_parser.py b/scripts/lib/packages_parser.py new file mode 100755 index 0000000..5bf4c98 --- /dev/null +++ b/scripts/lib/packages_parser.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 + +""" +Copyright (c) 2014-2025 Wind River Systems, Inc. + +SPDX-License-Identifier: Apache-2.0 + +Parses the packages.yaml into a CSV file for IP disclosure proposes + +The packages.yaml lists the packages present into the ISO + +It was more fields that we are interested, such as the dependencies + +This script only cares about the package name, the version and the filename. + +The packages.yaml lives in: /localdisk/workdir/starlingx/packages.yaml + +Usage example: packages_parser.py --input packages.yaml --csv-dest iso-packages.csv +""" + +import argparse +import csv +import logging +import sys + + +def removeprefix(text, prefix): + """ + str.removeprefix() and str.removesuffix() was introduced on python 3.9 + for older versions we need to implement it ourselfs + implementation from the PEP that introduced it + https://peps.python.org/pep-0616/#specification + """ + if text.startswith(prefix): + return text[len(prefix) :] + return text[:] + + +def removesuffix(text, suffix): + # suffix='' should not call self[:-0]. + if suffix and text.endswith(suffix): + return text[: -len(suffix)] + return text[:] + + +def read_yaml(pkgs_filename): + """parses simple key file yaml, only parsing some fields + + the packages.yaml follows the following structure + + acl: + arch: '' + ver: 2.2.53-10 + filename: acl_2.2.53-10_amd64.deb + deps: + - libacl1 + - libc6 + pkgarch: '' + provs: [] + [...] + + we only care about the package name, version and filename + + Args: + pkgs_filename packages.yaml filename + + Returns: + list of the csv rows (package_name, package_version, package_filename) + """ + curr_key = "" + old_key = "" + curr_ver = "" + curr_file = "" + rows = [] + with open(pkgs_filename, mode="r", encoding="utf-8") as f: + for line in f: + ls = line.rstrip() # line wo trailing spaces (to remove the newline char) + if ls.endswith(":") and not ls.startswith(" "): # parent key (pkg) + curr_key = removesuffix(ls, ":") + curr_ver = "" # found a new package, reset the other fields + curr_file = "" + elif ls.startswith(" "): # values within a pkg + if ls.strip().startswith("filename:"): + curr_file = removeprefix(ls.strip(), "filename: ") + elif ls.strip().startswith("ver:"): + curr_ver = removeprefix(ls.strip(), "ver: ") + if len(curr_ver) > 0 and len(curr_file) > 0 and old_key != curr_key: + # all the fields of a new package are field, add it results + row = [curr_key, curr_ver, curr_file] + rows.append(row) + old_key = curr_key + if len(rows) > 0: + return rows + raise ValueError( + "Parser Error! Input file is malformed, filename='%s'" % pkgs_filename + ) + + +def write_csv(dest_filename, headers, rows): + with open(dest_filename, mode="w", encoding="utf-8") as f: + writer = csv.writer(f) + writer.writerow(headers) + writer.writerows(rows) + + +def main(pkgs_filename, dest_csv_filename): + logging.info( + "starting the script, input=%s, output=%s", pkgs_filename, dest_csv_filename + ) + csv_headers = ["package_name", "version", "filename"] + rows = read_yaml(pkgs_filename) + logging.info("yaml parsed successfully, found %s packages", len(rows)) + logging.info("writing the results into the CSV file!") + write_csv(dest_csv_filename, csv_headers, rows) + logging.info("Done!") + + +if __name__ == "__main__": + cliparser = argparse.ArgumentParser( + prog="PackagesDotYamlParser", + description="Convert the packages.yaml into a csv file", + ) + cliparser.add_argument("--input", required=True, help="packages.yaml file location") + cliparser.add_argument("--csv-dest", required=True, help="csv output filename") + args = cliparser.parse_args() + logging.basicConfig( + format="%(asctime)s - %(levelname)s - %(message)s", + level=logging.INFO, + ) + try: + main(args.input, args.csv_dest) + except Exception as e: + logging.error("Fail to execute the script, exception message:\n%s", e) + sys.exit(1)