Skip to content

Commit 1c8b20e

Browse files
committed
Fixes for diff logic
1 parent 7b7089e commit 1c8b20e

File tree

3 files changed

+90
-48
lines changed

3 files changed

+90
-48
lines changed

Pipfile.lock

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

socketsecurity/core/__init__.py

Lines changed: 63 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
1-
import base64
2-
import json
31
import logging
42
import time
53
from dataclasses import asdict
64
from glob import glob
75
from pathlib import PurePath
8-
from typing import BinaryIO, Dict, List, Optional, Tuple
9-
6+
from typing import BinaryIO, Dict, List, Tuple
107
from socketdev import socketdev
118
from socketdev.fullscans import (
129
FullScanParams,
13-
SocketArtifact,
14-
DiffArtifact,
10+
SocketArtifact
1511
)
1612
from socketdev.org import Organization
1713
from socketdev.repos import RepositoryInfo
@@ -27,8 +23,9 @@
2723
Purl,
2824
)
2925
from socketsecurity.core.exceptions import (
30-
APIResourceNotFound,
26+
APIResourceNotFound
3127
)
28+
from socketdev.exceptions import APIFailure
3229
from socketsecurity.core.licenses import Licenses
3330

3431
from .socket_config import SocketConfig
@@ -216,7 +213,7 @@ def load_files_for_sending(files: List[str], workspace: str) -> List[Tuple[str,
216213

217214
return send_files
218215

219-
def create_full_scan(self, files: List[str], params: FullScanParams) -> FullScan:
216+
def create_full_scan(self, files: List[str], params: FullScanParams, has_head_scan: bool = False) -> FullScan:
220217
"""
221218
Creates a new full scan via the Socket API.
222219
@@ -236,10 +233,10 @@ def create_full_scan(self, files: List[str], params: FullScanParams) -> FullScan
236233
raise Exception(f"Error creating full scan: {res.message}, status: {res.status}")
237234

238235
full_scan = FullScan(**asdict(res.data))
239-
240-
full_scan_artifacts_dict = self.get_sbom_data(full_scan.id)
241-
full_scan.sbom_artifacts = self.get_sbom_data_list(full_scan_artifacts_dict)
242-
full_scan.packages = self.create_packages_dict(full_scan.sbom_artifacts)
236+
if not has_head_scan:
237+
full_scan_artifacts_dict = self.get_sbom_data(full_scan.id)
238+
full_scan.sbom_artifacts = self.get_sbom_data_list(full_scan_artifacts_dict)
239+
full_scan.packages = self.create_packages_dict(full_scan.sbom_artifacts)
243240

244241
create_full_end = time.time()
245242
total_time = create_full_end - create_full_start
@@ -317,24 +314,37 @@ def get_package_license_text(self, package: Package) -> str:
317314

318315
return ""
319316

320-
def get_repo_info(self, repo_slug: str) -> RepositoryInfo:
317+
def get_repo_info(self, repo_slug: str, default_branch: str = "socket-default-branch") -> RepositoryInfo:
321318
"""
322319
Gets repository information from the Socket API.
323320
324321
Args:
325322
repo_slug: Repository slug to get info for
323+
default_branch: Default branch string to use if the repo doesn't exist
326324
327325
Returns:
328326
RepositoryInfo object
329327
330328
Raises:
331329
Exception: If API request fails
332330
"""
333-
response = self.sdk.repos.repo(self.config.org_slug, repo_slug)
334-
if not response.success:
335-
log.error(f"Failed to get repository: {response.status}")
336-
log.error(response.message)
337-
raise Exception(f"Failed to get repository info: {response.status}, message: {response.message}")
331+
try:
332+
response = self.sdk.repos.repo(self.config.org_slug, repo_slug)
333+
if not response.success:
334+
log.error(f"Failed to get repository: {response.status}")
335+
log.error(response.message)
336+
# raise Exception(f"Failed to get repository info: {response.status}, message: {response.message}")
337+
except APIFailure:
338+
log.warning(f"Failed to get repository {repo_slug}, attempting to create it")
339+
create_response = self.sdk.repos.post(self.config.org_slug, name=repo_slug, default_branch=default_branch)
340+
if not create_response.success:
341+
log.error(f"Failed to create repository: {create_response.status}")
342+
log.error(create_response.message)
343+
raise Exception(
344+
f"Failed to create repository: {create_response.status}, message: {create_response.message}"
345+
)
346+
else:
347+
return create_response.data
338348
return response.data
339349

340350
def get_head_scan_for_repo(self, repo_slug: str) -> str:
@@ -350,24 +360,36 @@ def get_head_scan_for_repo(self, repo_slug: str) -> str:
350360
repo_info = self.get_repo_info(repo_slug)
351361
return repo_info.head_full_scan_id if repo_info.head_full_scan_id else None
352362

353-
def get_added_and_removed_packages(self, head_full_scan: Optional[FullScan], new_full_scan: FullScan) -> Tuple[Dict[str, Package], Dict[str, Package]]:
363+
@staticmethod
364+
def update_package_values(pkg: Package) -> Package:
365+
pkg.purl = f"{pkg.name}@{pkg.version}"
366+
pkg.url = f"https://socket.dev/{pkg.type}/package"
367+
if pkg.namespace:
368+
pkg.purl = f"{pkg.namespace}/{pkg.purl}"
369+
pkg.url += f"/{pkg.namespace}"
370+
pkg.url += f"/{pkg.name}/overview/{pkg.version}"
371+
return pkg
372+
373+
def get_added_and_removed_packages(self, head_full_scan_id: str, new_full_scan: FullScan) -> Tuple[Dict[str, Package], Dict[str, Package]]:
354374
"""
355375
Get packages that were added and removed between scans.
356376
357377
Args:
358378
head_full_scan: Previous scan (may be None if first scan)
359-
new_full_scan: New scan just created
379+
head_full_scan_id: New scan just created
360380
361381
Returns:
362382
Tuple of (added_packages, removed_packages) dictionaries
363383
"""
364-
if head_full_scan is None:
384+
if head_full_scan_id is None:
365385
log.info(f"No head scan found. New scan ID: {new_full_scan.id}")
366386
return new_full_scan.packages, {}
367387

368-
log.info(f"Comparing scans - Head scan ID: {head_full_scan.id}, New scan ID: {new_full_scan.id}")
369-
diff_report = self.sdk.fullscans.stream_diff(self.config.org_slug, head_full_scan.id, new_full_scan.id).data
370-
388+
log.info(f"Comparing scans - Head scan ID: {head_full_scan_id}, New scan ID: {new_full_scan.id}")
389+
diff_start = time.time()
390+
diff_report = self.sdk.fullscans.stream_diff(self.config.org_slug, head_full_scan_id, new_full_scan.id).data
391+
diff_end = time.time()
392+
log.info(f"Diff Report Gathered in {diff_end - diff_start:.2f} seconds")
371393
log.info(f"Diff report artifact counts:")
372394
log.info(f"Added: {len(diff_report.artifacts.added)}")
373395
log.info(f"Removed: {len(diff_report.artifacts.removed)}")
@@ -384,32 +406,24 @@ def get_added_and_removed_packages(self, head_full_scan: Optional[FullScan], new
384406
for artifact in added_artifacts:
385407
try:
386408
pkg = Package.from_diff_artifact(asdict(artifact))
409+
pkg = Core.update_package_values(pkg)
387410
added_packages[artifact.id] = pkg
388411
except KeyError:
389412
log.error(f"KeyError: Could not create package from added artifact {artifact.id}")
390413
log.error(f"Artifact details - name: {artifact.name}, version: {artifact.version}")
391-
matches = [p for p in new_full_scan.packages.values() if p.name == artifact.name and p.version == artifact.version]
392-
if matches:
393-
log.error(f"Found {len(matches)} packages with matching name/version:")
394-
for m in matches:
395-
log.error(f" ID: {m.id}, name: {m.name}, version: {m.version}")
396-
else:
397-
log.error("No matching packages found in new_full_scan")
414+
log.error("No matching packages found in new_full_scan")
398415

399416
for artifact in removed_artifacts:
400417
try:
401418
pkg = Package.from_diff_artifact(asdict(artifact))
419+
pkg = Core.update_package_values(pkg)
420+
if pkg.namespace:
421+
pkg.purl += f"{pkg.namespace}/{pkg.purl}"
402422
removed_packages[artifact.id] = pkg
403423
except KeyError:
404424
log.error(f"KeyError: Could not create package from removed artifact {artifact.id}")
405425
log.error(f"Artifact details - name: {artifact.name}, version: {artifact.version}")
406-
matches = [p for p in head_full_scan.packages.values() if p.name == artifact.name and p.version == artifact.version]
407-
if matches:
408-
log.error(f"Found {len(matches)} packages with matching name/version:")
409-
for m in matches:
410-
log.error(f" ID: {m.id}, name: {m.name}, version: {m.version}")
411-
else:
412-
log.error("No matching packages found in head_full_scan")
426+
log.error("No matching packages found in head_full_scan")
413427

414428
return added_packages, removed_packages
415429

@@ -439,32 +453,33 @@ def create_new_diff(
439453
if not files:
440454
return Diff(id="no_diff_id")
441455

442-
head_full_scan_id = None
443-
444456
try:
445457
# Get head scan ID
446458
head_full_scan_id = self.get_head_scan_for_repo(params.repo)
459+
has_head_scan = True
447460
except APIResourceNotFound:
448461
head_full_scan_id = None
462+
has_head_scan = False
449463

450464
# Create new scan
465+
params.include_license_details = False
451466
new_scan_start = time.time()
452-
new_full_scan = self.create_full_scan(files_for_sending, params)
467+
new_full_scan = self.create_full_scan(files_for_sending, params, has_head_scan)
453468
new_scan_end = time.time()
454469
log.info(f"Total time to create new full scan: {new_scan_end - new_scan_start:.2f}")
455470

456471

457-
head_full_scan = None
458-
if head_full_scan_id:
459-
head_full_scan = self.get_full_scan(head_full_scan_id)
472+
# head_full_scan = None
473+
# if head_full_scan_id:
474+
# head_full_scan = self.get_full_scan(head_full_scan_id)
460475

461-
added_packages, removed_packages = self.get_added_and_removed_packages(head_full_scan, new_full_scan)
476+
added_packages, removed_packages = self.get_added_and_removed_packages(head_full_scan_id, new_full_scan)
462477

463478
diff = self.create_diff_report(added_packages, removed_packages)
464479

465480
base_socket = "https://socket.dev/dashboard/org"
466481
diff.id = new_full_scan.id
467-
diff.report_url = f"{base_socket}/{self.config.org_slug}/sbom/{diff.id}"
482+
diff.report_url = f"{base_socket}/{self.config.org_slug}/sbom/{diff.id}?include_license_details=false"
468483
if head_full_scan_id is not None:
469484
diff.diff_url = f"{base_socket}/{self.config.org_slug}/diff/{diff.id}/{head_full_scan_id}"
470485
else:
@@ -609,7 +624,8 @@ def get_source_data(package: Package, packages: dict) -> list:
609624
source = (top_purl, manifests)
610625
introduced_by.append(source)
611626
else:
612-
log.debug(f"Unable to get top level package info for {top_id}")
627+
pass
628+
# log.debug(f"Unable to get top level package info for {top_id}")
613629
return introduced_by
614630

615631
@staticmethod

socketsecurity/core/classes.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,13 +115,18 @@ class Package(SocketArtifactLink):
115115
author: List[str] = field(default_factory=list)
116116
size: Optional[int] = None
117117
license: Optional[str] = None
118+
namespace: Optional[str] = None
118119

119120
# Package-specific fields
120121
license_text: str = ""
121122
purl: str = ""
122123
transitives: int = 0
123124
url: str = ""
124125

126+
# Artifact-specific fields
127+
licenseDetails: Optional[list] = None
128+
129+
125130
@classmethod
126131
def from_socket_artifact(cls, data: dict) -> "Package":
127132
"""
@@ -187,7 +192,8 @@ def from_diff_artifact(cls, data: dict) -> "Package":
187192
direct=ref.get("direct", False),
188193
manifestFiles=ref.get("manifestFiles", []),
189194
dependencies=ref.get("dependencies"),
190-
artifact=ref.get("artifact")
195+
artifact=ref.get("artifact"),
196+
namespace=data.get('namespace', None)
191197
)
192198

193199
class Issue:

0 commit comments

Comments
 (0)