Skip to content

Commit 4c44d10

Browse files
committed
fix(comments): preserve dependency change types
1 parent 4797cb9 commit 4c44d10

7 files changed

Lines changed: 126 additions & 67 deletions

File tree

socketsecurity/core/__init__.py

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2157,16 +2157,22 @@ def create_diff_report(
21572157
alerts_in_removed_packages: Dict[str, List[Issue]] = {}
21582158
alerts_in_unchanged_packages: Dict[str, List[Issue]] = {}
21592159

2160-
seen_new_packages = set()
2161-
seen_removed_packages = set()
2160+
seen_packages = {
2161+
"added": set(),
2162+
"updated": set(),
2163+
"removed": set(),
2164+
"replaced": set(),
2165+
}
21622166

21632167
for package_id, package in added_packages.items():
21642168
purl = self.create_purl(package_id, added_packages)
21652169
base_purl = f"{purl.ecosystem}/{purl.name}@{purl.version}"
21662170

2167-
if (not direct_only or package.direct) and base_purl not in seen_new_packages:
2168-
diff.new_packages.append(purl)
2169-
seen_new_packages.add(base_purl)
2171+
change_type = "updated" if package.diffType == "updated" else "added"
2172+
target = diff.updated_packages if change_type == "updated" else diff.new_packages
2173+
if (not direct_only or package.direct) and base_purl not in seen_packages[change_type]:
2174+
target.append(purl)
2175+
seen_packages[change_type].add(base_purl)
21702176

21712177
self.add_package_alerts_to_collection(
21722178
package=package,
@@ -2178,9 +2184,11 @@ def create_diff_report(
21782184
purl = self.create_purl(package_id, removed_packages)
21792185
base_purl = f"{purl.ecosystem}/{purl.name}@{purl.version}"
21802186

2181-
if (not direct_only or package.direct) and base_purl not in seen_removed_packages:
2182-
diff.removed_packages.append(purl)
2183-
seen_removed_packages.add(base_purl)
2187+
change_type = "replaced" if package.diffType == "replaced" else "removed"
2188+
target = diff.replaced_packages if change_type == "replaced" else diff.removed_packages
2189+
if (not direct_only or package.direct) and base_purl not in seen_packages[change_type]:
2190+
target.append(purl)
2191+
seen_packages[change_type].add(base_purl)
21842192

21852193
self.add_package_alerts_to_collection(
21862194
package=package,
@@ -2310,18 +2318,16 @@ def add_purl_capabilities(diff: Diff) -> None:
23102318
Args:
23112319
diff: Diff object to update with capability information
23122320
"""
2313-
new_packages = []
2314-
for purl in diff.new_packages:
2315-
if purl.id in diff.new_capabilities:
2316-
new_purl = Purl(
2317-
**{**purl.__dict__,
2318-
"capabilities": diff.new_capabilities[purl.id]}
2319-
)
2320-
new_packages.append(new_purl)
2321-
else:
2322-
new_packages.append(purl)
2323-
2324-
diff.new_packages = new_packages
2321+
for attribute in ("new_packages", "updated_packages"):
2322+
packages = []
2323+
for purl in getattr(diff, attribute):
2324+
if purl.id in diff.new_capabilities:
2325+
purl = Purl(
2326+
**{**purl.__dict__,
2327+
"capabilities": diff.new_capabilities[purl.id]}
2328+
)
2329+
packages.append(purl)
2330+
setattr(diff, attribute, packages)
23252331

23262332
def add_package_alerts_to_collection(self, package: Package, alerts_collection: dict, packages: dict) -> dict:
23272333
"""

socketsecurity/core/alert_selection.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ def clone_diff_with_selected_alerts(diff: Diff, selected_alerts: List[Issue]) ->
3131
removed_alerts=[],
3232
diff_url=getattr(diff, "diff_url", ""),
3333
new_packages=getattr(diff, "new_packages", []),
34+
updated_packages=getattr(diff, "updated_packages", []),
3435
removed_packages=getattr(diff, "removed_packages", []),
36+
replaced_packages=getattr(diff, "replaced_packages", []),
3537
packages=getattr(diff, "packages", {}),
3638
)
3739
selected_diff.id = getattr(diff, "id", "")

socketsecurity/core/classes.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,9 @@ class Diff:
507507
"""
508508

509509
new_packages: list[Purl]
510+
updated_packages: list[Purl]
510511
removed_packages: list[Purl]
512+
replaced_packages: list[Purl]
511513
packages: dict[str, Package]
512514
new_capabilities: Dict[str, List[str]]
513515
new_alerts: list[Issue]
@@ -525,8 +527,12 @@ def __init__(self, **kwargs):
525527
setattr(self, key, value)
526528
if not hasattr(self, "new_packages"):
527529
self.new_packages = []
530+
if not hasattr(self, "updated_packages"):
531+
self.updated_packages = []
528532
if not hasattr(self, "removed_packages"):
529533
self.removed_packages = []
534+
if not hasattr(self, "replaced_packages"):
535+
self.replaced_packages = []
530536
if not hasattr(self, "new_alerts"):
531537
self.new_alerts = []
532538
if not hasattr(self, "unchanged_alerts"):
@@ -548,8 +554,10 @@ def to_dict(self) -> dict:
548554
"""
549555
return {
550556
"new_packages": [p.to_dict() for p in self.new_packages],
557+
"updated_packages": [p.to_dict() for p in self.updated_packages],
551558
"new_capabilities": self.new_capabilities,
552559
"removed_packages": [p.to_dict() for p in self.removed_packages],
560+
"replaced_packages": [p.to_dict() for p in self.replaced_packages],
553561
"new_alerts": [alert.__dict__ for alert in self.new_alerts],
554562
"unchanged_alerts": [alert.__dict__ for alert in self.unchanged_alerts] if hasattr(self, "unchanged_alerts") else [],
555563
"removed_alerts": [alert.__dict__ for alert in self.removed_alerts] if hasattr(self, "removed_alerts") else [],

socketsecurity/core/messages.py

Lines changed: 52 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1268,51 +1268,58 @@ def create_added_table(diff: Diff, md: MdUtils) -> MdUtils:
12681268
num_of_overview_columns = len(overview_table)
12691269

12701270
count = 0
1271-
for added in diff.new_packages:
1272-
added: Purl # Ensure `added` has scores and relevant attributes.
1273-
1274-
package_url = f"[{added.purl}]({added.url})"
1275-
diff_badge = f"[![+](https://github-app-statics.socket.dev/diff-added.svg)]({added.url})"
1276-
1277-
# Scores dynamically converted to badge URLs and linked
1278-
def score_to_badge(score):
1279-
score_percent = int(score * 100) # Convert to integer percentage
1280-
return f"[![{score_percent}](https://github-app-statics.socket.dev/score-{score_percent}.svg)]({added.url})"
1281-
1282-
def get_score_for_badge(score_name: str) -> float:
1283-
scores = getattr(added, "scores", None)
1284-
if isinstance(scores, dict):
1285-
raw_score = scores.get(score_name)
1286-
else:
1287-
raw_score = getattr(scores, score_name, None) if scores is not None else None
1288-
1289-
if raw_score is None:
1290-
return 1.0
1291-
1292-
score = float(raw_score)
1293-
if score > 1:
1294-
score = score / 100
1295-
return max(0.0, min(score, 1.0))
1296-
1297-
# Generate badges for each score type
1298-
supply_chain_risk_badge = score_to_badge(get_score_for_badge("supplyChain"))
1299-
vulnerability_badge = score_to_badge(get_score_for_badge("vulnerability"))
1300-
quality_badge = score_to_badge(get_score_for_badge("quality"))
1301-
maintenance_badge = score_to_badge(get_score_for_badge("maintenance"))
1302-
license_badge = score_to_badge(get_score_for_badge("license"))
1303-
1304-
# Add the row for this package
1305-
row = [
1306-
diff_badge,
1307-
package_url,
1308-
supply_chain_risk_badge,
1309-
vulnerability_badge,
1310-
quality_badge,
1311-
maintenance_badge,
1312-
license_badge
1313-
]
1314-
overview_table.extend(row)
1315-
count += 1 # Count total packages
1271+
changes = (
1272+
("Added", diff.new_packages),
1273+
("Updated", diff.updated_packages),
1274+
("Removed", diff.removed_packages),
1275+
("Replaced", diff.replaced_packages),
1276+
)
1277+
for change, packages in changes:
1278+
for package in packages:
1279+
package: Purl
1280+
1281+
package_url = f"[{package.purl}]({package.url})"
1282+
diff_badge = f"**{change}**"
1283+
1284+
# Scores dynamically converted to badge URLs and linked
1285+
def score_to_badge(score):
1286+
score_percent = int(score * 100) # Convert to integer percentage
1287+
return f"[![{score_percent}](https://github-app-statics.socket.dev/score-{score_percent}.svg)]({package.url})"
1288+
1289+
def get_score_for_badge(score_name: str) -> float:
1290+
scores = getattr(package, "scores", None)
1291+
if isinstance(scores, dict):
1292+
raw_score = scores.get(score_name)
1293+
else:
1294+
raw_score = getattr(scores, score_name, None) if scores is not None else None
1295+
1296+
if raw_score is None:
1297+
return 1.0
1298+
1299+
score = float(raw_score)
1300+
if score > 1:
1301+
score = score / 100
1302+
return max(0.0, min(score, 1.0))
1303+
1304+
# Generate badges for each score type
1305+
supply_chain_risk_badge = score_to_badge(get_score_for_badge("supplyChain"))
1306+
vulnerability_badge = score_to_badge(get_score_for_badge("vulnerability"))
1307+
quality_badge = score_to_badge(get_score_for_badge("quality"))
1308+
maintenance_badge = score_to_badge(get_score_for_badge("maintenance"))
1309+
license_badge = score_to_badge(get_score_for_badge("license"))
1310+
1311+
# Add the row for this package
1312+
row = [
1313+
diff_badge,
1314+
package_url,
1315+
supply_chain_risk_badge,
1316+
vulnerability_badge,
1317+
quality_badge,
1318+
maintenance_badge,
1319+
license_badge
1320+
]
1321+
overview_table.extend(row)
1322+
count += 1
13161323

13171324
# Calculate total rows for table
13181325
num_of_overview_rows = count + 1 # Include header row

socketsecurity/socketcli.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -850,10 +850,15 @@ def _is_unprocessed(c):
850850
if not new_security_comment:
851851
log.debug("Security issue comment disabled, or no alerts and none to update")
852852

853-
# FIXME: diff.new_packages is never populated, neither is removed_packages
853+
has_dependency_changes = any((
854+
diff.new_packages,
855+
diff.updated_packages,
856+
diff.removed_packages,
857+
diff.replaced_packages,
858+
))
854859
new_overview_comment = should_write_comment(
855860
config.disable_overview,
856-
len(diff.new_packages) > 0,
861+
has_dependency_changes,
857862
update_old_overview_comment,
858863
)
859864
if not new_overview_comment:

tests/core/test_diff_generation.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,19 @@ def test_create_diff_report(core, diff_input):
9595
assert hasattr(dp3_purl, "capabilities")
9696
assert "Environment Variables" in dp3_purl.capabilities
9797

98+
99+
def test_create_diff_report_preserves_package_change_types(core, diff_input):
100+
added, removed = diff_input
101+
added["dp3"].diffType = "updated"
102+
removed["dp2"].diffType = "replaced"
103+
104+
diff = core.create_diff_report(added, removed)
105+
106+
assert {package.id for package in diff.new_packages} == {"dp4"}
107+
assert {package.id for package in diff.updated_packages} == {"dp3"}
108+
assert diff.removed_packages == []
109+
assert {package.id for package in diff.replaced_packages} == {"dp2"}
110+
98111
def create_input(core):
99112
# Get two different scans to compare
100113
head_scan = core.get_full_scan("head")

tests/unit/test_dependency_overview.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,21 @@ def test_dependency_overview_template_defaults_missing_or_null_scores(tmp_path,
6565
assert "score-42.svg" in comment
6666
assert "score-100.svg" in comment
6767
assert "score-10000.svg" not in comment
68+
69+
70+
def test_dependency_overview_labels_each_change_type(tmp_path, monkeypatch):
71+
monkeypatch.chdir(tmp_path)
72+
diff = Diff(
73+
id="test-diff",
74+
diff_url="https://socket.dev/test-diff",
75+
new_packages=[_make_purl("added", {})],
76+
updated_packages=[_make_purl("updated", {})],
77+
removed_packages=[_make_purl("removed", {})],
78+
replaced_packages=[_make_purl("replaced", {})],
79+
new_alerts=[],
80+
)
81+
82+
comment = Messages.dependency_overview_template(diff)
83+
84+
for change in ("Added", "Updated", "Removed", "Replaced"):
85+
assert f"**{change}**" in comment

0 commit comments

Comments
 (0)