Skip to content

Commit ec01185

Browse files
authored
Fixed license generation using the purl endpoint (#89)
Updated the method of how to generate the license attribution if enabled
1 parent 82d300b commit ec01185

File tree

5 files changed

+73
-17
lines changed

5 files changed

+73
-17
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
66

77
[project]
88
name = "socketsecurity"
9-
version = "2.1.9"
9+
version = "2.1.10"
1010
requires-python = ">= 3.10"
1111
license = {"file" = "LICENSE"}
1212
dependencies = [

socketsecurity/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
__author__ = 'socket.dev'
2-
__version__ = '2.1.9'
2+
__version__ = '2.1.10'

socketsecurity/core/__init__.py

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ def get_package_license_text(self, package: Package) -> str:
467467

468468
license_raw = package.license
469469
data = self.sdk.licensemetadata.post([license_raw], {'includetext': 'true'})
470-
license_str = data.data[0].license if data and len(data) == 1 else ""
470+
license_str = data[0].get('text') if data and len(data) == 1 else ""
471471
return license_str
472472

473473
def get_repo_info(self, repo_slug: str, default_branch: str = "socket-default-branch") -> RepositoryInfo:
@@ -543,13 +543,41 @@ def update_package_values(pkg: Package) -> Package:
543543
pkg.url += f"/{pkg.name}/overview/{pkg.version}"
544544
return pkg
545545

546-
def get_added_and_removed_packages(self, head_full_scan_id: str, new_full_scan_id: str) -> Tuple[Dict[str, Package], Dict[str, Package]]:
546+
def get_license_text_via_purl(self, packages: dict[str, Package]) -> dict:
547+
components = []
548+
for purl in packages:
549+
full_purl = f"pkg:/{purl}"
550+
components.append({"purl": full_purl})
551+
results = self.sdk.purl.post(
552+
license=True,
553+
components=components,
554+
licenseattrib=True,
555+
licensedetails=True
556+
)
557+
purl_packages = []
558+
for result in results:
559+
ecosystem = result["type"]
560+
name = result["name"]
561+
package_version = result["version"]
562+
licenseDetails = result.get("licenseDetails")
563+
licenseAttrib = result.get("licenseAttrib")
564+
purl = f"{ecosystem}/{name}@{package_version}"
565+
if purl not in purl_packages:
566+
packages[purl].licenseAttrib = licenseAttrib
567+
packages[purl].licenseDetails = licenseDetails
568+
return packages
569+
570+
def get_added_and_removed_packages(
571+
self,
572+
head_full_scan_id: str,
573+
new_full_scan_id: str
574+
) -> Tuple[Dict[str, Package], Dict[str, Package], Dict[str, Package]]:
547575
"""
548576
Get packages that were added and removed between scans.
549577
550578
Args:
551-
head_full_scan: Previous scan (may be None if first scan)
552-
head_full_scan_id: New scan just created
579+
head_full_scan_id: Previous scan (maybe None if first scan)
580+
new_full_scan_id: New scan just created
553581
554582
Returns:
555583
Tuple of (added_packages, removed_packages) dictionaries
@@ -579,20 +607,36 @@ def get_added_and_removed_packages(self, head_full_scan_id: str, new_full_scan_i
579607

580608
added_artifacts = diff_report.artifacts.added + diff_report.artifacts.updated
581609
removed_artifacts = diff_report.artifacts.removed + diff_report.artifacts.replaced
610+
unchanged_artifacts = diff_report.artifacts.unchanged
582611

583612
added_packages: Dict[str, Package] = {}
584613
removed_packages: Dict[str, Package] = {}
585-
614+
packages: Dict[str, Package] = {}
586615
for artifact in added_artifacts:
587616
try:
588617
pkg = Package.from_diff_artifact(asdict(artifact))
589618
pkg = Core.update_package_values(pkg)
590619
added_packages[artifact.id] = pkg
620+
full_purl = f"{pkg.type}/{pkg.purl}"
621+
if full_purl not in packages:
622+
packages[full_purl] = pkg
591623
except KeyError:
592624
log.error(f"KeyError: Could not create package from added artifact {artifact.id}")
593625
log.error(f"Artifact details - name: {artifact.name}, version: {artifact.version}")
594626
log.error("No matching packages found in new_full_scan")
595627

628+
for artifact in unchanged_artifacts:
629+
try:
630+
pkg = Package.from_diff_artifact(asdict(artifact))
631+
pkg = Core.update_package_values(pkg)
632+
full_purl = f"{pkg.type}/{pkg.purl}"
633+
if full_purl not in packages:
634+
packages[full_purl] = pkg
635+
except KeyError:
636+
log.error(f"KeyError: Could not create package from unchanged artifact {artifact.id}")
637+
log.error(f"Artifact details - name: {artifact.name}, version: {artifact.version}")
638+
log.error("No matching packages found in new_full_scan")
639+
596640
for artifact in removed_artifacts:
597641
try:
598642
pkg = Package.from_diff_artifact(asdict(artifact))
@@ -605,7 +649,8 @@ def get_added_and_removed_packages(self, head_full_scan_id: str, new_full_scan_i
605649
log.error(f"Artifact details - name: {artifact.name}, version: {artifact.version}")
606650
log.error("No matching packages found in head_full_scan")
607651

608-
return added_packages, removed_packages
652+
packages = self.get_license_text_via_purl(packages)
653+
return added_packages, removed_packages, packages
609654

610655
def create_new_diff(
611656
self,
@@ -665,9 +710,14 @@ def create_new_diff(
665710
scans_ready = self.check_full_scans_status(head_full_scan_id, new_full_scan.id)
666711
if scans_ready is False:
667712
log.error(f"Full scans did not complete within {self.config.timeout} seconds")
668-
added_packages, removed_packages = self.get_added_and_removed_packages(head_full_scan_id, new_full_scan.id)
713+
(
714+
added_packages,
715+
removed_packages,
716+
packages
717+
) = self.get_added_and_removed_packages(head_full_scan_id, new_full_scan.id)
669718

670719
diff = self.create_diff_report(added_packages, removed_packages)
720+
diff.packages = packages
671721

672722
base_socket = "https://socket.dev/dashboard/org"
673723
diff.id = new_full_scan.id
@@ -676,6 +726,7 @@ def create_new_diff(
676726
if not params.include_license_details:
677727
report_url += "?include_license_details=false"
678728
diff.report_url = report_url
729+
diff.new_scan_id = new_full_scan.id
679730

680731
if head_full_scan_id is not None:
681732
diff.diff_url = f"{base_socket}/{self.config.org_slug}/diff/{head_full_scan_id}/{diff.id}"

socketsecurity/core/classes.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ class Package():
132132

133133
# Artifact-specific fields
134134
licenseDetails: Optional[list] = None
135+
licenseAttrib: Optional[List] = None
135136

136137

137138
@classmethod
@@ -469,14 +470,15 @@ class Diff:
469470
"""
470471

471472
new_packages: list[Purl]
472-
new_capabilities: Dict[str, List[str]]
473473
removed_packages: list[Purl]
474+
packages: dict[str, Package]
475+
new_capabilities: Dict[str, List[str]]
474476
new_alerts: list[Issue]
475477
id: str
476478
sbom: str
477-
packages: dict[str, Package]
478479
report_url: str
479480
diff_url: str
481+
new_scan_id: str
480482

481483
def __init__(self, **kwargs):
482484
if kwargs:

socketsecurity/socketcli.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from socketdev import socketdev
88
from socketdev.fullscans import FullScanParams
99

10+
from core.exceptions import APIFailure
1011
from socketsecurity.config import CliConfig
1112
from socketsecurity.core import Core
1213
from socketsecurity.core.classes import Diff
@@ -260,22 +261,24 @@ def main_code():
260261
diff = core.create_new_diff(config.target_path, params, no_change=should_skip_scan)
261262
output_handler.handle_output(diff)
262263

263-
# Handle license generation
264+
# Handle license generation
264265
if diff is not None and config.generate_license:
265266
all_packages = {}
266-
for package_id in diff.packages:
267-
package = diff.packages[package_id]
267+
for purl in diff.packages:
268+
package = diff.packages[purl]
268269
output = {
269-
"id": package_id,
270+
"id": package.id,
270271
"name": package.name,
271272
"version": package.version,
272273
"ecosystem": package.type,
273274
"direct": package.direct,
274275
"url": package.url,
275276
"license": package.license,
276-
"license_text": package.license_text
277+
"licenseDetails": package.licenseDetails,
278+
"licenseAttrib": package.licenseAttrib,
279+
"purl": package.purl,
277280
}
278-
all_packages[package_id] = output
281+
all_packages[package.id] = output
279282
license_file = f"{config.repo}"
280283
if config.branch:
281284
license_file += f"_{config.branch}"

0 commit comments

Comments
 (0)