socketsecurity 0.0.97__tar.gz → 0.0.99__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.97/socketsecurity.egg-info → socketsecurity-0.0.99}/PKG-INFO +3 -2
  2. {socketsecurity-0.0.97 → socketsecurity-0.0.99}/README.md +2 -1
  3. {socketsecurity-0.0.97 → socketsecurity-0.0.99}/socketsecurity/__init__.py +1 -1
  4. {socketsecurity-0.0.97 → socketsecurity-0.0.99}/socketsecurity/core/__init__.py +126 -111
  5. {socketsecurity-0.0.97 → socketsecurity-0.0.99}/socketsecurity/socketcli.py +30 -11
  6. {socketsecurity-0.0.97 → socketsecurity-0.0.99/socketsecurity.egg-info}/PKG-INFO +3 -2
  7. {socketsecurity-0.0.97 → socketsecurity-0.0.99}/LICENSE +0 -0
  8. {socketsecurity-0.0.97 → socketsecurity-0.0.99}/pyproject.toml +0 -0
  9. {socketsecurity-0.0.97 → socketsecurity-0.0.99}/setup.cfg +0 -0
  10. {socketsecurity-0.0.97 → socketsecurity-0.0.99}/socketsecurity/core/classes.py +0 -0
  11. {socketsecurity-0.0.97 → socketsecurity-0.0.99}/socketsecurity/core/exceptions.py +0 -0
  12. {socketsecurity-0.0.97 → socketsecurity-0.0.99}/socketsecurity/core/git_interface.py +0 -0
  13. {socketsecurity-0.0.97 → socketsecurity-0.0.99}/socketsecurity/core/github.py +0 -0
  14. {socketsecurity-0.0.97 → socketsecurity-0.0.99}/socketsecurity/core/gitlab.py +0 -0
  15. {socketsecurity-0.0.97 → socketsecurity-0.0.99}/socketsecurity/core/issues.py +0 -0
  16. {socketsecurity-0.0.97 → socketsecurity-0.0.99}/socketsecurity/core/licenses.py +0 -0
  17. {socketsecurity-0.0.97 → socketsecurity-0.0.99}/socketsecurity/core/messages.py +0 -0
  18. {socketsecurity-0.0.97 → socketsecurity-0.0.99}/socketsecurity/core/scm_comments.py +0 -0
  19. {socketsecurity-0.0.97 → socketsecurity-0.0.99}/socketsecurity.egg-info/SOURCES.txt +0 -0
  20. {socketsecurity-0.0.97 → socketsecurity-0.0.99}/socketsecurity.egg-info/dependency_links.txt +0 -0
  21. {socketsecurity-0.0.97 → socketsecurity-0.0.99}/socketsecurity.egg-info/entry_points.txt +0 -0
  22. {socketsecurity-0.0.97 → socketsecurity-0.0.99}/socketsecurity.egg-info/requires.txt +0 -0
  23. {socketsecurity-0.0.97 → socketsecurity-0.0.99}/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.97
3
+ Version: 0.0.99
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>
@@ -31,7 +31,7 @@ The Socket Security CLI was created to enable integrations with other tools like
31
31
  socketcli [-h] [--api_token API_TOKEN] [--repo REPO] [--branch BRANCH] [--committer COMMITTER] [--pr_number PR_NUMBER]
32
32
  [--commit_message COMMIT_MESSAGE] [--default_branch] [--target_path TARGET_PATH] [--scm {api,github,gitlab}] [--sbom-file SBOM_FILE]
33
33
  [--commit-sha COMMIT_SHA] [--generate-license GENERATE_LICENSE] [-v] [--enable-debug] [--enable-json] [--disable-overview]
34
- [--disable-security-issue] [--files FILES]
34
+ [--disable-security-issue] [--files FILES] [--ignore-commit-files]
35
35
  ````
36
36
 
37
37
  If you don't want to provide the Socket API Token every time then you can use the environment variable `SOCKET_SECURITY_API_KEY`
@@ -59,3 +59,4 @@ If you don't want to provide the Socket API Token every time then you can use th
59
59
  | --disable-overview | | False | False | If enabled will disable Dependency Overview comments |
60
60
  | --disable-security-issue | | False | False | If enabled will disable Security Issue Comments |
61
61
  | --files | | False | | If provided in the format of `["file1", "file2"]` it will only look for those files and not glob the path |
62
+ | --ignore-commit-files | | False | False | If enabled then the CLI will ignore what files are changed in the commit and look for all manifest files |
@@ -8,7 +8,7 @@ The Socket Security CLI was created to enable integrations with other tools like
8
8
  socketcli [-h] [--api_token API_TOKEN] [--repo REPO] [--branch BRANCH] [--committer COMMITTER] [--pr_number PR_NUMBER]
9
9
  [--commit_message COMMIT_MESSAGE] [--default_branch] [--target_path TARGET_PATH] [--scm {api,github,gitlab}] [--sbom-file SBOM_FILE]
10
10
  [--commit-sha COMMIT_SHA] [--generate-license GENERATE_LICENSE] [-v] [--enable-debug] [--enable-json] [--disable-overview]
11
- [--disable-security-issue] [--files FILES]
11
+ [--disable-security-issue] [--files FILES] [--ignore-commit-files]
12
12
  ````
13
13
 
14
14
  If you don't want to provide the Socket API Token every time then you can use the environment variable `SOCKET_SECURITY_API_KEY`
@@ -36,3 +36,4 @@ If you don't want to provide the Socket API Token every time then you can use th
36
36
  | --disable-overview | | False | False | If enabled will disable Dependency Overview comments |
37
37
  | --disable-security-issue | | False | False | If enabled will disable Security Issue Comments |
38
38
  | --files | | False | | If provided in the format of `["file1", "file2"]` it will only look for those files and not glob the path |
39
+ | --ignore-commit-files | | False | False | If enabled then the CLI will ignore what files are changed in the commit and look for all manifest files |
@@ -1,2 +1,2 @@
1
1
  __author__ = 'socket.dev'
2
- __version__ = '0.0.97'
2
+ __version__ = '0.0.99'
@@ -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
@@ -135,9 +135,17 @@ parser.add_argument(
135
135
  default="[]"
136
136
  )
137
137
 
138
+ parser.add_argument(
139
+ '--ignore-commit-files',
140
+ help='Ignores only looking for changed files form the commit. Will find any supported manifest file type',
141
+ action='store_true',
142
+ default=False
143
+ )
138
144
 
139
- def output_console_comments(diff_report) -> None:
145
+
146
+ def output_console_comments(diff_report: Diff, sbom_file_name: str = None) -> None:
140
147
  console_security_comment = Messages.create_console_security_alert_table(diff_report)
148
+ save_sbom_file(diff_report, sbom_file_name)
141
149
  if len(diff_report.new_alerts) > 0:
142
150
  log.info("Security issues detected by Socket Security")
143
151
  log.info(console_security_comment)
@@ -146,13 +154,18 @@ def output_console_comments(diff_report) -> None:
146
154
  log.info("No New Security issues detected by Socket Security")
147
155
 
148
156
 
149
- def output_console_json(diff_report) -> None:
157
+ def output_console_json(diff_report: Diff, sbom_file_name: str = None) -> None:
150
158
  console_security_comment = Messages.create_security_comment_json(diff_report)
159
+ save_sbom_file(diff_report, sbom_file_name)
151
160
  print(json.dumps(console_security_comment))
152
161
  if len(diff_report.new_alerts) > 0:
153
162
  sys.exit(1)
154
163
 
155
164
 
165
+ def save_sbom_file(diff_report: Diff, sbom_file_name: str = None):
166
+ if diff_report is not None and sbom_file_name is not None:
167
+ Core.save_file(sbom_file_name, json.dumps(Core.create_sbom_output(diff_report)))
168
+
156
169
  def cli():
157
170
  try:
158
171
  main_code()
@@ -187,11 +200,13 @@ def main_code():
187
200
  enable_json = arguments.enable_json
188
201
  disable_overview = arguments.disable_overview
189
202
  disable_security_issue = arguments.disable_security_issue
203
+ ignore_commit_files = arguments.ignore_commit_files
190
204
  files = arguments.files
191
205
  log.info(f"Starting Socket Security Scan version {__version__}")
192
206
  api_token = os.getenv("SOCKET_SECURITY_API_KEY") or arguments.api_token
193
207
  try:
194
208
  files = json.loads(files)
209
+ is_repo = True
195
210
  except Exception as error:
196
211
  log.error(f"Unable to parse {files}")
197
212
  log.error(error)
@@ -211,9 +226,11 @@ def main_code():
211
226
  committer = git_repo.committer
212
227
  if commit_message is None or commit_message == '':
213
228
  commit_message = git_repo.commit_message
214
- if len(files) == 0:
229
+ if len(files) == 0 and not ignore_commit_files:
215
230
  files = git_repo.changed_files
231
+ is_repo = True
216
232
  except InvalidGitRepositoryError:
233
+ is_repo = False
217
234
  pass
218
235
  # git_repo = None
219
236
  if repo is None:
@@ -233,6 +250,10 @@ def main_code():
233
250
  if scm is not None:
234
251
  default_branch = scm.is_default_branch
235
252
 
253
+ if is_repo and files is not None and len(files) == 0 and not ignore_commit_files:
254
+ no_change = True
255
+ else:
256
+ no_change = False
236
257
  base_api_url = os.getenv("BASE_API_URL") or None
237
258
  core = Core(token=api_token, request_timeout=6000, base_api_url=base_api_url)
238
259
  set_as_pending_head = False
@@ -258,7 +279,7 @@ def main_code():
258
279
  elif scm is not None and scm.check_event_type() != "comment":
259
280
  log.info("Push initiated flow")
260
281
  diff: Diff
261
- diff = core.create_new_diff(target_path, params, workspace=target_path, new_files=files)
282
+ diff = core.create_new_diff(target_path, params, workspace=target_path, new_files=files, no_change=no_change)
262
283
  if scm.check_event_type() == "diff":
263
284
  log.info("Starting comment logic for PR/MR event")
264
285
  log.debug(f"Getting comments for Repo {scm.repository} for PR {scm.pr_number}")
@@ -289,17 +310,17 @@ def main_code():
289
310
  log.info("Not a PR/MR event no comment needed")
290
311
  if enable_json:
291
312
  log.debug("Outputting JSON Results")
292
- output_console_json(diff)
313
+ output_console_json(diff, sbom_file)
293
314
  else:
294
- output_console_comments(diff)
315
+ output_console_comments(diff, sbom_file)
295
316
  else:
296
317
  log.info("API Mode")
297
318
  diff: Diff
298
- diff = core.create_new_diff(target_path, params, workspace=target_path, new_files=files)
319
+ diff = core.create_new_diff(target_path, params, workspace=target_path, new_files=files, no_change=no_change)
299
320
  if enable_json:
300
- output_console_json(diff)
321
+ output_console_json(diff, sbom_file)
301
322
  else:
302
- output_console_comments(diff)
323
+ output_console_comments(diff, sbom_file)
303
324
  if diff is not None and license_mode:
304
325
  all_packages = {}
305
326
  for package_id in diff.packages:
@@ -317,8 +338,6 @@ def main_code():
317
338
  }
318
339
  all_packages[package_id] = output
319
340
  core.save_file(license_file, json.dumps(all_packages))
320
- if diff is not None and sbom_file is not None:
321
- core.save_file(sbom_file, json.dumps(core.create_sbom_output(diff)))
322
341
 
323
342
 
324
343
  if __name__ == '__main__':
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: socketsecurity
3
- Version: 0.0.97
3
+ Version: 0.0.99
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>
@@ -31,7 +31,7 @@ The Socket Security CLI was created to enable integrations with other tools like
31
31
  socketcli [-h] [--api_token API_TOKEN] [--repo REPO] [--branch BRANCH] [--committer COMMITTER] [--pr_number PR_NUMBER]
32
32
  [--commit_message COMMIT_MESSAGE] [--default_branch] [--target_path TARGET_PATH] [--scm {api,github,gitlab}] [--sbom-file SBOM_FILE]
33
33
  [--commit-sha COMMIT_SHA] [--generate-license GENERATE_LICENSE] [-v] [--enable-debug] [--enable-json] [--disable-overview]
34
- [--disable-security-issue] [--files FILES]
34
+ [--disable-security-issue] [--files FILES] [--ignore-commit-files]
35
35
  ````
36
36
 
37
37
  If you don't want to provide the Socket API Token every time then you can use the environment variable `SOCKET_SECURITY_API_KEY`
@@ -59,3 +59,4 @@ If you don't want to provide the Socket API Token every time then you can use th
59
59
  | --disable-overview | | False | False | If enabled will disable Dependency Overview comments |
60
60
  | --disable-security-issue | | False | False | If enabled will disable Security Issue Comments |
61
61
  | --files | | False | | If provided in the format of `["file1", "file2"]` it will only look for those files and not glob the path |
62
+ | --ignore-commit-files | | False | False | If enabled then the CLI will ignore what files are changed in the commit and look for all manifest files |
File without changes