Skip to content
This repository has been archived by the owner on Feb 15, 2024. It is now read-only.

Commit

Permalink
Merge pull request #206 from RedHatProductSecurity/fix-affects-mode
Browse files Browse the repository at this point in the history
GRIF-72: Fix affects mode
  • Loading branch information
JimFuller-RedHat authored Jun 29, 2023
2 parents 46300dd + bf50f98 commit 0c2300c
Show file tree
Hide file tree
Showing 7 changed files with 241 additions and 199 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased
* pin osidb-bindings 3.3.0
* update crypto python module
* fix generation of affects

## [0.2.8] - 2023-06-28
### Added
Expand Down
33 changes: 21 additions & 12 deletions griffon/commands/queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,14 @@
generate_entity_report,
generate_license_report,
)
from griffon.output import console, cprint, raw_json_transform
from griffon.output import (
console,
cprint,
generate_affects,
generate_normalised_results,
generate_result_tree,
raw_json_transform,
)
from griffon.services import QueryService, core_queries # , exp

logger = logging.getLogger("griffon")
Expand Down Expand Up @@ -382,18 +389,20 @@ def get_product_contain_component(

# generate affects
output = raw_json_transform(q, True)
ordered_results = sorted(output["results"], key=lambda d: d["product_stream"])
affects = []
product_versions = sorted(
list(set([item["product_version"] for item in ordered_results]))

exclude_products = []
if get_config_option(ctx.obj["PROFILE"], "exclude"):
exclude_products = get_config_option(ctx.obj["PROFILE"], "exclude").split("\n")
exclude_components = []
if get_config_option(ctx.obj["PROFILE"], "exclude_components"):
exclude_components = get_config_option(
ctx.obj["PROFILE"], "exclude_components"
).split("\n")
normalised_results = generate_normalised_results(
output, exclude_products, exclude_components
)
for pv in product_versions:
names = [item["name"] for item in ordered_results if pv == item["product_version"]]
names = list(set(names))
for name in names:
affects.append(
{"product_version": pv, "component_name": name, "operation": "add"}
)
result_tree = generate_result_tree(normalised_results)
affects = generate_affects(ctx, result_tree, exclude_components, "add", format="json")

# attempt to import sfm2client module
try:
Expand Down
193 changes: 114 additions & 79 deletions griffon/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,115 @@ def text_output_product_summary(ctx, output, format, exclude_products, no_wrap=F
ctx.exit()


def generate_normalised_results(output, exclude_products, exclude_components):
normalised_results = list()
if "results" in output:
for item in output["results"]:
for ps in item["product_streams"]:
if ps["product_versions"][0]["name"] not in exclude_products:
if not any([match in item["name"] for match in exclude_components]):
c = {
"product_version": ps["product_versions"][0]["name"],
"product_stream": ps.get("name"),
"namespace": item.get("namespace"),
"name": item.get("name"),
"nvr": item.get("nvr"),
"type": item.get("type"),
"arch": item.get("arch"),
"version": item.get("version"),
"related_url": item.get("related_url"),
"purl": item.get("purl"),
"sources": item.get("sources"),
"upstreams": item.get("upstreams"),
}
if "software_build" in item:
c["build_source_url"] = item["software_build"].get("source")
normalised_results.append(c)
return normalised_results


def generate_result_tree(normalised_results):
product_versions = sorted(list(set([item["product_version"] for item in normalised_results])))
result_tree = {}
for pv in product_versions:
result_tree[pv] = {}
product_streams = sorted(
list(
set(
[
item["product_stream"]
for item in normalised_results
if item["product_version"] == pv
]
)
)
)
for ps in product_streams:
result_tree[pv][ps] = {}
component_names = sorted(
list(
set(
[
item["name"]
for item in normalised_results
if item["product_stream"] == ps
]
)
)
)
for cn in component_names:
result_tree[pv][ps][cn] = {}
nvrs = [
item
for item in normalised_results
if item["product_stream"] == ps and item["name"] == cn
]

for nvr in nvrs:
result_tree[pv][ps][cn][nvr["nvr"]] = nvr
return result_tree


def generate_affects(
ctx, result_tree, exclude_components, flaw_operation, format="text", no_wrap=False
):
search_component_name = ctx.params["component_name"]
for pv in result_tree.keys():
component_names = set()
for ps in result_tree[pv].keys():
for component_name in result_tree[pv][ps].keys():
for nvr in result_tree[pv][ps][component_name].keys():
source_names = [
source["name"]
for source in result_tree[pv][ps][component_name][nvr]["sources"]
if source["namespace"] == "REDHAT"
]
component_names.update(source_names)
# we should only show component name if both {component name} and {component name-container} exists # noqa
if (
search_component_name in component_names
and f"{search_component_name}-container" in component_names
):
component_names.remove(f"{search_component_name}-container")
if format == "text":
for cn in component_names:
# ensure {component name} is not in profile exclude components enum
if not any([match in cn for match in exclude_components]):
console.print(
f"{pv}/{cn}={flaw_operation}",
no_wrap=no_wrap,
)
else:
affects = []
for cn in component_names:
# ensure {component name} is not in profile exclude components enum
if not any([match in cn for match in exclude_components]):
affects.append(
{"product_version": pv, "component_name": cn, "operation": flaw_operation}
)
return affects


def text_output_products_contain_component(
ctx, output, exclude_products, exclude_components, no_wrap=False
):
Expand All @@ -178,69 +287,10 @@ def text_output_products_contain_component(
# ordered_results = sorted(output["results"], key=lambda d: d["product_stream"])

# first flatten the tree
normalised_results = list()
if "results" in output:
for item in output["results"]:
for ps in item["product_streams"]:
if ps["product_versions"][0]["name"] not in exclude_products:
if not any([match in item["name"] for match in exclude_components]):
c = {
"product_version": ps["product_versions"][0]["name"],
"product_stream": ps.get("name"),
"namespace": item.get("namespace"),
"name": item.get("name"),
"nvr": item.get("nvr"),
"type": item.get("type"),
"arch": item.get("arch"),
"version": item.get("version"),
"related_url": item.get("related_url"),
"purl": item.get("purl"),
"sources": item.get("sources"),
"upstreams": item.get("upstreams"),
}
if "software_build" in item:
c["build_source_url"] = item["software_build"].get("source")
normalised_results.append(c)
product_versions = sorted(
list(set([item["product_version"] for item in normalised_results]))
normalised_results = generate_normalised_results(
output, exclude_products, exclude_components
)
result_tree = {}
for pv in product_versions:
result_tree[pv] = {}
product_streams = sorted(
list(
set(
[
item["product_stream"]
for item in normalised_results
if item["product_version"] == pv
]
)
)
)
for ps in product_streams:
result_tree[pv][ps] = {}
component_names = sorted(
list(
set(
[
item["name"]
for item in normalised_results
if item["product_stream"] == ps
]
)
)
)
for cn in component_names:
result_tree[pv][ps][cn] = {}
nvrs = [
item
for item in normalised_results
if item["product_stream"] == ps and item["name"] == cn
]

for nvr in nvrs:
result_tree[pv][ps][cn][nvr["nvr"]] = nvr
result_tree = generate_result_tree(normalised_results)

# TODO - MAVEN component type will require special handling
if ctx.params["affect_mode"]:
Expand All @@ -254,23 +304,8 @@ def text_output_products_contain_component(
if flaw_mode == "update":
flaw_operation = "update"

for pv in result_tree.keys():
component_names = set()
for ps in result_tree[pv].keys():
component_names.update(result_tree[pv][ps].keys())
# we should only show component name if both {component name} and {component name-container} exists # noqa
if (
search_component_name in component_names
and f"{search_component_name}-container" in component_names
):
component_names.remove(f"{search_component_name}-container")
for cn in component_names:
# ensure {component name} is not in profile exclude components enum
if not any([match in cn for match in exclude_components]):
console.print(
f"{pv}/{cn}={flaw_operation}",
no_wrap=no_wrap,
)
generate_affects(ctx, result_tree, exclude_components, flaw_operation, no_wrap=False)

else:
if ctx.obj["VERBOSE"] == 0: # product_version X component_name
for pv in result_tree.keys():
Expand Down
2 changes: 1 addition & 1 deletion griffon/services/core_queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ def __init__(self, params: dict) -> None:
def execute(self) -> List[Dict[str, Any]]:
results = []
params = {
"include_fields": "link,purl,type,name,related_url,namespace,software_build,nvr,sources.nvr,sources.purl,sources.name,sources.download_url,sources.related_url,upstreams.nvr,upstreams.purl,upstreams.name,upstreams.download_url,upstreams.related_url,release,version,arch,product_streams.product_versions,product_streams.name,product_streams.ofuri", # noqa
"include_fields": "link,purl,type,name,related_url,namespace,software_build,nvr,sources.nvr,sources.purl,sources.name,sources.namespace,sources.download_url,sources.related_url,upstreams.nvr,upstreams.purl,upstreams.name,upstreams.download_url,upstreams.related_url,release,version,arch,product_streams.product_versions,product_streams.name,product_streams.ofuri", # noqa
}

if self.search_latest:
Expand Down
2 changes: 1 addition & 1 deletion requirements/base.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# This file is autogenerated by pip-compile with Python 3.9
# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile --allow-unsafe --generate-hashes requirements/base.in
Expand Down
Loading

0 comments on commit 0c2300c

Please sign in to comment.