socketsecurity 2.0.52__tar.gz → 2.0.55__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/PKG-INFO +1 -1
  2. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/pyproject.toml +1 -1
  3. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/__init__.py +1 -1
  4. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/config.py +24 -14
  5. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/core/__init__.py +18 -7
  6. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/core/classes.py +1 -1
  7. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/core/messages.py +130 -40
  8. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/core/scm_comments.py +106 -4
  9. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/core/socket_config.py +1 -0
  10. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/socketcli.py +7 -1
  11. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/.github/CODEOWNERS +0 -0
  12. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/.github/PULL_REQUEST_TEMPLATE/bug-fix.md +0 -0
  13. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/.github/PULL_REQUEST_TEMPLATE/feature.md +0 -0
  14. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/.github/PULL_REQUEST_TEMPLATE/improvement.md +0 -0
  15. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  16. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/.github/workflows/docker-stable.yml +0 -0
  17. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/.github/workflows/pr-preview.yml +0 -0
  18. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/.github/workflows/release.yml +0 -0
  19. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/.github/workflows/version-check.yml +0 -0
  20. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/.gitignore +0 -0
  21. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/.hooks/sync_version.py +0 -0
  22. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/.pre-commit-config.yaml +0 -0
  23. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/.python-version +0 -0
  24. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/Dockerfile +0 -0
  25. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/LICENSE +0 -0
  26. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/Makefile +0 -0
  27. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/Pipfile.lock +0 -0
  28. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/README.md +0 -0
  29. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/docs/README.md +0 -0
  30. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/pytest.ini +0 -0
  31. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/requirements-dev.lock +0 -0
  32. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/requirements.lock +0 -0
  33. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/scripts/build_container.sh +0 -0
  34. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/scripts/deploy-test-docker.sh +0 -0
  35. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/scripts/deploy-test-pypi.sh +0 -0
  36. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/scripts/run.sh +0 -0
  37. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/core/cli_client.py +0 -0
  38. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/core/exceptions.py +0 -0
  39. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/core/git_interface.py +0 -0
  40. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/core/issues.py +0 -0
  41. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/core/licenses.py +0 -0
  42. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/core/logging.py +0 -0
  43. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/core/scm/__init__.py +0 -0
  44. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/core/scm/base.py +0 -0
  45. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/core/scm/client.py +0 -0
  46. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/core/scm/github.py +0 -0
  47. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/core/scm/gitlab.py +0 -0
  48. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/core/utils.py +0 -0
  49. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/output.py +0 -0
  50. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/plugins/__init__.py +0 -0
  51. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/plugins/base.py +0 -0
  52. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/plugins/jira.py +0 -0
  53. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/plugins/manager.py +0 -0
  54. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/plugins/slack.py +0 -0
  55. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/plugins/teams.py +0 -0
  56. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/socketsecurity/plugins/webhook.py +0 -0
  57. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/tests/__init__.py +0 -0
  58. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/tests/core/conftest.py +0 -0
  59. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/tests/core/create_diff_input.json +0 -0
  60. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/tests/core/test_diff_generation.py +0 -0
  61. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/tests/core/test_package_and_alerts.py +0 -0
  62. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/tests/core/test_sdk_methods.py +0 -0
  63. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/tests/core/test_supporting_methods.py +0 -0
  64. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/tests/data/fullscans/create_response.json +0 -0
  65. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/tests/data/fullscans/diff/stream_diff.json +0 -0
  66. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/tests/data/fullscans/diff/stream_diff_full.json +0 -0
  67. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/tests/data/fullscans/head_scan/metadata.json +0 -0
  68. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/tests/data/fullscans/head_scan/stream_scan.json +0 -0
  69. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/tests/data/fullscans/head_scan/stream_scan_full.json +0 -0
  70. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/tests/data/fullscans/new_scan/metadata.json +0 -0
  71. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/tests/data/fullscans/new_scan/stream_scan.json +0 -0
  72. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/tests/data/repos/repo_info_error.json +0 -0
  73. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/tests/data/repos/repo_info_no_head.json +0 -0
  74. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/tests/data/repos/repo_info_success.json +0 -0
  75. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/tests/data/settings/security-policy.json +0 -0
  76. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/tests/unit/__init__.py +0 -0
  77. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/tests/unit/test_cli_config.py +0 -0
  78. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/tests/unit/test_client.py +0 -0
  79. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/tests/unit/test_config.py +0 -0
  80. {socketsecurity-2.0.52 → socketsecurity-2.0.55}/tests/unit/test_output.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: socketsecurity
3
- Version: 2.0.52
3
+ Version: 2.0.55
4
4
  Summary: Socket Security CLI for CI/CD
5
5
  Project-URL: Homepage, https://socket.dev
6
6
  Author-email: Douglas Coburn <douglas@socket.dev>
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
 
7
7
  [project]
8
8
  name = "socketsecurity"
9
- version = "2.0.52"
9
+ version = "2.0.55"
10
10
  requires-python = ">= 3.10"
11
11
  license = {"file" = "LICENSE"}
12
12
  dependencies = [
@@ -1,2 +1,2 @@
1
1
  __author__ = 'socket.dev'
2
- __version__ = '2.0.52'
2
+ __version__ = '2.0.55'
@@ -50,6 +50,7 @@ class CliConfig:
50
50
  timeout: Optional[int] = 1200
51
51
  exclude_license_details: bool = False
52
52
  include_module_folders: bool = False
53
+ repo_is_public: bool = False
53
54
  version: str = __version__
54
55
  jira_plugin: PluginConfig = field(default_factory=PluginConfig)
55
56
  slack_plugin: PluginConfig = field(default_factory=PluginConfig)
@@ -94,6 +95,7 @@ class CliConfig:
94
95
  'timeout': args.timeout,
95
96
  'exclude_license_details': args.exclude_license_details,
96
97
  'include_module_folders': args.include_module_folders,
98
+ 'repo_is_public': args.repo_is_public,
97
99
  'version': __version__
98
100
  }
99
101
  config_args.update({
@@ -147,30 +149,32 @@ def create_argument_parser() -> argparse.ArgumentParser:
147
149
  required=False
148
150
  )
149
151
  repo_group.add_argument(
152
+ "--repo-is-public",
153
+ dest="repo_is_public",
154
+ action="store_true",
155
+ help="If set it will flag a new repository creation as public. Defaults to false."
156
+ )
157
+ repo_group.add_argument(
158
+ "--branch",
159
+ metavar="<name>",
160
+ help="Branch name",
161
+ default=""
162
+ )
163
+
164
+ integration_group = parser.add_argument_group('Integration')
165
+ integration_group.add_argument(
150
166
  "--integration",
151
167
  choices=INTEGRATION_TYPES,
152
168
  metavar="<type>",
153
- help="Integration type",
169
+ help="Integration type of api, github, gitlab, azure, or bitbucket. Defaults to api",
154
170
  default="api"
155
171
  )
156
- repo_group.add_argument(
172
+ integration_group.add_argument(
157
173
  "--owner",
158
174
  metavar="<name>",
159
175
  help="Name of the integration owner, defaults to the socket organization slug",
160
176
  required=False
161
177
  )
162
- repo_group.add_argument(
163
- "--branch",
164
- metavar="<name>",
165
- help="Branch name",
166
- default=""
167
- )
168
- repo_group.add_argument(
169
- "--committers",
170
- metavar="<name>",
171
- help="Committer(s) to filter by",
172
- nargs="*"
173
- )
174
178
 
175
179
  # Pull Request and Commit info
176
180
  pr_group = parser.add_argument_group('Pull Request and Commit')
@@ -209,6 +213,12 @@ def create_argument_parser() -> argparse.ArgumentParser:
209
213
  dest="commit_sha",
210
214
  help=argparse.SUPPRESS
211
215
  )
216
+ pr_group.add_argument(
217
+ "--committers",
218
+ metavar="<name>",
219
+ help="Committer for the commit (comma separated)",
220
+ nargs="*"
221
+ )
212
222
 
213
223
  # Path and File options
214
224
  path_group = parser.add_argument_group('Path and File')
@@ -21,7 +21,7 @@ from socketsecurity.core.classes import (
21
21
  FullScan,
22
22
  Issue,
23
23
  Package,
24
- Purl,
24
+ Purl
25
25
  )
26
26
  from socketsecurity.core.exceptions import APIResourceNotFound
27
27
  from socketsecurity.core.licenses import Licenses
@@ -439,7 +439,12 @@ class Core:
439
439
  log.warning(f"Failed to get repository {repo_slug}, attempting to create it")
440
440
  try:
441
441
 
442
- create_response = self.sdk.repos.post(self.config.org_slug, name=repo_slug, default_branch=default_branch)
442
+ create_response = self.sdk.repos.post(
443
+ self.config.org_slug,
444
+ name=repo_slug,
445
+ default_branch=default_branch,
446
+ visibility=self.config.repo_visibility
447
+ )
443
448
 
444
449
  # Check if the response is empty (failure) or has content (success)
445
450
  if not create_response:
@@ -644,7 +649,7 @@ class Core:
644
649
  seen_removed_packages = set()
645
650
 
646
651
  for package_id, package in added_packages.items():
647
- purl = Core.create_purl(package_id, added_packages)
652
+ purl = self.create_purl(package_id, added_packages)
648
653
  base_purl = f"{purl.ecosystem}/{purl.name}@{purl.version}"
649
654
 
650
655
  if (not direct_only or package.direct) and base_purl not in seen_new_packages:
@@ -658,7 +663,7 @@ class Core:
658
663
  )
659
664
 
660
665
  for package_id, package in removed_packages.items():
661
- purl = Core.create_purl(package_id, removed_packages)
666
+ purl = self.create_purl(package_id, removed_packages)
662
667
  base_purl = f"{purl.ecosystem}/{purl.name}@{purl.version}"
663
668
 
664
669
  if (not direct_only or package.direct) and base_purl not in seen_removed_packages:
@@ -682,8 +687,13 @@ class Core:
682
687
 
683
688
  return diff
684
689
 
685
- @staticmethod
686
- def create_purl(package_id: str, packages: dict[str, Package]) -> Purl:
690
+ def get_all_scores(self, packages: dict[str, Package]) -> dict[str, Package]:
691
+ components = []
692
+ for package_id in packages:
693
+ package = packages[package_id]
694
+ return packages
695
+
696
+ def create_purl(self, package_id: str, packages: dict[str, Package]) -> Purl:
687
697
  """
688
698
  Creates the extended PURL data for package identification and tracking.
689
699
 
@@ -707,7 +717,8 @@ class Core:
707
717
  size=package.size,
708
718
  transitives=package.transitives,
709
719
  url=package.url,
710
- purl=package.purl
720
+ purl=package.purl,
721
+ scores=package.score
711
722
  )
712
723
  return purl
713
724
 
@@ -370,7 +370,6 @@ class Repository:
370
370
  def __str__(self):
371
371
  return json.dumps(self.__dict__)
372
372
 
373
-
374
373
  class Purl:
375
374
  """
376
375
  Represents a Package URL (PURL) with extended metadata.
@@ -392,6 +391,7 @@ class Purl:
392
391
  author_url: str
393
392
  url: str
394
393
  purl: str
394
+ scores: dict[str, int]
395
395
 
396
396
  def __init__(self, **kwargs):
397
397
  if kwargs:
@@ -302,26 +302,95 @@ class Messages:
302
302
  @staticmethod
303
303
  def security_comment_template(diff: Diff) -> str:
304
304
  """
305
- Creates the security comment template
306
- :param diff: Diff - Diff report with the data needed for the template
307
- :return:
305
+ Generates the security comment template in the new required format.
306
+ Dynamically determines placement of the alerts table if markers like `<!-- start-socket-alerts-table -->` are used.
307
+
308
+ :param diff: Diff - Contains the detected vulnerabilities and warnings.
309
+ :return: str - The formatted Markdown/HTML string.
308
310
  """
309
- md = MdUtils(file_name="markdown_security_temp.md")
310
- md.new_line("<!-- socket-security-comment-actions -->")
311
- md.new_header(level=1, title="Socket Security: Issues Report")
312
- md.new_line("Potential security issues detected. Learn more about [socket.dev](https://socket.dev)")
313
- md.new_line("To accept the risk, merge this PR and you will not be notified again.")
314
- md.new_line()
315
- md.new_line("<!-- start-socket-alerts-table -->")
316
- md, ignore_commands, next_steps = Messages.create_security_alert_table(diff, md)
317
- md.new_line("<!-- end-socket-alerts-table -->")
318
- md.new_line()
319
- md = Messages.create_next_steps(md, next_steps)
320
- md = Messages.create_deeper_look(md)
321
- md = Messages.create_remove_package(md)
322
- md = Messages.create_acceptable_risk(md, ignore_commands)
323
- md.create_md_file()
324
- return md.file_data_text.lstrip()
311
+ # Start of the comment
312
+ comment = """<!-- socket-security-comment-actions -->
313
+
314
+ > **❗️ Caution**
315
+ > **Review the following alerts detected in dependencies.**
316
+ >
317
+ > According to your organization’s Security Policy, you **must** resolve all **“Block”** alerts before proceeding. It’s recommended to resolve **“Warn”** alerts too.
318
+ > Learn more about [Socket for GitHub](https://socket.dev?utm_medium=gh).
319
+
320
+ <!-- start-socket-updated-alerts-table -->
321
+ <table>
322
+ <thead>
323
+ <tr>
324
+ <th>Action</th>
325
+ <th>Severity</th>
326
+ <th align="left">Alert (click for details)</th>
327
+ </tr>
328
+ </thead>
329
+ <tbody>
330
+ """
331
+
332
+ # Loop through alerts, dynamically generating rows
333
+ for alert in diff.new_alerts:
334
+ severity_icon = Messages.get_severity_icon(alert.severity)
335
+ action = "Block" if alert.error else "Warn"
336
+ details_open = ""
337
+ # Generate a table row for each alert
338
+ comment += f"""
339
+ <!-- start-socket-alert-{alert.pkg_name}@{alert.pkg_version} -->
340
+ <tr>
341
+ <td><strong>{action}</strong></td>
342
+ <td align="center">
343
+ <img src="{severity_icon}" alt="{alert.severity}" width="20" height="20">
344
+ </td>
345
+ <td>
346
+ <details {details_open}>
347
+ <summary>{alert.pkg_name}@{alert.pkg_version} - {alert.title}</summary>
348
+ <p><strong>Note:</strong> {alert.description}</p>
349
+ <p><strong>Source:</strong> <a href="{alert.manifests}">Manifest File</a></p>
350
+ <p>ℹ️ Read more on:
351
+ <a href="{alert.purl}">This package</a> |
352
+ <a href="{alert.url}">This alert</a> |
353
+ <a href="https://socket.dev/alerts/malware">What is known malware?</a></p>
354
+ <blockquote>
355
+ <p><em>Suggestion:</em> {alert.suggestion}</p>
356
+ <p><em>Mark as acceptable risk:</em> To ignore this alert only in this pull request, reply with:<br/>
357
+ <code>@SocketSecurity ignore {alert.pkg_name}@{alert.pkg_version}</code><br/>
358
+ Or ignore all future alerts with:<br/>
359
+ <code>@SocketSecurity ignore-all</code></p>
360
+ </blockquote>
361
+ </details>
362
+ </td>
363
+ </tr>
364
+ <!-- end-socket-alert-{alert.pkg_name}@{alert.pkg_version} -->
365
+ """
366
+
367
+ # Close table and comment
368
+ comment += """
369
+ </tbody>
370
+ </table>
371
+ <!-- end-socket-alerts-table -->
372
+
373
+ [View full report](https://socket.dev/...&action=error%2Cwarn)
374
+ """
375
+
376
+ return comment
377
+
378
+ @staticmethod
379
+ def get_severity_icon(severity: str) -> str:
380
+ """
381
+ Maps severity levels to their corresponding badge/icon URLs.
382
+
383
+ :param severity: str - Severity level (e.g., "Critical", "High").
384
+ :return: str - Badge/icon URL.
385
+ """
386
+ severity_map = {
387
+ "critical": "https://github-app-statics.socket.dev/severity-3.svg",
388
+ "high": "https://github-app-statics.socket.dev/severity-2.svg",
389
+ "medium": "https://github-app-statics.socket.dev/severity-1.svg",
390
+ "low": "https://github-app-statics.socket.dev/severity-0.svg",
391
+ }
392
+ return severity_map.get(severity.lower(), "https://github-app-statics.socket.dev/severity-0.svg")
393
+
325
394
 
326
395
  @staticmethod
327
396
  def create_next_steps(md: MdUtils, next_steps: dict):
@@ -456,11 +525,9 @@ class Messages:
456
525
  md = MdUtils(file_name="markdown_overview_temp.md")
457
526
  md.new_line("<!-- socket-overview-comment-actions -->")
458
527
  md.new_header(level=1, title="Socket Security: Dependency Overview")
459
- md.new_line("New and removed dependencies detected. Learn more about [socket.dev](https://socket.dev)")
528
+ md.new_line("Review the following changes in direct dependencies. Learn more about [socket.dev](https://socket.dev)")
460
529
  md.new_line()
461
530
  md = Messages.create_added_table(diff, md)
462
- if len(diff.removed_packages) > 0:
463
- md = Messages.create_remove_line(diff, md)
464
531
  md.create_md_file()
465
532
  if len(md.file_data_text.lstrip()) >= 65500:
466
533
  md = Messages.short_dependency_overview_comment(diff)
@@ -471,7 +538,7 @@ class Messages:
471
538
  md = MdUtils(file_name="markdown_overview_temp.md")
472
539
  md.new_line("<!-- socket-overview-comment-actions -->")
473
540
  md.new_header(level=1, title="Socket Security: Dependency Overview")
474
- md.new_line("New and removed dependencies detected. Learn more about [socket.dev](https://socket.dev)")
541
+ md.new_line("Review the following changes in direct dependencies. Learn more about [socket.dev](https://socket.dev)")
475
542
  md.new_line()
476
543
  md.new_line("The amount of dependency changes were to long for this comment. Please check out the full report")
477
544
  md.new_line(f"To view more information about this report checkout the [Full Report]({diff.diff_url})")
@@ -498,40 +565,63 @@ class Messages:
498
565
  def create_added_table(diff: Diff, md: MdUtils) -> MdUtils:
499
566
  """
500
567
  Create the Added packages table for the Dependency Overview template
501
- :param diff: Diff - Diff report with the Added packages information
568
+ :param diff: Diff - Diff report with the Added package information
502
569
  :param md: MdUtils - Main markdown variable
503
570
  :return:
504
571
  """
572
+ # Table column headers
505
573
  overview_table = [
574
+ "Diff",
506
575
  "Package",
507
- "Direct",
508
- "Capabilities",
509
- "Transitives",
510
- "Size",
511
- "Author"
576
+ "Supply Chain<br/>Security",
577
+ "Vulnerability",
578
+ "Quality",
579
+ "Maintenance",
580
+ "License"
512
581
  ]
513
582
  num_of_overview_columns = len(overview_table)
583
+
514
584
  count = 0
515
585
  for added in diff.new_packages:
516
- added: Purl
517
- package_url = Messages.create_purl_link(added)
518
- capabilities = ", ".join(added.capabilities)
586
+ added: Purl # Ensure `added` has scores and relevant attributes.
587
+
588
+ package_url = f"[{added.purl}]({added.url})"
589
+ diff_badge = f"[![+](https://github-app-statics.socket.dev/diff-added.svg)]({added.url})"
590
+
591
+ # Scores dynamically converted to badge URLs and linked
592
+ def score_to_badge(score):
593
+ score_percent = int(score * 100) # Convert to integer percentage
594
+ return f"[![{score_percent}](https://github-app-statics.socket.dev/score-{score_percent}.svg)]({added.url})"
595
+
596
+ # Generate badges for each score type
597
+ supply_chain_risk_badge = score_to_badge(added.scores.get("supplyChain", 100))
598
+ vulnerability_badge = score_to_badge(added.scores.get("vulnerability", 100))
599
+ quality_badge = score_to_badge(added.scores.get("quality", 100))
600
+ maintenance_badge = score_to_badge(added.scores.get("maintenance", 100))
601
+ license_badge = score_to_badge(added.scores.get("license", 100))
602
+
603
+ # Add the row for this package
519
604
  row = [
605
+ diff_badge,
520
606
  package_url,
521
- added.direct,
522
- capabilities,
523
- added.transitives,
524
- f"{added.size} KB",
525
- added.author_url
607
+ supply_chain_risk_badge,
608
+ vulnerability_badge,
609
+ quality_badge,
610
+ maintenance_badge,
611
+ license_badge
526
612
  ]
527
613
  overview_table.extend(row)
528
- count += 1
529
- num_of_overview_rows = count + 1
614
+ count += 1 # Count total packages
615
+
616
+ # Calculate total rows for table
617
+ num_of_overview_rows = count + 1 # Include header row
618
+
619
+ # Generate Markdown table
530
620
  md.new_table(
531
621
  columns=num_of_overview_columns,
532
622
  rows=num_of_overview_rows,
533
623
  text=overview_table,
534
- text_align="left"
624
+ text_align="center"
535
625
  )
536
626
  return md
537
627
 
@@ -84,9 +84,22 @@ class Comments:
84
84
 
85
85
  @staticmethod
86
86
  def process_security_comment(comment: Comment, comments) -> str:
87
- lines = []
88
- start = False
89
87
  ignore_all, ignore_commands = Comments.get_ignore_options(comments)
88
+ if "start-socket-alerts-table" in "".join(comment.body_list):
89
+ new_body = Comments.process_original_security_comment(comment, ignore_all, ignore_commands)
90
+ else:
91
+ new_body = Comments.process_updated_security_comment(comment, ignore_all, ignore_commands)
92
+
93
+ return new_body
94
+
95
+ @staticmethod
96
+ def process_original_security_comment(
97
+ comment: Comment,
98
+ ignore_all: bool,
99
+ ignore_commands: list[tuple[str, str]]
100
+ ) -> str:
101
+ start = False
102
+ lines = []
90
103
  for line in comment.body_list:
91
104
  line = line.strip()
92
105
  if "start-socket-alerts-table" in line:
@@ -110,8 +123,97 @@ class Comments:
110
123
  lines.append(line)
111
124
  else:
112
125
  lines.append(line)
113
- new_body = "\n".join(lines)
114
- return new_body
126
+ return "\n".join(lines)
127
+
128
+ @staticmethod
129
+ def process_updated_security_comment(
130
+ comment: Comment,
131
+ ignore_all: bool,
132
+ ignore_commands: list[tuple[str, str]]
133
+ ) -> str:
134
+ """
135
+ Processes an updated security comment containing an HTML table with alert sections.
136
+ Removes entire sections marked by start and end hidden comments if the alert matches
137
+ ignore conditions.
138
+
139
+ :param comment: Comment - The raw comment object containing the existing information.
140
+ :param ignore_all: bool - Flag to ignore all alerts.
141
+ :param ignore_commands: list of tuples - Specific ignore commands representing (pkg_name, pkg_version).
142
+ :return: str - The updated comment as a single string.
143
+ """
144
+ lines = []
145
+ ignore_section = False
146
+ pkg_name = pkg_version = "" # Track current package and version
147
+
148
+ # Loop through the comment lines
149
+ for line in comment.body_list:
150
+ line = line.strip()
151
+
152
+ # Detect the start of an alert section
153
+ if line.startswith("<!-- start-socket-alert-"):
154
+ # Extract package name and version from the comment
155
+ try:
156
+ start_marker = line[len("<!-- start-socket-alert-"):-4] # Strip the comment markers
157
+ pkg_name, pkg_version = start_marker.split("@") # Extract pkg_name and pkg_version
158
+ except ValueError:
159
+ pkg_name, pkg_version = "", ""
160
+
161
+ # Determine if we should ignore this alert
162
+ ignore_section = ignore_all or any(
163
+ Comments.is_ignore(pkg_name, pkg_version, name, version)
164
+ for name, version in ignore_commands
165
+ )
166
+
167
+ # If not ignored, include this start marker
168
+ if not ignore_section:
169
+ lines.append(line)
170
+
171
+ # Detect the end of an alert section
172
+ elif line.startswith("<!-- end-socket-alert-"):
173
+ # Only include if we are not ignoring this section
174
+ if not ignore_section:
175
+ lines.append(line)
176
+ ignore_section = False # Reset ignore flag
177
+
178
+ # Include lines inside an alert section only if not ignored
179
+ elif not ignore_section:
180
+ lines.append(line)
181
+
182
+ return "\n".join(lines)
183
+
184
+ @staticmethod
185
+ def extract_alert_details_from_row(row: str, ignore_all: bool, ignore_commands: list[tuple[str, str]]) -> tuple:
186
+ """
187
+ Parses an HTML table row (<tr>) to extract alert details and determine if it should be ignored.
188
+
189
+ :param row: str - The HTML table row as a string.
190
+ :param ignore_all: bool - Flag to ignore all alerts.
191
+ :param ignore_commands: list of tuples - List of (pkg_name, pkg_version) to ignore.
192
+ :return: tuple - (pkg_name, pkg_version, ignore)
193
+ """
194
+ # Extract package details (pkg_name and pkg_version) from the HTML table row
195
+ try:
196
+ # Find the relevant <summary> element to extract package information
197
+ start_index = row.index("<summary>")
198
+ end_index = row.index("</summary>")
199
+ summary_content = row[start_index + 9:end_index] # Extract content between <summary> tags
200
+
201
+ # Example: "npm/malicious-package@1.0.0 - Known Malware Alert"
202
+ pkg_info, _ = summary_content.split(" - ", 1)
203
+ pkg_name, pkg_version = pkg_info.split("@")
204
+ except ValueError:
205
+ # If parsing fails, skip this row
206
+ return "", "", False
207
+
208
+ # Check ignore logic
209
+ ignore = False
210
+ for name, version in ignore_commands:
211
+ if ignore_all or Comments.is_ignore(pkg_name, pkg_version, name, version):
212
+ ignore = True
213
+ break
214
+
215
+ return pkg_name, pkg_version, ignore
216
+
115
217
 
116
218
  @staticmethod
117
219
  def check_for_socket_comments(comments: dict):
@@ -26,6 +26,7 @@ class SocketConfig:
26
26
  full_scan_path: Optional[str] = None
27
27
  repository_path: Optional[str] = None
28
28
  security_policy: Dict = None
29
+ repo_visibility: Optional[str] = 'private'
29
30
  all_issues: Optional['AllIssues'] = None
30
31
  excluded_dirs: Set[str] = field(default_factory=lambda: default_exclude_dirs)
31
32
  version: str = __version__
@@ -148,8 +148,14 @@ def main_code():
148
148
  log.debug("Found manifest files or forced scan, proceeding")
149
149
 
150
150
  org_slug = core.config.org_slug
151
+ if config.repo_is_public:
152
+ core.config.repo_visibility = "public"
151
153
  integration_type = config.integration_type
152
154
  integration_org_slug = config.integration_org_slug or org_slug
155
+ try:
156
+ pr_number = int(config.pr_number)
157
+ except (ValueError, TypeError):
158
+ pr_number = 0
153
159
 
154
160
  params = FullScanParams(
155
161
  org_slug=org_slug,
@@ -159,7 +165,7 @@ def main_code():
159
165
  branch=config.branch,
160
166
  commit_message=config.commit_message,
161
167
  commit_hash=config.commit_sha,
162
- pull_request=config.pr_number,
168
+ pull_request=pr_number,
163
169
  committers=config.committers,
164
170
  make_default_branch=config.default_branch,
165
171
  set_as_pending_head=True
File without changes