Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 73e1ce2

Browse files
committed
Fixed logic for removed dependencies triggering dependency overview and fixed regex expander
1 parent e039fb7 commit 73e1ce2

File tree

4 files changed

+77
-97
lines changed

4 files changed

+77
-97
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.4"
9+
version = "2.1.5"
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.4'
2+
__version__ = '2.1.5'

‎socketsecurity/core/__init__.py‎

Lines changed: 74 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -133,25 +133,40 @@ def create_sbom_output(self, diff: Diff) -> dict:
133133
@staticmethod
134134
def expand_brace_pattern(pattern: str) -> List[str]:
135135
"""
136-
Expands brace expressions (e.g., {a,b,c}) into separate patterns.
137-
"""
138-
brace_regex = re.compile(r"\{([^{}]+)\}")
139-
140-
# Expand all brace groups
141-
expanded_patterns = [pattern]
142-
while any("{" in p for p in expanded_patterns):
143-
new_patterns = []
144-
for pat in expanded_patterns:
145-
match = brace_regex.search(pat)
146-
if match:
147-
options = match.group(1).split(",") # Extract values inside {}
148-
prefix, suffix = pat[:match.start()], pat[match.end():]
149-
new_patterns.extend([prefix + opt + suffix for opt in options])
150-
else:
151-
new_patterns.append(pat)
152-
expanded_patterns = new_patterns
153-
154-
return expanded_patterns
136+
Recursively expands brace expressions (e.g., {a,b,c}) into separate patterns, supporting nested braces.
137+
"""
138+
def recursive_expand(pat: str) -> List[str]:
139+
stack = []
140+
for i, c in enumerate(pat):
141+
if c == '{':
142+
stack.append(i)
143+
elif c == '}' and stack:
144+
start = stack.pop()
145+
if not stack:
146+
# Found the outermost pair
147+
before = pat[:start]
148+
after = pat[i+1:]
149+
inner = pat[start+1:i]
150+
# Split on commas not inside nested braces
151+
options = []
152+
depth = 0
153+
last = 0
154+
for j, ch in enumerate(inner):
155+
if ch == '{':
156+
depth += 1
157+
elif ch == '}':
158+
depth -= 1
159+
elif ch == ',' and depth == 0:
160+
options.append(inner[last:j])
161+
last = j+1
162+
options.append(inner[last:])
163+
results = []
164+
for opt in options:
165+
expanded = before + opt + after
166+
results.extend(recursive_expand(expanded))
167+
return results
168+
return [pat]
169+
return recursive_expand(pattern)
155170

156171
@staticmethod
157172
def is_excluded(file_path: str, excluded_dirs: Set[str]) -> bool:
@@ -176,13 +191,7 @@ def find_files(self, path: str) -> List[str]:
176191
files: Set[str] = set()
177192

178193
# Get supported patterns from the API
179-
try:
180-
patterns = self.get_supported_patterns()
181-
except Exception as e:
182-
log.error(f"Error getting supported patterns from API: {e}")
183-
log.warning("Falling back to local patterns")
184-
from .utils import socket_globs as fallback_patterns
185-
patterns = fallback_patterns
194+
patterns = self.get_supported_patterns()
186195

187196
for ecosystem in patterns:
188197
if ecosystem in self.config.excluded_ecosystems:
@@ -425,7 +434,7 @@ def create_packages_dict(self, sbom_artifacts: list[SocketArtifact]) -> dict[str
425434
packages = {}
426435
top_level_count = {}
427436
for artifact in sbom_artifacts:
428-
package = Package.from_diff_artifact(artifact.__dict__)
437+
package = Package.from_socket_artifact(asdict(artifact))
429438
if package.id in packages:
430439
print("Duplicate package?")
431440
else:
@@ -534,44 +543,22 @@ def update_package_values(pkg: Package) -> Package:
534543
pkg.url += f"/{pkg.name}/overview/{pkg.version}"
535544
return pkg
536545

537-
def get_added_and_removed_packages(
538-
self,
539-
head_full_scan_id: str,
540-
new_full_scan_id: str,
541-
merge: bool = False,
542-
external_href: str = None,
543-
) -> Tuple[Dict[str, Package], Dict[str, Package], str, str]:
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]]:
544547
"""
545548
Get packages that were added and removed between scans.
546549
547550
Args:
548-
head_full_scan_id: Previous scan
549-
new_full_scan_id: New scan just created
550-
merge: Whether the scan is merged into the default branch
551-
external_href: External reference
551+
head_full_scan: Previous scan (may be None if first scan)
552+
head_full_scan_id: New scan just created
553+
552554
Returns:
553555
Tuple of (added_packages, removed_packages) dictionaries
554556
"""
555557

556558
log.info(f"Comparing scans - Head scan ID: {head_full_scan_id}, New scan ID: {new_full_scan_id}")
557559
diff_start = time.time()
558560
try:
559-
params = {
560-
"before": head_full_scan_id,
561-
"after": new_full_scan_id,
562-
"description": f"Diff scan between head {head_full_scan_id} and new {new_full_scan_id} scans",
563-
"merge": merge,
564-
}
565-
if external_href:
566-
params["external_href"] = external_href
567-
new_diff_scan = self.sdk.diffscans.create_from_ids(self.config.org_slug, params)
568-
data = new_diff_scan.get("diff_scan", {})
569-
diff_scan_id = data.get("id")
570-
if not diff_scan_id:
571-
log.error(f"Failed to get diff scan ID for {new_full_scan_id}")
572-
log.error(new_diff_scan)
573-
sys.exit(1)
574-
diff_report = self.sdk.diffscans.get(self.config.org_slug, diff_scan_id)
561+
diff_report = self.sdk.fullscans.stream_diff(self.config.org_slug, head_full_scan_id, new_full_scan_id, use_types=True).data
575562
except APIFailure as e:
576563
log.error(f"API Error: {e}")
577564
sys.exit(1)
@@ -581,63 +568,44 @@ def get_added_and_removed_packages(
581568
log.error(f"Stack trace:\n{traceback.format_exc()}")
582569
raise
583570

584-
diff_data = diff_report.get("diff_scan", {})
585571
diff_end = time.time()
586-
diff_url = diff_data.get("html_url")
587-
after_data = diff_data.get("after_full_scan")
588-
if after_data:
589-
new_full_scan_url = after_data.get("html_url")
590-
else:
591-
new_full_scan_url = ""
592-
artifacts = diff_data.get("artifacts", {})
593-
added = artifacts.get("added", [])
594-
removed = artifacts.get("removed", [])
595-
unchanged = artifacts.get("unchanged", [])
596-
replaced = artifacts.get("replaced", [])
597-
updated = artifacts.get("updated", [])
598572
log.info(f"Diff Report Gathered in {diff_end - diff_start:.2f} seconds")
599573
log.info("Diff report artifact counts:")
600-
log.info(f"Added: {len(added)}")
601-
log.info(f"Removed: {len(removed)}")
602-
log.info(f"Unchanged: {len(unchanged)}")
603-
log.info(f"Replaced: {len(replaced)}")
604-
log.info(f"Updated: {len(updated)}")
574+
log.info(f"Added: {len(diff_report.artifacts.added)}")
575+
log.info(f"Removed: {len(diff_report.artifacts.removed)}")
576+
log.info(f"Unchanged: {len(diff_report.artifacts.unchanged)}")
577+
log.info(f"Replaced: {len(diff_report.artifacts.replaced)}")
578+
log.info(f"Updated: {len(diff_report.artifacts.updated)}")
605579

606-
added_artifacts = added + updated
607-
removed_artifacts = removed
580+
added_artifacts = diff_report.artifacts.added + diff_report.artifacts.updated
581+
removed_artifacts = diff_report.artifacts.removed+diff_report.artifacts.replaced
608582

609583
added_packages: Dict[str, Package] = {}
610584
removed_packages: Dict[str, Package] = {}
611585

612586
for artifact in added_artifacts:
613-
artifact_id = artifact.get("id")
614-
artifact_name = artifact.get("name")
615-
artifact_version = artifact.get("version")
616587
try:
617-
pkg = Package.from_diff_artifact(artifact)
588+
pkg = Package.from_diff_artifact(asdict(artifact))
618589
pkg = Core.update_package_values(pkg)
619-
added_packages[pkg.id] = pkg
590+
added_packages[artifact.id] = pkg
620591
except KeyError:
621-
log.error(f"KeyError: Could not create package from added artifact {artifact_id}")
622-
log.error(f"Artifact details - name: {artifact_name}, version: {artifact_version}")
592+
log.error(f"KeyError: Could not create package from added artifact {artifact.id}")
593+
log.error(f"Artifact details - name: {artifact.name}, version: {artifact.version}")
623594
log.error("No matching packages found in new_full_scan")
624595

625596
for artifact in removed_artifacts:
626-
artifact_id = artifact.get("id")
627-
artifact_name = artifact.get("name")
628-
artifact_version = artifact.get("version")
629597
try:
630-
pkg = Package.from_diff_artifact(artifact)
598+
pkg = Package.from_diff_artifact(asdict(artifact))
631599
pkg = Core.update_package_values(pkg)
632600
if pkg.namespace:
633601
pkg.purl += f"{pkg.namespace}/{pkg.purl}"
634-
removed_packages[pkg.id] = pkg
602+
removed_packages[artifact.id] = pkg
635603
except KeyError:
636-
log.error(f"KeyError: Could not create package from removed artifact {artifact_id}")
637-
log.error(f"Artifact details - name: {artifact_name}, version: {artifact_version}")
604+
log.error(f"KeyError: Could not create package from removed artifact {artifact.id}")
605+
log.error(f"Artifact details - name: {artifact.name}, version: {artifact.version}")
638606
log.error("No matching packages found in head_full_scan")
639607

640-
return added_packages, removed_packages, diff_url, new_full_scan_url
608+
return added_packages, removed_packages
641609

642610
def create_new_diff(
643611
self,
@@ -683,6 +651,7 @@ def create_new_diff(
683651
try:
684652
new_scan_start = time.time()
685653
new_full_scan = self.create_full_scan(files_for_sending, params)
654+
new_full_scan.sbom_artifacts = self.get_sbom_data(new_full_scan.id)
686655
new_scan_end = time.time()
687656
log.info(f"Total time to create new full scan: {new_scan_end - new_scan_start:.2f}")
688657
except APIFailure as e:
@@ -694,15 +663,26 @@ def create_new_diff(
694663
log.error(f"Stack trace:\n{traceback.format_exc()}")
695664
raise
696665

697-
added_packages, removed_packages, diff_url, report_url= self.get_added_and_removed_packages(
698-
head_full_scan_id,
699-
new_full_scan.id
700-
)
666+
scans_ready= self.check_full_scans_status(head_full_scan_id, new_full_scan.id)
667+
ifscans_readyisFalse:
668+
log.error(f"Full scans did not complete within {self.config.timeout} seconds")
669+
added_packages, removed_packages=self.get_added_and_removed_packages(head_full_scan_id, new_full_scan.id)
701670

702671
diff = self.create_diff_report(added_packages, removed_packages)
672+
673+
base_socket = "https://socket.dev/dashboard/org"
703674
diff.id = new_full_scan.id
675+
676+
report_url = f"{base_socket}/{self.config.org_slug}/sbom/{diff.id}"
677+
if not params.include_license_details:
678+
report_url += "?include_license_details=false"
704679
diff.report_url = report_url
705-
diff.diff_url = diff_url
680+
681+
if head_full_scan_id is not None:
682+
diff.diff_url = f"{base_socket}/{self.config.org_slug}/diff/{head_full_scan_id}/{diff.id}"
683+
else:
684+
diff.diff_url = diff.report_url
685+
706686
return diff
707687

708688
def create_diff_report(

‎socketsecurity/socketcli.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ def main_code():
235235
log.debug("Updated security comment with no new alerts")
236236

237237
# FIXME: diff.new_packages is never populated, neither is removed_packages
238-
if (len(diff.new_packages) == 0andlen(diff.removed_packages) ==0) or config.disable_overview:
238+
if (len(diff.new_packages) == 0) or config.disable_overview:
239239
if not update_old_overview_comment:
240240
new_overview_comment = False
241241
log.debug("No new/removed packages or Dependency Overview comment disabled")

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /