socketsecurity 0.0.98__tar.gz → 1.0.0__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 (23) hide show
  1. {socketsecurity-0.0.98/socketsecurity.egg-info → socketsecurity-1.0.0}/PKG-INFO +1 -1
  2. {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity/__init__.py +1 -1
  3. {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity/core/__init__.py +131 -127
  4. {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity/core/classes.py +12 -1
  5. {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity/core/messages.py +26 -8
  6. {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity/socketcli.py +38 -14
  7. {socketsecurity-0.0.98 → socketsecurity-1.0.0/socketsecurity.egg-info}/PKG-INFO +1 -1
  8. {socketsecurity-0.0.98 → socketsecurity-1.0.0}/LICENSE +0 -0
  9. {socketsecurity-0.0.98 → socketsecurity-1.0.0}/README.md +0 -0
  10. {socketsecurity-0.0.98 → socketsecurity-1.0.0}/pyproject.toml +0 -0
  11. {socketsecurity-0.0.98 → socketsecurity-1.0.0}/setup.cfg +0 -0
  12. {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity/core/exceptions.py +0 -0
  13. {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity/core/git_interface.py +0 -0
  14. {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity/core/github.py +0 -0
  15. {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity/core/gitlab.py +0 -0
  16. {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity/core/issues.py +0 -0
  17. {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity/core/licenses.py +0 -0
  18. {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity/core/scm_comments.py +0 -0
  19. {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity.egg-info/SOURCES.txt +0 -0
  20. {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity.egg-info/dependency_links.txt +0 -0
  21. {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity.egg-info/entry_points.txt +0 -0
  22. {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity.egg-info/requires.txt +0 -0
  23. {socketsecurity-0.0.98 → socketsecurity-1.0.0}/socketsecurity.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: socketsecurity
3
- Version: 0.0.98
3
+ Version: 1.0.0
4
4
  Summary: Socket Security CLI for CI/CD
5
5
  Author-email: Douglas Coburn <douglas@socket.dev>
6
6
  Maintainer-email: Douglas Coburn <douglas@socket.dev>
@@ -1,2 +1,2 @@
1
1
  __author__ = 'socket.dev'
2
- __version__ = '0.0.98'
2
+ __version__ = '1.0.0'
@@ -1,4 +1,6 @@
1
1
  import logging
2
+ from pathlib import PurePath
3
+
2
4
  import requests
3
5
  from urllib.parse import urlencode
4
6
  import base64
@@ -46,6 +48,74 @@ security_policy = {}
46
48
  log = logging.getLogger("socketdev")
47
49
  log.addHandler(logging.NullHandler())
48
50
 
51
+ socket_globs = {
52
+ "npm": {
53
+ "package.json": {
54
+ "pattern": "package.json"
55
+ },
56
+ "package-lock.json": {
57
+ "pattern": "package-lock.json"
58
+ },
59
+ "npm-shrinkwrap.json": {
60
+ "pattern": "npm-shrinkwrap.json"
61
+ },
62
+ "yarn.lock": {
63
+ "pattern": "yarn.lock"
64
+ },
65
+ "pnpm-lock.yaml": {
66
+ "pattern": "pnpm-lock.yaml"
67
+ },
68
+ "pnpm-lock.yml": {
69
+ "pattern": "pnpm-lock.yml"
70
+ },
71
+ "pnpm-workspace.yaml": {
72
+ "pattern": "pnpm-workspace.yaml"
73
+ },
74
+ "pnpm-workspace.yml": {
75
+ "pattern": "pnpm-workspace.yml"
76
+ }
77
+ },
78
+ "pypi": {
79
+ "pipfile": {
80
+ "pattern": "pipfile"
81
+ },
82
+ "pyproject.toml": {
83
+ "pattern": "pyproject.toml"
84
+ },
85
+ "requirements.txt": {
86
+ "pattern": "*requirements.txt"
87
+ },
88
+ "requirements": {
89
+ "pattern": "requirements/*.txt"
90
+ },
91
+ "requirements-*.txt": {
92
+ "pattern": "requirements-*.txt"
93
+ },
94
+ "requirements_*.txt": {
95
+ "pattern": "requirements_*.txt"
96
+ },
97
+ "requirements.frozen": {
98
+ "pattern": "requirements.frozen"
99
+ },
100
+ "setup.py": {
101
+ "pattern": "setup.py"
102
+ }
103
+ },
104
+ "golang": {
105
+ "go.mod": {
106
+ "pattern": "go.mod"
107
+ },
108
+ "go.sum": {
109
+ "pattern": "go.sum"
110
+ }
111
+ },
112
+ "java": {
113
+ "pom.xml": {
114
+ "pattern": "pom.xml"
115
+ }
116
+ }
117
+ }
118
+
49
119
 
50
120
  def encode_key(token: str) -> None:
51
121
  """
@@ -287,125 +357,61 @@ class Core:
287
357
  return manifest_files
288
358
 
289
359
  @staticmethod
290
- def create_sbom_output(diff: Diff) -> list:
291
- sbom = []
292
- for package_id in diff.packages:
293
- package: Package
294
- package = diff.packages[package_id]
295
- manifest_files = Core.get_manifest_files(package, diff.packages)
296
- item = {
297
- "id": package.id,
298
- "license": package.license,
299
- "license_text": package.license_text,
300
- "manifestFiles": manifest_files,
301
- "score": package.score,
302
- "size": package.size,
303
- "ecosystem": package.type,
304
- "alerts": package.alerts,
305
- "direct": package.direct,
306
- "name": package.name,
307
- "version": package.version,
308
- "author": package.author,
309
- "url": package.url
310
- }
311
- sbom.append(item)
360
+ def create_sbom_output(diff: Diff) -> dict:
361
+ base_path = f"orgs/{org_slug}/export/cdx"
362
+ path = f"{base_path}/{diff.id}"
363
+ result = do_request(path=path)
364
+ try:
365
+ sbom = result.json()
366
+ except Exception as error:
367
+ log.error(f"Unable to get CycloneDX Output for {diff.id}")
368
+ log.error(error)
369
+ sbom = {}
312
370
  return sbom
313
371
 
314
372
  @staticmethod
315
- def find_files(path: str, new_files: list = None) -> list:
373
+ def match_supported_files(path: str, files: list) -> list:
374
+ matched = []
375
+ for ecosystem in socket_globs:
376
+ patterns = socket_globs[ecosystem]
377
+ for file_name in patterns:
378
+ pattern = patterns[file_name]["pattern"]
379
+ # path_pattern = f"**/{pattern}"
380
+ for file in files:
381
+ if "\\" in file:
382
+ file = file.replace("\\", "/")
383
+ if PurePath(file).match(pattern):
384
+ matched.append(file)
385
+ return matched
386
+
387
+ @staticmethod
388
+ def find_files(path: str, files: list = None) -> list:
316
389
  """
317
390
  Globs the path for supported manifest files.
318
391
  Note: Might move the source to a JSON file
319
392
  :param path: Str - path to where the manifest files are located
320
- :param new_files:
393
+ :param files: override finding the manifest files using the glob matcher
321
394
  :return:
322
395
  """
323
- socket_globs = {
324
- "npm": {
325
- "package.json": {
326
- "pattern": "package.json"
327
- },
328
- "package-lock.json": {
329
- "pattern": "package-lock.json"
330
- },
331
- "npm-shrinkwrap.json": {
332
- "pattern": "npm-shrinkwrap.json"
333
- },
334
- "yarn.lock": {
335
- "pattern": "yarn.lock"
336
- },
337
- "pnpm-lock.yaml": {
338
- "pattern": "pnpm-lock.yaml"
339
- },
340
- "pnpm-lock.yml": {
341
- "pattern": "pnpm-lock.yml"
342
- },
343
- "pnpm-workspace.yaml": {
344
- "pattern": "pnpm-workspace.yaml"
345
- },
346
- "pnpm-workspace.yml": {
347
- "pattern": "pnpm-workspace.yml"
348
- }
349
- },
350
- "pypi": {
351
- "pipfile": {
352
- "pattern": "pipfile"
353
- },
354
- "pyproject.toml": {
355
- "pattern": "pyproject.toml"
356
- },
357
- "requirements.txt": {
358
- "pattern": "*requirements.txt"
359
- },
360
- "requirements": {
361
- "pattern": "requirements/*.txt"
362
- },
363
- "requirements-*.txt": {
364
- "pattern": "requirements-*.txt"
365
- },
366
- "requirements_*.txt": {
367
- "pattern": "requirements_*.txt"
368
- },
369
- "requirements.frozen": {
370
- "pattern": "requirements.frozen"
371
- },
372
- "setup.py": {
373
- "pattern": "setup.py"
374
- }
375
- },
376
- "golang": {
377
- "go.mod": {
378
- "pattern": "go.mod"
379
- },
380
- "go.sum": {
381
- "pattern": "go.sum"
382
- }
383
- },
384
- "java": {
385
- "pom.xml": {
386
- "pattern": "pom.xml"
387
- }
388
- }
389
- }
390
396
  all_files = []
391
397
  for ecosystem in socket_globs:
392
398
  patterns = socket_globs[ecosystem]
393
399
  for file_name in patterns:
394
400
  pattern = patterns[file_name]["pattern"]
395
401
  file_path = f"{path}/**/{pattern}"
396
- files = glob(file_path, recursive=True)
402
+ if files is None or len(files) == 0:
403
+ files = glob(file_path, recursive=True)
404
+ else:
405
+ files = Core.match_supported_files(path, files)
397
406
  for file in files:
398
- if "/" in file:
399
- _, base_name = file.rsplit("/", 1)
400
- else:
401
- base_name = file
402
- if new_files is not None and len(new_files) > 0 and base_name not in new_files:
403
- continue
404
407
  if platform.system() == "Windows":
405
408
  file = file.replace("\\", "/")
409
+ if path not in file:
410
+ file = f"{path}/{file}"
406
411
  found_path, file_name = file.rsplit("/", 1)
407
412
  details = (found_path, file_name)
408
- all_files.append(details)
413
+ if details not in all_files:
414
+ all_files.append(details)
409
415
  return all_files
410
416
 
411
417
  @staticmethod
@@ -480,7 +486,13 @@ class Core:
480
486
  return full_scan
481
487
 
482
488
  @staticmethod
483
- def create_new_diff(path: str, params: FullScanParams, workspace: str, new_files: list = None) -> Diff:
489
+ def create_new_diff(
490
+ path: str,
491
+ params: FullScanParams,
492
+ workspace: str,
493
+ new_files: list = None,
494
+ no_change: bool = False
495
+ ) -> Diff:
484
496
  """
485
497
  1. Get the head full scan. If it isn't present because this repo doesn't exist yet return an Empty full scan.
486
498
  2. Create a new Full scan for the current run
@@ -490,9 +502,14 @@ class Core:
490
502
  :param params: FullScanParams - Query params for the Full Scan endpoint
491
503
  :param workspace: str - Path for workspace
492
504
  :param new_files:
505
+ :param no_change:
493
506
  :return:
494
507
  """
508
+ if no_change:
509
+ return Diff()
495
510
  files = Core.find_files(path, new_files)
511
+ if files is None or len(files) == 0:
512
+ return Diff()
496
513
  try:
497
514
  head_full_scan_id = Core.get_head_scan_for_repo(params.repo)
498
515
  if head_full_scan_id is None or head_full_scan_id == "":
@@ -505,17 +522,15 @@ class Core:
505
522
  log.info(f"Total time to get head full-scan {total_head_time: .2f}")
506
523
  except APIResourceNotFound:
507
524
  head_full_scan = []
508
- if files is not None and len(files) > 0:
509
- new_scan_start = time.time()
510
- new_full_scan = Core.create_full_scan(files, params, workspace)
511
- new_full_scan.packages = Core.create_sbom_dict(new_full_scan.sbom_artifacts)
512
- new_scan_end = time.time()
513
- total_new_time = new_scan_end - new_scan_start
514
- log.info(f"Total time to get new full-scan {total_new_time: .2f}")
515
- diff_report = Core.compare_sboms(new_full_scan.sbom_artifacts, head_full_scan)
516
- diff_report.packages = new_full_scan.packages
517
- else:
518
- diff_report = Diff()
525
+ new_scan_start = time.time()
526
+ new_full_scan = Core.create_full_scan(files, params, workspace)
527
+ new_full_scan.packages = Core.create_sbom_dict(new_full_scan.sbom_artifacts)
528
+ new_scan_end = time.time()
529
+ total_new_time = new_scan_end - new_scan_start
530
+ log.info(f"Total time to get new full-scan {total_new_time: .2f}")
531
+ diff_report = Core.compare_sboms(new_full_scan.sbom_artifacts, head_full_scan)
532
+ diff_report.packages = new_full_scan.packages
533
+ diff_report.id = new_full_scan.id
519
534
  return diff_report
520
535
 
521
536
  @staticmethod
@@ -622,30 +637,16 @@ class Core:
622
637
  if alert_key not in head_scan_alerts:
623
638
  new_alerts = new_scan_alerts[alert_key]
624
639
  for alert in new_alerts:
625
- if Core.is_error(alert):
640
+ if alert.error or alert.warn:
626
641
  alerts.append(alert)
627
642
  else:
628
643
  new_alerts = new_scan_alerts[alert_key]
629
644
  head_alerts = head_scan_alerts[alert_key]
630
645
  for alert in new_alerts:
631
- if alert not in head_alerts and Core.is_error(alert):
646
+ if alert not in head_alerts and (alert.error or alert.warn):
632
647
  alerts.append(alert)
633
648
  return alerts
634
649
 
635
- @staticmethod
636
- def is_error(alert: Alert):
637
- """
638
- Compare the current alert against the Security Policy to determine if it should be included. Can be overridden
639
- with all_new_alerts Global setting if desired to return all alerts and not just the error category from the
640
- security policy.
641
- :param alert:
642
- :return:
643
- """
644
- if all_new_alerts or (alert.type in security_policy and security_policy[alert.type]['action'] == "error"):
645
- return True
646
- else:
647
- return False
648
-
649
650
  @staticmethod
650
651
  def create_issue_alerts(package: Package, alerts: dict, packages: dict) -> dict:
651
652
  """
@@ -689,6 +690,9 @@ class Core:
689
690
  purl=package.purl,
690
691
  url=package.url
691
692
  )
693
+ if alert.type in security_policy:
694
+ action = security_policy[alert.type]['action']
695
+ setattr(issue_alert, action, True)
692
696
  if issue_alert.key not in alerts:
693
697
  alerts[issue_alert.key] = [issue_alert]
694
698
  else:
@@ -140,7 +140,10 @@ class Issue:
140
140
  pkg_id: str
141
141
  props: dict
142
142
  key: str
143
- is_error: bool
143
+ error: bool
144
+ warn: bool
145
+ ignore: bool
146
+ monitor: bool
144
147
  description: str
145
148
  title: str
146
149
  emoji: str
@@ -162,6 +165,14 @@ class Issue:
162
165
  self.introduced_by = []
163
166
  if not hasattr(self, "manifests"):
164
167
  self.manifests = ""
168
+ if not hasattr(self, "error"):
169
+ self.error = False
170
+ if not hasattr(self, "warn"):
171
+ self.warn = False
172
+ if not hasattr(self, "monitor"):
173
+ self.monitor = False
174
+ if not hasattr(self, "ignore"):
175
+ self.ignore = False
165
176
 
166
177
  def __str__(self):
167
178
  return json.dumps(self.__dict__)
@@ -9,10 +9,13 @@ class Messages:
9
9
 
10
10
  @staticmethod
11
11
  def create_security_comment_json(diff: Diff) -> dict:
12
+ scan_failed = False
12
13
  if len(diff.new_alerts) == 0:
13
- scan_failed = False
14
- else:
15
- scan_failed = True
14
+ for alert in diff.new_alerts:
15
+ alert: Issue
16
+ if alert.error:
17
+ scan_failed = True
18
+ break
16
19
  output = {
17
20
  "scan_failed": scan_failed,
18
21
  "new_alerts": []
@@ -22,7 +25,6 @@ class Messages:
22
25
  output["new_alerts"].append(json.loads(str(alert)))
23
26
  return output
24
27
 
25
-
26
28
  @staticmethod
27
29
  def security_comment_template(diff: Diff) -> str:
28
30
  """
@@ -130,7 +132,8 @@ class Messages:
130
132
  "Alert",
131
133
  "Package",
132
134
  "Introduced by",
133
- "Manifest File"
135
+ "Manifest File",
136
+ "CI"
134
137
  ]
135
138
  num_of_alert_columns = len(alert_table)
136
139
  next_steps = {}
@@ -147,11 +150,16 @@ class Messages:
147
150
  ignore_commands.append(ignore)
148
151
  manifest_str, sources = Messages.create_sources(alert, "console")
149
152
  purl_url = f"[{alert.purl}]({alert.url})"
153
+ if alert.error:
154
+ emoji = ':no_entry_sign:'
155
+ else:
156
+ emoji = ':warning:'
150
157
  row = [
151
158
  alert.title,
152
159
  purl_url,
153
160
  ", ".join(sources),
154
- manifest_str
161
+ manifest_str,
162
+ emoji
155
163
  ]
156
164
  if row not in alert_table:
157
165
  alert_table.extend(row)
@@ -262,17 +270,27 @@ class Messages:
262
270
  "Alert",
263
271
  "Package",
264
272
  "Introduced by",
265
- "Manifest File"
273
+ "Manifest File",
274
+ "CI Status"
266
275
  ]
267
276
  )
268
277
  for alert in diff.new_alerts:
269
278
  alert: Issue
270
279
  manifest_str, sources = Messages.create_sources(alert, "console")
280
+ if alert.error:
281
+ state = "block"
282
+ elif alert.warn:
283
+ state = "warn"
284
+ elif alert.monitor:
285
+ state = "monitor"
286
+ else:
287
+ state = "ignore"
271
288
  row = [
272
289
  alert.title,
273
290
  alert.url,
274
291
  ", ".join(sources),
275
- manifest_str
292
+ manifest_str,
293
+ state
276
294
  ]
277
295
  alert_table.add_row(row)
278
296
  return alert_table
@@ -1,7 +1,7 @@
1
1
  import argparse
2
2
  import json
3
3
  from socketsecurity.core import Core, __version__
4
- from socketsecurity.core.classes import FullScanParams, Diff, Package
4
+ from socketsecurity.core.classes import FullScanParams, Diff, Package, Alert
5
5
  from socketsecurity.core.messages import Messages
6
6
  from socketsecurity.core.scm_comments import Comments
7
7
  from socketsecurity.core.git_interface import Git
@@ -143,23 +143,42 @@ parser.add_argument(
143
143
  )
144
144
 
145
145
 
146
- def output_console_comments(diff_report) -> None:
146
+ def output_console_comments(diff_report: Diff, sbom_file_name: str = None) -> None:
147
147
  console_security_comment = Messages.create_console_security_alert_table(diff_report)
148
- if len(diff_report.new_alerts) > 0:
148
+ save_sbom_file(diff_report, sbom_file_name)
149
+ if not report_pass(diff_report):
149
150
  log.info("Security issues detected by Socket Security")
150
- log.info(console_security_comment)
151
+ msg = f"\n{console_security_comment}"
152
+ log.info(msg)
151
153
  sys.exit(1)
152
154
  else:
153
155
  log.info("No New Security issues detected by Socket Security")
154
156
 
155
157
 
156
- def output_console_json(diff_report) -> None:
158
+ def output_console_json(diff_report: Diff, sbom_file_name: str = None) -> None:
157
159
  console_security_comment = Messages.create_security_comment_json(diff_report)
160
+ save_sbom_file(diff_report, sbom_file_name)
158
161
  print(json.dumps(console_security_comment))
159
- if len(diff_report.new_alerts) > 0:
162
+ if not report_pass(diff_report):
160
163
  sys.exit(1)
161
164
 
162
165
 
166
+ def report_pass(diff_report: Diff) -> bool:
167
+ report_passed = True
168
+ if len(diff_report.new_alerts) > 0:
169
+ for alert in diff_report.new_alerts:
170
+ alert: Alert
171
+ if report_passed and alert.error:
172
+ report_passed = False
173
+ break
174
+ return report_passed
175
+
176
+
177
+ def save_sbom_file(diff_report: Diff, sbom_file_name: str = None):
178
+ if diff_report is not None and sbom_file_name is not None:
179
+ Core.save_file(sbom_file_name, json.dumps(Core.create_sbom_output(diff_report)))
180
+
181
+
163
182
  def cli():
164
183
  try:
165
184
  main_code()
@@ -200,6 +219,7 @@ def main_code():
200
219
  api_token = os.getenv("SOCKET_SECURITY_API_KEY") or arguments.api_token
201
220
  try:
202
221
  files = json.loads(files)
222
+ is_repo = True
203
223
  except Exception as error:
204
224
  log.error(f"Unable to parse {files}")
205
225
  log.error(error)
@@ -221,7 +241,9 @@ def main_code():
221
241
  commit_message = git_repo.commit_message
222
242
  if len(files) == 0 and not ignore_commit_files:
223
243
  files = git_repo.changed_files
244
+ is_repo = True
224
245
  except InvalidGitRepositoryError:
246
+ is_repo = False
225
247
  pass
226
248
  # git_repo = None
227
249
  if repo is None:
@@ -241,6 +263,10 @@ def main_code():
241
263
  if scm is not None:
242
264
  default_branch = scm.is_default_branch
243
265
 
266
+ if is_repo and files is not None and len(files) == 0 and not ignore_commit_files:
267
+ no_change = True
268
+ else:
269
+ no_change = False
244
270
  base_api_url = os.getenv("BASE_API_URL") or None
245
271
  core = Core(token=api_token, request_timeout=6000, base_api_url=base_api_url)
246
272
  set_as_pending_head = False
@@ -266,7 +292,7 @@ def main_code():
266
292
  elif scm is not None and scm.check_event_type() != "comment":
267
293
  log.info("Push initiated flow")
268
294
  diff: Diff
269
- diff = core.create_new_diff(target_path, params, workspace=target_path, new_files=files)
295
+ diff = core.create_new_diff(target_path, params, workspace=target_path, new_files=files, no_change=no_change)
270
296
  if scm.check_event_type() == "diff":
271
297
  log.info("Starting comment logic for PR/MR event")
272
298
  log.debug(f"Getting comments for Repo {scm.repository} for PR {scm.pr_number}")
@@ -297,17 +323,17 @@ def main_code():
297
323
  log.info("Not a PR/MR event no comment needed")
298
324
  if enable_json:
299
325
  log.debug("Outputting JSON Results")
300
- output_console_json(diff)
326
+ output_console_json(diff, sbom_file)
301
327
  else:
302
- output_console_comments(diff)
328
+ output_console_comments(diff, sbom_file)
303
329
  else:
304
330
  log.info("API Mode")
305
331
  diff: Diff
306
- diff = core.create_new_diff(target_path, params, workspace=target_path, new_files=files)
332
+ diff = core.create_new_diff(target_path, params, workspace=target_path, new_files=files, no_change=no_change)
307
333
  if enable_json:
308
- output_console_json(diff)
334
+ output_console_json(diff, sbom_file)
309
335
  else:
310
- output_console_comments(diff)
336
+ output_console_comments(diff, sbom_file)
311
337
  if diff is not None and license_mode:
312
338
  all_packages = {}
313
339
  for package_id in diff.packages:
@@ -325,8 +351,6 @@ def main_code():
325
351
  }
326
352
  all_packages[package_id] = output
327
353
  core.save_file(license_file, json.dumps(all_packages))
328
- if diff is not None and sbom_file is not None:
329
- core.save_file(sbom_file, json.dumps(core.create_sbom_output(diff)))
330
354
 
331
355
 
332
356
  if __name__ == '__main__':
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: socketsecurity
3
- Version: 0.0.98
3
+ Version: 1.0.0
4
4
  Summary: Socket Security CLI for CI/CD
5
5
  Author-email: Douglas Coburn <douglas@socket.dev>
6
6
  Maintainer-email: Douglas Coburn <douglas@socket.dev>
File without changes