socketsecurity 2.0.52__tar.gz → 2.0.56__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.56}/PKG-INFO +15 -13
  2. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/README.md +14 -12
  3. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/pyproject.toml +1 -1
  4. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/__init__.py +1 -1
  5. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/config.py +39 -14
  6. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/core/__init__.py +20 -7
  7. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/core/classes.py +1 -1
  8. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/core/messages.py +130 -40
  9. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/core/scm_comments.py +106 -4
  10. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/core/socket_config.py +3 -1
  11. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/socketcli.py +9 -1
  12. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/.github/CODEOWNERS +0 -0
  13. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/.github/PULL_REQUEST_TEMPLATE/bug-fix.md +0 -0
  14. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/.github/PULL_REQUEST_TEMPLATE/feature.md +0 -0
  15. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/.github/PULL_REQUEST_TEMPLATE/improvement.md +0 -0
  16. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  17. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/.github/workflows/docker-stable.yml +0 -0
  18. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/.github/workflows/pr-preview.yml +0 -0
  19. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/.github/workflows/release.yml +0 -0
  20. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/.github/workflows/version-check.yml +0 -0
  21. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/.gitignore +0 -0
  22. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/.hooks/sync_version.py +0 -0
  23. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/.pre-commit-config.yaml +0 -0
  24. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/.python-version +0 -0
  25. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/Dockerfile +0 -0
  26. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/LICENSE +0 -0
  27. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/Makefile +0 -0
  28. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/Pipfile.lock +0 -0
  29. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/docs/README.md +0 -0
  30. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/pytest.ini +0 -0
  31. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/requirements-dev.lock +0 -0
  32. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/requirements.lock +0 -0
  33. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/scripts/build_container.sh +0 -0
  34. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/scripts/deploy-test-docker.sh +0 -0
  35. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/scripts/deploy-test-pypi.sh +0 -0
  36. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/scripts/run.sh +0 -0
  37. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/core/cli_client.py +0 -0
  38. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/core/exceptions.py +0 -0
  39. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/core/git_interface.py +0 -0
  40. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/core/issues.py +0 -0
  41. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/core/licenses.py +0 -0
  42. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/core/logging.py +0 -0
  43. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/core/scm/__init__.py +0 -0
  44. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/core/scm/base.py +0 -0
  45. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/core/scm/client.py +0 -0
  46. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/core/scm/github.py +0 -0
  47. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/core/scm/gitlab.py +0 -0
  48. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/core/utils.py +0 -0
  49. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/output.py +0 -0
  50. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/plugins/__init__.py +0 -0
  51. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/plugins/base.py +0 -0
  52. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/plugins/jira.py +0 -0
  53. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/plugins/manager.py +0 -0
  54. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/plugins/slack.py +0 -0
  55. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/plugins/teams.py +0 -0
  56. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/socketsecurity/plugins/webhook.py +0 -0
  57. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/tests/__init__.py +0 -0
  58. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/tests/core/conftest.py +0 -0
  59. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/tests/core/create_diff_input.json +0 -0
  60. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/tests/core/test_diff_generation.py +0 -0
  61. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/tests/core/test_package_and_alerts.py +0 -0
  62. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/tests/core/test_sdk_methods.py +0 -0
  63. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/tests/core/test_supporting_methods.py +0 -0
  64. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/tests/data/fullscans/create_response.json +0 -0
  65. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/tests/data/fullscans/diff/stream_diff.json +0 -0
  66. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/tests/data/fullscans/diff/stream_diff_full.json +0 -0
  67. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/tests/data/fullscans/head_scan/metadata.json +0 -0
  68. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/tests/data/fullscans/head_scan/stream_scan.json +0 -0
  69. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/tests/data/fullscans/head_scan/stream_scan_full.json +0 -0
  70. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/tests/data/fullscans/new_scan/metadata.json +0 -0
  71. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/tests/data/fullscans/new_scan/stream_scan.json +0 -0
  72. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/tests/data/repos/repo_info_error.json +0 -0
  73. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/tests/data/repos/repo_info_no_head.json +0 -0
  74. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/tests/data/repos/repo_info_success.json +0 -0
  75. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/tests/data/settings/security-policy.json +0 -0
  76. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/tests/unit/__init__.py +0 -0
  77. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/tests/unit/test_cli_config.py +0 -0
  78. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/tests/unit/test_client.py +0 -0
  79. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/tests/unit/test_config.py +0 -0
  80. {socketsecurity-2.0.52 → socketsecurity-2.0.56}/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.56
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>
@@ -79,13 +79,14 @@ If you don't want to provide the Socket API Token every time then you can use th
79
79
  | --api-token | False | | Socket Security API token (can also be set via SOCKET_SECURITY_API_KEY env var) |
80
80
 
81
81
  #### Repository
82
- | Parameter | Required | Default | Description |
83
- |:--------------|:---------|:--------|:------------------------------------------------------------------------|
84
- | --repo | False | | Repository name in owner/repo format |
85
- | --integration | False | api | Integration type (api, github, gitlab) |
86
- | --owner | False | | Name of the integration owner, defaults to the socket organization slug |
87
- | --branch | False | "" | Branch name |
88
- | --committers | False | | Committer(s) to filter by |
82
+ | Parameter | Required | Default | Description |
83
+ |:-----------------|:---------|:--------|:------------------------------------------------------------------------|
84
+ | --repo | False | | Repository name in owner/repo format |
85
+ | --integration | False | api | Integration type (api, github, gitlab) |
86
+ | --owner | False | | Name of the integration owner, defaults to the socket organization slug |
87
+ | --branch | False | "" | Branch name |
88
+ | --committers | False | | Committer(s) to filter by |
89
+ | --repo-is-public | False | False | If set, flags a new repository creation as public. Defaults to false. |
89
90
 
90
91
  #### Pull Request and Commit
91
92
  | Parameter | Required | Default | Description |
@@ -95,11 +96,12 @@ If you don't want to provide the Socket API Token every time then you can use th
95
96
  | --commit-sha | False | "" | Commit SHA |
96
97
 
97
98
  #### Path and File
98
- | Parameter | Required | Default | Description |
99
- |:--------------|:---------|:--------|:-------------------------------------|
100
- | --target-path | False | ./ | Target path for analysis |
101
- | --sbom-file | False | | SBOM file path |
102
- | --files | False | [] | Files to analyze (JSON array string) |
99
+ | Parameter | Required | Default | Description |
100
+ |:-------------------|:---------|:--------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
101
+ | --target-path | False | ./ | Target path for analysis |
102
+ | --sbom-file | False | | SBOM file path |
103
+ | --files | False | [] | Files to analyze (JSON array string) |
104
+ | --exclude-patterns | False | [] | List of patterns to exclude from analysis (JSON array string). You can get supported files form the [Supported Files API](https://docs.socket.dev/reference/getsupportedfiles) |
103
105
 
104
106
  #### Branch and Scan Configuration
105
107
  | Parameter | Required | Default | Description |
@@ -23,13 +23,14 @@ If you don't want to provide the Socket API Token every time then you can use th
23
23
  | --api-token | False | | Socket Security API token (can also be set via SOCKET_SECURITY_API_KEY env var) |
24
24
 
25
25
  #### Repository
26
- | Parameter | Required | Default | Description |
27
- |:--------------|:---------|:--------|:------------------------------------------------------------------------|
28
- | --repo | False | | Repository name in owner/repo format |
29
- | --integration | False | api | Integration type (api, github, gitlab) |
30
- | --owner | False | | Name of the integration owner, defaults to the socket organization slug |
31
- | --branch | False | "" | Branch name |
32
- | --committers | False | | Committer(s) to filter by |
26
+ | Parameter | Required | Default | Description |
27
+ |:-----------------|:---------|:--------|:------------------------------------------------------------------------|
28
+ | --repo | False | | Repository name in owner/repo format |
29
+ | --integration | False | api | Integration type (api, github, gitlab) |
30
+ | --owner | False | | Name of the integration owner, defaults to the socket organization slug |
31
+ | --branch | False | "" | Branch name |
32
+ | --committers | False | | Committer(s) to filter by |
33
+ | --repo-is-public | False | False | If set, flags a new repository creation as public. Defaults to false. |
33
34
 
34
35
  #### Pull Request and Commit
35
36
  | Parameter | Required | Default | Description |
@@ -39,11 +40,12 @@ If you don't want to provide the Socket API Token every time then you can use th
39
40
  | --commit-sha | False | "" | Commit SHA |
40
41
 
41
42
  #### Path and File
42
- | Parameter | Required | Default | Description |
43
- |:--------------|:---------|:--------|:-------------------------------------|
44
- | --target-path | False | ./ | Target path for analysis |
45
- | --sbom-file | False | | SBOM file path |
46
- | --files | False | [] | Files to analyze (JSON array string) |
43
+ | Parameter | Required | Default | Description |
44
+ |:-------------------|:---------|:--------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
45
+ | --target-path | False | ./ | Target path for analysis |
46
+ | --sbom-file | False | | SBOM file path |
47
+ | --files | False | [] | Files to analyze (JSON array string) |
48
+ | --exclude-patterns | False | [] | List of patterns to exclude from analysis (JSON array string). You can get supported files form the [Supported Files API](https://docs.socket.dev/reference/getsupportedfiles) |
47
49
 
48
50
  #### Branch and Scan Configuration
49
51
  | Parameter | Required | Default | Description |
@@ -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.56"
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.56'
@@ -1,4 +1,5 @@
1
1
  import argparse
2
+ import logging
2
3
  import os
3
4
  from dataclasses import asdict, dataclass, field
4
5
  from typing import List, Optional
@@ -50,6 +51,8 @@ class CliConfig:
50
51
  timeout: Optional[int] = 1200
51
52
  exclude_license_details: bool = False
52
53
  include_module_folders: bool = False
54
+ repo_is_public: bool = False
55
+ excluded_ecosystems: list[str] = field(default_factory=lambda: [])
53
56
  version: str = __version__
54
57
  jira_plugin: PluginConfig = field(default_factory=PluginConfig)
55
58
  slack_plugin: PluginConfig = field(default_factory=PluginConfig)
@@ -94,8 +97,15 @@ class CliConfig:
94
97
  'timeout': args.timeout,
95
98
  'exclude_license_details': args.exclude_license_details,
96
99
  'include_module_folders': args.include_module_folders,
100
+ 'repo_is_public': args.repo_is_public,
101
+ "excluded_ecosystems": args.excluded_ecosystems,
97
102
  'version': __version__
98
103
  }
104
+ try:
105
+ config_args["excluded_ecosystems"] = json.loads(config_args["excluded_ecosystems"].replace("'", '"'))
106
+ except json.JSONDecodeError:
107
+ logging.error(f"Unable to parse excluded_ecosystems: {config_args['excluded_ecosystems']}")
108
+ exit(1)
99
109
  config_args.update({
100
110
  "jira_plugin": PluginConfig(
101
111
  enabled=os.getenv("SOCKET_JIRA_ENABLED", "false").lower() == "true",
@@ -147,30 +157,32 @@ def create_argument_parser() -> argparse.ArgumentParser:
147
157
  required=False
148
158
  )
149
159
  repo_group.add_argument(
160
+ "--repo-is-public",
161
+ dest="repo_is_public",
162
+ action="store_true",
163
+ help="If set it will flag a new repository creation as public. Defaults to false."
164
+ )
165
+ repo_group.add_argument(
166
+ "--branch",
167
+ metavar="<name>",
168
+ help="Branch name",
169
+ default=""
170
+ )
171
+
172
+ integration_group = parser.add_argument_group('Integration')
173
+ integration_group.add_argument(
150
174
  "--integration",
151
175
  choices=INTEGRATION_TYPES,
152
176
  metavar="<type>",
153
- help="Integration type",
177
+ help="Integration type of api, github, gitlab, azure, or bitbucket. Defaults to api",
154
178
  default="api"
155
179
  )
156
- repo_group.add_argument(
180
+ integration_group.add_argument(
157
181
  "--owner",
158
182
  metavar="<name>",
159
183
  help="Name of the integration owner, defaults to the socket organization slug",
160
184
  required=False
161
185
  )
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
186
 
175
187
  # Pull Request and Commit info
176
188
  pr_group = parser.add_argument_group('Pull Request and Commit')
@@ -209,6 +221,12 @@ def create_argument_parser() -> argparse.ArgumentParser:
209
221
  dest="commit_sha",
210
222
  help=argparse.SUPPRESS
211
223
  )
224
+ pr_group.add_argument(
225
+ "--committers",
226
+ metavar="<name>",
227
+ help="Committer for the commit (comma separated)",
228
+ nargs="*"
229
+ )
212
230
 
213
231
  # Path and File options
214
232
  path_group = parser.add_argument_group('Path and File')
@@ -242,6 +260,13 @@ def create_argument_parser() -> argparse.ArgumentParser:
242
260
  help="Files to analyze (JSON array string)"
243
261
  )
244
262
 
263
+ path_group.add_argument(
264
+ "--excluded-ecosystems",
265
+ default="[]",
266
+ dest="excluded_ecosystems",
267
+ help="List of ecosystems to exclude from analysis (JSON array string)"
268
+ )
269
+
245
270
  # Branch and Scan Configuration
246
271
  config_group = parser.add_argument_group('Branch and Scan Configuration')
247
272
  config_group.add_argument(
@@ -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
@@ -184,6 +184,8 @@ class Core:
184
184
  patterns = fallback_patterns
185
185
 
186
186
  for ecosystem in patterns:
187
+ if ecosystem in self.config.excluded_ecosystems:
188
+ continue
187
189
  ecosystem_patterns = patterns[ecosystem]
188
190
  for file_name in ecosystem_patterns:
189
191
  original_pattern = ecosystem_patterns[file_name]["pattern"]
@@ -439,7 +441,12 @@ class Core:
439
441
  log.warning(f"Failed to get repository {repo_slug}, attempting to create it")
440
442
  try:
441
443
 
442
- create_response = self.sdk.repos.post(self.config.org_slug, name=repo_slug, default_branch=default_branch)
444
+ create_response = self.sdk.repos.post(
445
+ self.config.org_slug,
446
+ name=repo_slug,
447
+ default_branch=default_branch,
448
+ visibility=self.config.repo_visibility
449
+ )
443
450
 
444
451
  # Check if the response is empty (failure) or has content (success)
445
452
  if not create_response:
@@ -644,7 +651,7 @@ class Core:
644
651
  seen_removed_packages = set()
645
652
 
646
653
  for package_id, package in added_packages.items():
647
- purl = Core.create_purl(package_id, added_packages)
654
+ purl = self.create_purl(package_id, added_packages)
648
655
  base_purl = f"{purl.ecosystem}/{purl.name}@{purl.version}"
649
656
 
650
657
  if (not direct_only or package.direct) and base_purl not in seen_new_packages:
@@ -658,7 +665,7 @@ class Core:
658
665
  )
659
666
 
660
667
  for package_id, package in removed_packages.items():
661
- purl = Core.create_purl(package_id, removed_packages)
668
+ purl = self.create_purl(package_id, removed_packages)
662
669
  base_purl = f"{purl.ecosystem}/{purl.name}@{purl.version}"
663
670
 
664
671
  if (not direct_only or package.direct) and base_purl not in seen_removed_packages:
@@ -682,8 +689,13 @@ class Core:
682
689
 
683
690
  return diff
684
691
 
685
- @staticmethod
686
- def create_purl(package_id: str, packages: dict[str, Package]) -> Purl:
692
+ def get_all_scores(self, packages: dict[str, Package]) -> dict[str, Package]:
693
+ components = []
694
+ for package_id in packages:
695
+ package = packages[package_id]
696
+ return packages
697
+
698
+ def create_purl(self, package_id: str, packages: dict[str, Package]) -> Purl:
687
699
  """
688
700
  Creates the extended PURL data for package identification and tracking.
689
701
 
@@ -707,7 +719,8 @@ class Core:
707
719
  size=package.size,
708
720
  transitives=package.transitives,
709
721
  url=package.url,
710
- purl=package.purl
722
+ purl=package.purl,
723
+ scores=package.score
711
724
  )
712
725
  return purl
713
726
 
@@ -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):
@@ -1,7 +1,7 @@
1
1
  from dataclasses import dataclass, field
2
2
  from typing import Dict, Optional
3
3
  from urllib.parse import urlparse
4
- from typing import Set
4
+ from typing import Set, List
5
5
  import os
6
6
 
7
7
  from socketsecurity.core.issues import AllIssues
@@ -26,8 +26,10 @@ 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)
32
+ excluded_ecosystems: List[str] = field(default_factory=lambda: [])
31
33
  version: str = __version__
32
34
 
33
35
  def __post_init__(self):
@@ -148,8 +148,16 @@ 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"
153
+ if config.excluded_ecosystems and len(config.excluded_ecosystems) > 0:
154
+ core.config.excluded_ecosystems = config.excluded_ecosystems
151
155
  integration_type = config.integration_type
152
156
  integration_org_slug = config.integration_org_slug or org_slug
157
+ try:
158
+ pr_number = int(config.pr_number)
159
+ except (ValueError, TypeError):
160
+ pr_number = 0
153
161
 
154
162
  params = FullScanParams(
155
163
  org_slug=org_slug,
@@ -159,7 +167,7 @@ def main_code():
159
167
  branch=config.branch,
160
168
  commit_message=config.commit_message,
161
169
  commit_hash=config.commit_sha,
162
- pull_request=config.pr_number,
170
+ pull_request=pr_number,
163
171
  committers=config.committers,
164
172
  make_default_branch=config.default_branch,
165
173
  set_as_pending_head=True
File without changes