capycli 2.0.0.dev8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. License.md +27 -0
  2. capycli/__init__.py +214 -0
  3. capycli/__main__.py +13 -0
  4. capycli/bom/__init__.py +10 -0
  5. capycli/bom/bom_convert.py +163 -0
  6. capycli/bom/check_bom.py +187 -0
  7. capycli/bom/check_bom_item_status.py +197 -0
  8. capycli/bom/check_granularity.py +244 -0
  9. capycli/bom/create_components.py +644 -0
  10. capycli/bom/csv.py +69 -0
  11. capycli/bom/diff_bom.py +279 -0
  12. capycli/bom/download_sources.py +227 -0
  13. capycli/bom/filter_bom.py +323 -0
  14. capycli/bom/findsources.py +278 -0
  15. capycli/bom/handle_bom.py +134 -0
  16. capycli/bom/html.py +67 -0
  17. capycli/bom/legacy.py +312 -0
  18. capycli/bom/legacy_cx.py +151 -0
  19. capycli/bom/map_bom.py +1039 -0
  20. capycli/bom/merge_bom.py +155 -0
  21. capycli/bom/plaintext.py +69 -0
  22. capycli/bom/show_bom.py +77 -0
  23. capycli/common/__init__.py +9 -0
  24. capycli/common/capycli_bom_support.py +629 -0
  25. capycli/common/comparable_version.py +161 -0
  26. capycli/common/component_cache.py +240 -0
  27. capycli/common/dependencies_base.py +48 -0
  28. capycli/common/file_support.py +28 -0
  29. capycli/common/html_support.py +119 -0
  30. capycli/common/json_support.py +36 -0
  31. capycli/common/map_result.py +116 -0
  32. capycli/common/print.py +55 -0
  33. capycli/common/purl_service.py +169 -0
  34. capycli/common/purl_store.py +100 -0
  35. capycli/common/purl_utils.py +85 -0
  36. capycli/common/script_base.py +165 -0
  37. capycli/common/script_support.py +78 -0
  38. capycli/data/__init__.py +9 -0
  39. capycli/data/granularity_list.csv +1338 -0
  40. capycli/dependencies/__init__.py +9 -0
  41. capycli/dependencies/handle_dependencies.py +70 -0
  42. capycli/dependencies/javascript.py +261 -0
  43. capycli/dependencies/maven_list.py +333 -0
  44. capycli/dependencies/maven_pom.py +150 -0
  45. capycli/dependencies/nuget.py +184 -0
  46. capycli/dependencies/python.py +345 -0
  47. capycli/main/__init__.py +9 -0
  48. capycli/main/application.py +165 -0
  49. capycli/main/argument_parser.py +101 -0
  50. capycli/main/cli.py +28 -0
  51. capycli/main/exceptions.py +14 -0
  52. capycli/main/options.py +424 -0
  53. capycli/main/result_codes.py +41 -0
  54. capycli/mapping/handle_mapping.py +46 -0
  55. capycli/mapping/mapping_to_html.py +182 -0
  56. capycli/mapping/mapping_to_xlsx.py +197 -0
  57. capycli/moverview/handle_moverview.py +46 -0
  58. capycli/moverview/moverview_to_html.py +122 -0
  59. capycli/moverview/moverview_to_xlsx.py +170 -0
  60. capycli/project/__init__.py +9 -0
  61. capycli/project/check_prerequisites.py +304 -0
  62. capycli/project/create_bom.py +190 -0
  63. capycli/project/create_project.py +335 -0
  64. capycli/project/create_readme.py +546 -0
  65. capycli/project/find_project.py +128 -0
  66. capycli/project/get_license_info.py +246 -0
  67. capycli/project/handle_project.py +118 -0
  68. capycli/project/show_ecc.py +200 -0
  69. capycli/project/show_licenses.py +211 -0
  70. capycli/project/show_project.py +215 -0
  71. capycli/project/show_vulnerabilities.py +238 -0
  72. capycli-2.0.0.dev8.dist-info/LICENSES/CC0-1.0.txt +121 -0
  73. capycli-2.0.0.dev8.dist-info/LICENSES/MIT.txt +27 -0
  74. capycli-2.0.0.dev8.dist-info/License.md +27 -0
  75. capycli-2.0.0.dev8.dist-info/METADATA +268 -0
  76. capycli-2.0.0.dev8.dist-info/RECORD +78 -0
  77. capycli-2.0.0.dev8.dist-info/WHEEL +4 -0
  78. capycli-2.0.0.dev8.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,155 @@
1
+ # -------------------------------------------------------------------------------
2
+ # Copyright (c) 2023 Siemens
3
+ # All Rights Reserved.
4
+ # Author: thomas.graf@siemens.com
5
+ #
6
+ # SPDX-License-Identifier: MIT
7
+ # -------------------------------------------------------------------------------
8
+
9
+ import os
10
+ import sys
11
+
12
+ from cyclonedx.model.bom import Bom
13
+ from cyclonedx.model.component import Component
14
+
15
+ import capycli.common.script_base
16
+ from capycli.common.capycli_bom_support import CaPyCliBom, SbomWriter
17
+ from capycli.common.print import print_red, print_text
18
+ from capycli.main.result_codes import ResultCode
19
+
20
+ LOG = capycli.get_logger(__name__)
21
+
22
+ """
23
+ A general question for merge and diff operation is HOW we compare SBOM component.
24
+ For CaPyCLI 1.x the answer was easy: we had a simple JSON format to store component
25
+ information and we only compared name and version.
26
+
27
+ For CaPyCLI 2.x we have CycloneDX as format to store component information and we have
28
+ more questions regarding the component comparison:
29
+ - what about the package-url?
30
+ - what about the bom-ref?
31
+ - what happens if certain properties are different?
32
+ - what happens if certain external references are different?
33
+ - what about the SBOM meta-data
34
+ - what about differences in tools?
35
+ - what about differences in properties like siemens:profile?
36
+ - what about differences in licenses?
37
+
38
+ cyclonedx-cli only compares group, name and version when doing a diff.
39
+ At the moment (version 0.24.2) they do not do any comparison while merging.
40
+
41
+ Current idea:
42
+ * Only compare group, name and version for every component.
43
+ * Do not care about different properties, external references, etc. of components with identical group,
44
+ name and version. We cannot really decide what to do. Merging of these component properties could be
45
+ as wrong as comparing them.
46
+ * Consider `merge` as an operation to merge a secondary SBOM into a master SBOM.
47
+ The metadata, license and siemens:profile of the master will be persisted in the result.
48
+
49
+ Remember KISS ("Keep it simple, stupid!"). Use this simple merge approach for the time being.
50
+ If there is the need to do better or a great idea on how to do better, we can change the approach.
51
+ """
52
+
53
+
54
+ class MergeBom(capycli.common.script_base.ScriptBase):
55
+ """Merge two SBOM files.
56
+ """
57
+
58
+ @staticmethod
59
+ def are_same(c1: Component, c2: Component, deep: bool = False) -> bool:
60
+ """
61
+ Compares two components. If deep if False, then only
62
+ group, name and version are compared.
63
+
64
+ If deep is True, also properties and external references are compared.
65
+ """
66
+ if (c1.group != c2.group) or (c1.name != c2.name) or (c1.version != c2.version):
67
+ return False
68
+
69
+ if deep:
70
+ # TBD
71
+ pass
72
+
73
+ return True
74
+
75
+ def find_in_bom(self, bom: Bom, component: Component) -> Component or None:
76
+ """Searches for an item with the given name and version in the given SBOM."""
77
+ for c in bom.components:
78
+ if self.are_same(c, component):
79
+ return c
80
+
81
+ return None
82
+
83
+ def merge_boms(self, bom_old: Bom, bom_new: Bom) -> Bom:
84
+ for component_new in bom_new.components:
85
+ found = self.find_in_bom(bom_old, component_new)
86
+ if not found:
87
+ bom_old.components.add(component_new)
88
+
89
+ return bom_old
90
+
91
+ def run(self, args):
92
+ """Main method()"""
93
+ if args.debug:
94
+ global LOG
95
+ LOG = capycli.get_logger(__name__)
96
+
97
+ print_text(
98
+ "\n" + capycli.APP_NAME + ", " + capycli.get_app_version() +
99
+ " - Merge two SBOM files.\n")
100
+
101
+ if args.help:
102
+ print("usage: CaPyCli bom merge [-h] [-v] bomfile1 bomfile2 [outputfile]")
103
+ print("")
104
+ print("positional arguments:")
105
+ print(" bomfile1 first bill of material, JSON")
106
+ print(" bomfile2 second bill of material, JSON")
107
+ print("")
108
+ print("optional arguments:")
109
+ print(" -h, --help show this help message and exit")
110
+ print(" outputfile if outputfile is specified the new SBOM will be written")
111
+ print(" to this file. Default is overwrite bomfile1")
112
+ return
113
+
114
+ if len(args.command) < 4:
115
+ print_red("Not enough input files specified!")
116
+ sys.exit(ResultCode.RESULT_COMMAND_ERROR)
117
+
118
+ if not os.path.isfile(args.command[2]):
119
+ print_red("First SBOM file not found!")
120
+ sys.exit(ResultCode.RESULT_FILE_NOT_FOUND)
121
+
122
+ if not os.path.isfile(args.command[3]):
123
+ print_red("Second SBOM file not found!")
124
+ sys.exit(ResultCode.RESULT_FILE_NOT_FOUND)
125
+
126
+ output = args.command[2]
127
+ if len(args.command) == 5:
128
+ output = args.command[4]
129
+
130
+ print_text("Loading first SBOM file", args.command[2])
131
+ try:
132
+ bom_old = CaPyCliBom.read_sbom(args.command[2])
133
+ except Exception as ex:
134
+ print_red("Error reading input SBOM file: " + repr(ex))
135
+ sys.exit(ResultCode.RESULT_ERROR_READING_BOM)
136
+ print_text(" ", self.get_comp_count_text(bom_old), "read from SBOM")
137
+
138
+ print_text("Loading second SBOM file", args.command[3])
139
+ try:
140
+ bom_new = CaPyCliBom.read_sbom(args.command[3])
141
+ except Exception as ex:
142
+ print_red("Error reading input SBOM file: " + repr(ex))
143
+ sys.exit(ResultCode.RESULT_ERROR_READING_BOM)
144
+ print_text(" ", self.get_comp_count_text(bom_new), "read from SBOM")
145
+
146
+ bom_merged = self.merge_boms(bom_old, bom_new)
147
+
148
+ print_text("Writing combined SBOM with", self.get_comp_count_text(bom_merged), "to", output)
149
+ try:
150
+ SbomWriter.write_to_json(bom_merged, output, True)
151
+ except Exception as ex:
152
+ print_red("Error writing updated SBOM file: " + repr(ex))
153
+ sys.exit(ResultCode.RESULT_ERROR_WRITING_BOM)
154
+
155
+ print_text()
@@ -0,0 +1,69 @@
1
+ # -------------------------------------------------------------------------------
2
+ # Copyright (c) 2023 Siemens
3
+ # All Rights Reserved.
4
+ # Author: thomas.graf@siemens.com
5
+ #
6
+ # SPDX-License-Identifier: MIT
7
+ # -------------------------------------------------------------------------------
8
+
9
+ from cyclonedx.model.component import Component
10
+
11
+ from capycli import LOG
12
+ from capycli.main.exceptions import CaPyCliException
13
+
14
+ # -------------------------------------
15
+ # Expected File Format
16
+ #
17
+ # <component name>, <component version>
18
+ #
19
+ # Example
20
+ # python, 3.8
21
+ # colorama, 0.4.3
22
+ # wheel, 0.34.2
23
+ # tomli, 2.0.1
24
+ # -------------------------------------
25
+
26
+
27
+ class PlainTextSupport():
28
+ @classmethod
29
+ def flatlist_to_cdx_components(cls, inputfile: str) -> list[Component]:
30
+ """Convert a flat list of components to a list
31
+ of CycloneDX components."""
32
+ bom = []
33
+ LOG.debug(f"Reading from file {inputfile}")
34
+ try:
35
+ with open(inputfile, encoding="utf-8") as fin:
36
+ for line in fin:
37
+ line = line.strip()
38
+ parts = line.split(",")
39
+
40
+ if len(parts) < 2:
41
+ continue
42
+
43
+ name = parts[0].strip()
44
+ version = parts[1].strip()
45
+ LOG.debug(f" Reading from text: name={name}, version={version}")
46
+ cxcomp = Component(
47
+ name=name,
48
+ version=version)
49
+
50
+ bom.append(cxcomp)
51
+ except Exception as exp:
52
+ raise CaPyCliException("Error reading text file: " + str(exp))
53
+
54
+ LOG.debug("done")
55
+ return bom
56
+
57
+ @classmethod
58
+ def write_cdx_components_as_flatlist(cls, bom: list[Component], outputfile: str) -> None:
59
+ LOG.debug(f"Writing to file {outputfile}")
60
+ try:
61
+ with open(outputfile, "w", encoding="utf-8") as fout:
62
+ for cx_comp in bom:
63
+ name = cx_comp.name
64
+ version = cx_comp.version
65
+ fout.write(f"{name}, {version}\n")
66
+ except Exception as exp:
67
+ raise CaPyCliException("Error writing text file: " + str(exp))
68
+
69
+ LOG.debug("done")
@@ -0,0 +1,77 @@
1
+ # -------------------------------------------------------------------------------
2
+ # Copyright (c) 2019-23 Siemens
3
+ # All Rights Reserved.
4
+ # Author: thomas.graf@siemens.com
5
+ #
6
+ # SPDX-License-Identifier: MIT
7
+ # -------------------------------------------------------------------------------
8
+
9
+ """
10
+ Display the contents of a SBOM.
11
+ """
12
+
13
+ import os
14
+ import sys
15
+
16
+ from cyclonedx.model.bom import Bom
17
+
18
+ import capycli.common.script_base
19
+ from capycli.common.capycli_bom_support import CaPyCliBom, CycloneDxSupport
20
+ from capycli.common.print import print_red, print_text, print_yellow
21
+ from capycli.main.result_codes import ResultCode
22
+
23
+ LOG = capycli.get_logger(__name__)
24
+
25
+
26
+ class ShowBom(capycli.common.script_base.ScriptBase):
27
+ """Print SBOM contents to stdout"""
28
+ def display_bom(self, bom: Bom, verbose: bool) -> None:
29
+ if not bom:
30
+ print_yellow(" Empty SBOM!")
31
+ return
32
+
33
+ for bomitem in bom.components:
34
+ print_text(" " + bomitem.name + ", " + bomitem.version)
35
+
36
+ if verbose:
37
+ if bomitem.purl:
38
+ print_text(" package-url:" + bomitem.purl)
39
+
40
+ sw360id = CycloneDxSupport.get_property_value(bomitem, CycloneDxSupport.CDX_PROP_SW360ID)
41
+ if sw360id:
42
+ print_text(" SW360 id:" + sw360id)
43
+
44
+ print_text("\n" + str(len(bom.components)) + " items in bill of material\n")
45
+
46
+ def run(self, args):
47
+ """Main method()"""
48
+ if args.debug:
49
+ global LOG
50
+ LOG = capycli.get_logger(__name__)
51
+
52
+ print_text("\n" + capycli.APP_NAME + ", " + capycli.get_app_version() + " - Print SBOM contents to stdout\n")
53
+
54
+ if args.help:
55
+ print("usage: capycli bom show [-h] -i bomfile")
56
+ print("")
57
+ print("optional arguments:")
58
+ print("-h, --help show this help message and exit")
59
+ print("-i INPUTFILE input file to read from (JSON)")
60
+ print("-v be verbose")
61
+ return
62
+
63
+ if not args.inputfile:
64
+ LOG.error("No input file specified!")
65
+ sys.exit(ResultCode.RESULT_COMMAND_ERROR)
66
+
67
+ if not os.path.isfile(args.inputfile):
68
+ LOG.error("Input file not found!")
69
+ sys.exit(ResultCode.RESULT_FILE_NOT_FOUND)
70
+
71
+ try:
72
+ bom = CaPyCliBom.read_sbom(args.inputfile)
73
+ except Exception as ex:
74
+ print_red("Error reading SBOM: " + repr(ex))
75
+ sys.exit(ResultCode.RESULT_ERROR_READING_BOM)
76
+
77
+ self.display_bom(bom, args.verbose)
@@ -0,0 +1,9 @@
1
+ # -------------------------------------------------------------------------------
2
+ # Copyright (c) 2019-2023 Siemens
3
+ # All Rights Reserved.
4
+ # Author: thomas.graf@siemens.com
5
+ #
6
+ # SPDX-License-Identifier: MIT
7
+ # -------------------------------------------------------------------------------
8
+
9
+ """Module containing the common support methods."""