socketsecurity 2.2.90__tar.gz → 2.2.91__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 (134) hide show
  1. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/.github/workflows/version-check.yml +36 -9
  2. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/.hooks/sync_version.py +56 -7
  3. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/PKG-INFO +33 -3
  4. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/README.md +30 -0
  5. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/pyproject.toml +3 -3
  6. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/__init__.py +1 -1
  7. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/config.py +70 -0
  8. socketsecurity-2.2.91/socketsecurity/fossa_compat.py +459 -0
  9. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/output.py +107 -46
  10. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/socketcli.py +46 -21
  11. socketsecurity-2.2.91/tests/fixtures/fossa/README.md +18 -0
  12. socketsecurity-2.2.91/tests/fixtures/fossa/fossa-analyze-empty.json +13 -0
  13. socketsecurity-2.2.91/tests/fixtures/fossa/fossa-analyze-populated.json +1275 -0
  14. socketsecurity-2.2.91/tests/fixtures/fossa/fossa-sbom-empty-deep.json +1 -0
  15. socketsecurity-2.2.91/tests/fixtures/fossa/fossa-sbom-populated.json +1 -0
  16. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/unit/test_cli_config.py +47 -2
  17. socketsecurity-2.2.91/tests/unit/test_fossa_compat.py +470 -0
  18. socketsecurity-2.2.91/tests/unit/test_fossa_parity.py +106 -0
  19. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/unit/test_output.py +265 -24
  20. socketsecurity-2.2.91/tests/unit/test_socketcli.py +134 -0
  21. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/uv.lock +2 -2
  22. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/.github/CODEOWNERS +0 -0
  23. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/.github/PULL_REQUEST_TEMPLATE/bug-fix.md +0 -0
  24. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/.github/PULL_REQUEST_TEMPLATE/feature.md +0 -0
  25. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/.github/PULL_REQUEST_TEMPLATE/improvement.md +0 -0
  26. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  27. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/.github/workflows/docker-stable.yml +0 -0
  28. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/.github/workflows/e2e-test.yml +0 -0
  29. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/.github/workflows/pr-preview.yml +0 -0
  30. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/.github/workflows/python-tests.yml +0 -0
  31. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/.github/workflows/release.yml +0 -0
  32. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/.github/zizmor.yml +0 -0
  33. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/.gitignore +0 -0
  34. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/.pre-commit-config.yaml +0 -0
  35. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/.python-version +0 -0
  36. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/CHANGELOG.md +0 -0
  37. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/Dockerfile +0 -0
  38. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/LICENSE +0 -0
  39. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/Makefile +0 -0
  40. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/docs/ci-cd.md +0 -0
  41. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/docs/cli-reference.md +0 -0
  42. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/docs/development.md +0 -0
  43. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/docs/troubleshooting.md +0 -0
  44. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/examples/config/sarif-dashboard-parity.json +0 -0
  45. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/examples/config/sarif-dashboard-parity.toml +0 -0
  46. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/examples/config/sarif-diff-ci-cd.json +0 -0
  47. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/examples/config/sarif-diff-ci-cd.toml +0 -0
  48. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/examples/config/sarif-instance-detail.json +0 -0
  49. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/examples/config/sarif-instance-detail.toml +0 -0
  50. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/instructions/gitlab-commit-status/uat.md +0 -0
  51. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/pytest.ini +0 -0
  52. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/scripts/build_container.sh +0 -0
  53. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/scripts/build_container_flexible.sh +0 -0
  54. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/scripts/deploy-test-docker.sh +0 -0
  55. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/scripts/deploy-test-pypi.sh +0 -0
  56. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/scripts/docker-entrypoint.sh +0 -0
  57. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/scripts/run.sh +0 -0
  58. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/session.md +0 -0
  59. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socket.yml +0 -0
  60. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/core/__init__.py +0 -0
  61. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/core/alert_selection.py +0 -0
  62. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/core/classes.py +0 -0
  63. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/core/cli_client.py +0 -0
  64. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/core/exceptions.py +0 -0
  65. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/core/git_interface.py +0 -0
  66. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/core/helper/__init__.py +0 -0
  67. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/core/helper/socket_facts_loader.py +0 -0
  68. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/core/lazy_file_loader.py +0 -0
  69. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/core/logging.py +0 -0
  70. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/core/messages.py +0 -0
  71. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/core/resource_utils.py +0 -0
  72. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/core/scm/__init__.py +0 -0
  73. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/core/scm/base.py +0 -0
  74. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/core/scm/client.py +0 -0
  75. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/core/scm/github.py +0 -0
  76. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/core/scm/gitlab.py +0 -0
  77. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/core/scm_comments.py +0 -0
  78. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/core/socket_config.py +0 -0
  79. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/core/tools/reachability.py +0 -0
  80. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/core/utils.py +0 -0
  81. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/plugins/__init__.py +0 -0
  82. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/plugins/base.py +0 -0
  83. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/plugins/formatters/__init__.py +0 -0
  84. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/plugins/formatters/slack.py +0 -0
  85. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/plugins/jira.py +0 -0
  86. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/plugins/manager.py +0 -0
  87. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/plugins/slack.py +0 -0
  88. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/plugins/teams.py +0 -0
  89. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/socketsecurity/plugins/webhook.py +0 -0
  90. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/__init__.py +0 -0
  91. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/core/conftest.py +0 -0
  92. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/core/create_diff_input.json +0 -0
  93. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/core/test_diff_alerts.py +0 -0
  94. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/core/test_diff_generation.py +0 -0
  95. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/core/test_has_manifest_files.py +0 -0
  96. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/core/test_package_and_alerts.py +0 -0
  97. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/core/test_sdk_methods.py +0 -0
  98. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/core/test_supporting_methods.py +0 -0
  99. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/data/fullscans/create_response.json +0 -0
  100. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/data/fullscans/diff/stream_diff.json +0 -0
  101. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/data/fullscans/diff/stream_diff_full.json +0 -0
  102. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/data/fullscans/head_scan/metadata.json +0 -0
  103. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/data/fullscans/head_scan/stream_scan.json +0 -0
  104. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/data/fullscans/head_scan/stream_scan_full.json +0 -0
  105. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/data/fullscans/new_scan/metadata.json +0 -0
  106. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/data/fullscans/new_scan/stream_scan.json +0 -0
  107. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/data/repos/repo_info_error.json +0 -0
  108. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/data/repos/repo_info_no_head.json +0 -0
  109. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/data/repos/repo_info_success.json +0 -0
  110. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/data/settings/security-policy.json +0 -0
  111. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/e2e/fixtures/simple-npm/index.js +0 -0
  112. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/e2e/fixtures/simple-npm/package.json +0 -0
  113. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/e2e/fixtures/simple-pypi/requirements.txt +0 -0
  114. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/e2e/validate-gitlab.sh +0 -0
  115. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/e2e/validate-json.sh +0 -0
  116. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/e2e/validate-reachability.sh +0 -0
  117. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/e2e/validate-sarif.sh +0 -0
  118. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/e2e/validate-scan.sh +0 -0
  119. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/unit/__init__.py +0 -0
  120. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/unit/test_alert_selection.py +0 -0
  121. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/unit/test_client.py +0 -0
  122. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/unit/test_config.py +0 -0
  123. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/unit/test_dependency_overview.py +0 -0
  124. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/unit/test_disable_ignore.py +0 -0
  125. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/unit/test_gitlab_auth.py +0 -0
  126. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/unit/test_gitlab_auth_fallback.py +0 -0
  127. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/unit/test_gitlab_commit_status.py +0 -0
  128. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/unit/test_gitlab_format.py +0 -0
  129. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/unit/test_ignore_telemetry_filtering.py +0 -0
  130. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/tests/unit/test_slack_plugin.py +0 -0
  131. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/workflows/bitbucket-pipelines.yml +0 -0
  132. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/workflows/buildkite.yml +0 -0
  133. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/workflows/github-actions.yml +0 -0
  134. {socketsecurity-2.2.90 → socketsecurity-2.2.91}/workflows/gitlab-ci.yml +0 -0
@@ -35,16 +35,43 @@ jobs:
35
35
  MAIN_VERSION=$(git show origin/main:socketsecurity/__init__.py | grep -o "__version__.*" | awk '{print $3}' | tr -d "'")
36
36
  echo "MAIN_VERSION=$MAIN_VERSION" >> $GITHUB_ENV
37
37
 
38
- # Compare versions using Python
39
- python3 -c "
38
+ export PR_VERSION
39
+ export MAIN_VERSION
40
+
41
+ # Compare against both main and latest published PyPI release.
42
+ python3 <<'PY'
43
+ import json
44
+ import os
45
+ import urllib.request
40
46
  from packaging import version
41
- pr_ver = version.parse('${PR_VERSION}')
42
- main_ver = version.parse('${MAIN_VERSION}')
43
- if pr_ver <= main_ver:
44
- print(f'❌ Version must be incremented! Main: {main_ver}, PR: {pr_ver}')
45
- exit(1)
46
- print(f'✅ Version properly incremented from {main_ver} to {pr_ver}')
47
- "
47
+
48
+ pr_ver = version.parse(os.environ["PR_VERSION"])
49
+ main_ver = version.parse(os.environ["MAIN_VERSION"])
50
+
51
+ with urllib.request.urlopen("https://pypi.org/pypi/socketsecurity/json") as response:
52
+ pypi_data = json.load(response)
53
+
54
+ published_versions = []
55
+ for raw in pypi_data.get("releases", {}).keys():
56
+ parsed = version.parse(raw)
57
+ if not parsed.is_prerelease and not parsed.is_devrelease:
58
+ published_versions.append(parsed)
59
+
60
+ pypi_ver = max(published_versions) if published_versions else version.parse("0.0.0")
61
+ required_floor = max(main_ver, pypi_ver)
62
+
63
+ if pr_ver <= required_floor:
64
+ print(
65
+ f"❌ Version must be greater than main and PyPI! "
66
+ f"Main: {main_ver}, PyPI: {pypi_ver}, PR: {pr_ver}"
67
+ )
68
+ raise SystemExit(1)
69
+
70
+ print(
71
+ f"✅ Version properly incremented. "
72
+ f"Main: {main_ver}, PyPI: {pypi_ver}, PR: {pr_ver}"
73
+ )
74
+ PY
48
75
 
49
76
  - name: Require uv.lock update when pyproject changes
50
77
  run: |
@@ -12,7 +12,9 @@ UV_LOCK_FILE = pathlib.Path("uv.lock")
12
12
 
13
13
  VERSION_PATTERN = re.compile(r"__version__\s*=\s*['\"]([^'\"]+)['\"]")
14
14
  PYPROJECT_PATTERN = re.compile(r'^version\s*=\s*".*"$', re.MULTILINE)
15
- PYPI_API = "https://test.pypi.org/pypi/socketsecurity/json"
15
+ STABLE_VERSION_PATTERN = re.compile(r"^\d+\.\d+\.\d+$")
16
+ PYPI_PROD_API = "https://pypi.org/pypi/socketsecurity/json"
17
+ PYPI_TEST_API = "https://test.pypi.org/pypi/socketsecurity/json"
16
18
 
17
19
  def read_version_from_init(path: pathlib.Path) -> str:
18
20
  content = path.read_text()
@@ -39,17 +41,39 @@ def bump_patch_version(version: str) -> str:
39
41
  parts[-1] = str(int(parts[-1]) + 1)
40
42
  return ".".join(parts)
41
43
 
42
- def fetch_existing_versions() -> set:
44
+ def parse_stable_version(version: str):
45
+ if not STABLE_VERSION_PATTERN.fullmatch(version):
46
+ return None
47
+ return tuple(int(part) for part in version.split("."))
48
+
49
+
50
+ def format_stable_version(version_parts) -> str:
51
+ return ".".join(str(part) for part in version_parts)
52
+
53
+
54
+ def fetch_existing_versions(api_url: str) -> set:
43
55
  try:
44
- with urllib.request.urlopen(PYPI_API) as response:
56
+ with urllib.request.urlopen(api_url) as response:
45
57
  data = json.load(response)
46
58
  return set(data.get("releases", {}).keys())
47
59
  except Exception as e:
48
- print(f"⚠️ Warning: Failed to fetch existing versions from Test PyPI: {e}")
60
+ print(f"⚠️ Warning: Failed to fetch versions from {api_url}: {e}")
49
61
  return set()
50
62
 
63
+
64
+ def fetch_latest_stable_pypi_version():
65
+ versions = fetch_existing_versions(PYPI_PROD_API)
66
+ stable_versions = []
67
+ for ver in versions:
68
+ parsed = parse_stable_version(ver)
69
+ if parsed is not None:
70
+ stable_versions.append(parsed)
71
+ if not stable_versions:
72
+ return None
73
+ return max(stable_versions)
74
+
51
75
  def find_next_available_dev_version(base_version: str) -> str:
52
- existing_versions = fetch_existing_versions()
76
+ existing_versions = fetch_existing_versions(PYPI_TEST_API)
53
77
  for i in range(1, 100):
54
78
  candidate = f"{base_version}.dev{i}"
55
79
  if candidate not in existing_versions:
@@ -57,6 +81,19 @@ def find_next_available_dev_version(base_version: str) -> str:
57
81
  print("❌ Could not find available .devN slot after 100 attempts.")
58
82
  sys.exit(1)
59
83
 
84
+
85
+ def find_next_stable_patch_version(current_version: str) -> str:
86
+ current_stable = current_version.split(".dev")[0] if ".dev" in current_version else current_version
87
+ current_parts = parse_stable_version(current_stable)
88
+ if current_parts is None:
89
+ print(f"❌ Unsupported version format for stable bump: {current_version}")
90
+ sys.exit(1)
91
+
92
+ latest_pypi_parts = fetch_latest_stable_pypi_version()
93
+ base_parts = max([current_parts, latest_pypi_parts] if latest_pypi_parts else [current_parts])
94
+ next_parts = (base_parts[0], base_parts[1], base_parts[2] + 1)
95
+ return format_stable_version(next_parts)
96
+
60
97
  def inject_version(version: str):
61
98
  print(f"🔁 Updating version to: {version}")
62
99
 
@@ -105,13 +142,25 @@ def main():
105
142
  print(f"⚠️ Version was unchanged — auto-bumped. Please git add{lock_hint} + commit again.")
106
143
  sys.exit(0)
107
144
  else:
108
- new_version = bump_patch_version(current_version)
145
+ new_version = find_next_stable_patch_version(current_version)
109
146
  inject_version(new_version)
110
147
  uv_lock_changed = run_uv_lock()
111
148
  lock_hint = " and uv.lock" if uv_lock_changed else ""
112
- print(f"⚠️ Version was unchanged — auto-bumped. Please git add{lock_hint} + commit again.")
149
+ print(f"⚠️ Version was unchanged — auto-bumped to {new_version}. Please git add{lock_hint} + commit again.")
113
150
  sys.exit(1)
114
151
  else:
152
+ if not dev_mode:
153
+ current_parts = parse_stable_version(current_version)
154
+ latest_pypi_parts = fetch_latest_stable_pypi_version()
155
+ if current_parts is not None and latest_pypi_parts is not None and current_parts <= latest_pypi_parts:
156
+ next_parts = (latest_pypi_parts[0], latest_pypi_parts[1], latest_pypi_parts[2] + 1)
157
+ new_version = format_stable_version(next_parts)
158
+ inject_version(new_version)
159
+ uv_lock_changed = run_uv_lock()
160
+ lock_hint = " and uv.lock" if uv_lock_changed else ""
161
+ print(f"⚠️ Version {current_version} is already published on PyPI — auto-bumped to {new_version}. Please git add{lock_hint} + commit again.")
162
+ sys.exit(1)
163
+
115
164
  uv_lock_changed = run_uv_lock()
116
165
  if uv_lock_changed:
117
166
  print("⚠️ Version already bumped, but uv.lock was out of date and has been updated. Please git add uv.lock + commit again.")
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: socketsecurity
3
- Version: 2.2.90
3
+ Version: 2.2.91
4
4
  Summary: Socket Security CLI for CI/CD
5
- Project-URL: Homepage, https://github.com/SocketDev/socket-python-cli
5
+ Project-URL: Homepage, https://socket.dev
6
6
  Author-email: Douglas Coburn <douglas@socket.dev>
7
7
  Maintainer-email: Douglas Coburn <douglas@socket.dev>
8
8
  License: MIT License
@@ -41,7 +41,7 @@ Requires-Dist: packaging
41
41
  Requires-Dist: prettytable
42
42
  Requires-Dist: python-dotenv
43
43
  Requires-Dist: requests
44
- Requires-Dist: socketdev<4.0.0,>=3.1.0
44
+ Requires-Dist: socketdev<4.0.0,>=3.0.33
45
45
  Provides-Extra: dev
46
46
  Requires-Dist: hatch; extra == 'dev'
47
47
  Requires-Dist: pre-commit; extra == 'dev'
@@ -142,6 +142,7 @@ socketcli \
142
142
  | Use case | Recommended mode | Key flags |
143
143
  |:--|:--|:--|
144
144
  | Basic policy enforcement in CI | Diff-based policy check | `--strict-blocking` |
145
+ | Legal/compliance artifact generation | Legal preset | `--legal` |
145
146
  | Reachable-focused SARIF for reporting | Full-scope grouped SARIF | `--reach --sarif-scope full --sarif-grouping alert --sarif-reachability reachable --sarif-file <path>` |
146
147
  | Detailed reachability export for investigations | Full-scope instance SARIF | `--reach --sarif-scope full --sarif-grouping instance --sarif-reachability all --sarif-file <path>` |
147
148
  | Net-new PR findings only | Diff-scope SARIF | `--reach --sarif-scope diff --sarif-reachability reachable --sarif-file <path>` |
@@ -192,6 +193,35 @@ Run:
192
193
  socketcli --config .socketcli.toml --target-path .
193
194
  ```
194
195
 
196
+ Legal/compliance preset example:
197
+
198
+ ```bash
199
+ socketcli --legal --target-path .
200
+ ```
201
+
202
+ This preset enables license generation and writes default artifacts unless you override them:
203
+ - `socket-report.json`
204
+ - `socket-summary.txt`
205
+ - `socket-report-link.txt`
206
+ - `socket-sbom.json`
207
+ - `socket-license.json`
208
+
209
+ FOSSA-compatibility shaped legal artifacts:
210
+
211
+ ```bash
212
+ socketcli --legal-format fossa --target-path .
213
+ ```
214
+
215
+ This switches the JSON report and legal artifact payloads to FOSSA-style compatibility shapes:
216
+ - the analyze artifact becomes a `project` / `vulnerability` / `licensing` / `quality` report
217
+ - the SBOM artifact becomes a FOSSA-attribution-style payload with `copyrightsByLicense`, `deepDependencies`, `directDependencies`, `licenses`, and `project` keys
218
+
219
+ When `--legal-format fossa` is used without explicit output paths, the defaults are closer to the FOSSA pipeline contract:
220
+ - `fossa-analyze.json`
221
+ - `fossa-test.txt`
222
+ - `fossa-link.txt`
223
+ - `fossa-sbom.json`
224
+
195
225
  Reference sample configs:
196
226
 
197
227
  TOML:
@@ -84,6 +84,7 @@ socketcli \
84
84
  | Use case | Recommended mode | Key flags |
85
85
  |:--|:--|:--|
86
86
  | Basic policy enforcement in CI | Diff-based policy check | `--strict-blocking` |
87
+ | Legal/compliance artifact generation | Legal preset | `--legal` |
87
88
  | Reachable-focused SARIF for reporting | Full-scope grouped SARIF | `--reach --sarif-scope full --sarif-grouping alert --sarif-reachability reachable --sarif-file <path>` |
88
89
  | Detailed reachability export for investigations | Full-scope instance SARIF | `--reach --sarif-scope full --sarif-grouping instance --sarif-reachability all --sarif-file <path>` |
89
90
  | Net-new PR findings only | Diff-scope SARIF | `--reach --sarif-scope diff --sarif-reachability reachable --sarif-file <path>` |
@@ -134,6 +135,35 @@ Run:
134
135
  socketcli --config .socketcli.toml --target-path .
135
136
  ```
136
137
 
138
+ Legal/compliance preset example:
139
+
140
+ ```bash
141
+ socketcli --legal --target-path .
142
+ ```
143
+
144
+ This preset enables license generation and writes default artifacts unless you override them:
145
+ - `socket-report.json`
146
+ - `socket-summary.txt`
147
+ - `socket-report-link.txt`
148
+ - `socket-sbom.json`
149
+ - `socket-license.json`
150
+
151
+ FOSSA-compatibility shaped legal artifacts:
152
+
153
+ ```bash
154
+ socketcli --legal-format fossa --target-path .
155
+ ```
156
+
157
+ This switches the JSON report and legal artifact payloads to FOSSA-style compatibility shapes:
158
+ - the analyze artifact becomes a `project` / `vulnerability` / `licensing` / `quality` report
159
+ - the SBOM artifact becomes a FOSSA-attribution-style payload with `copyrightsByLicense`, `deepDependencies`, `directDependencies`, `licenses`, and `project` keys
160
+
161
+ When `--legal-format fossa` is used without explicit output paths, the defaults are closer to the FOSSA pipeline contract:
162
+ - `fossa-analyze.json`
163
+ - `fossa-test.txt`
164
+ - `fossa-link.txt`
165
+ - `fossa-sbom.json`
166
+
137
167
  Reference sample configs:
138
168
 
139
169
  TOML:
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
 
7
7
  [project]
8
8
  name = "socketsecurity"
9
- version = "2.2.90"
9
+ version = "2.2.91"
10
10
  requires-python = ">= 3.11"
11
11
  license = {"file" = "LICENSE"}
12
12
  dependencies = [
@@ -16,7 +16,7 @@ dependencies = [
16
16
  'GitPython',
17
17
  'packaging',
18
18
  'python-dotenv',
19
- "socketdev>=3.1.0,<4.0.0",
19
+ "socketdev>=3.0.33,<4.0.0",
20
20
  "bs4>=0.0.2",
21
21
  "markdown>=3.10",
22
22
  ]
@@ -57,7 +57,7 @@ socketcli = "socketsecurity.socketcli:cli"
57
57
  socketclidev = "socketsecurity.socketcli:cli"
58
58
 
59
59
  [project.urls]
60
- Homepage = "https://github.com/SocketDev/socket-python-cli"
60
+ Homepage = "https://socket.dev"
61
61
 
62
62
  [tool.coverage.run]
63
63
  source = ["socketsecurity"]
@@ -1,3 +1,3 @@
1
1
  __author__ = 'socket.dev'
2
- __version__ = '2.2.90'
2
+ __version__ = '2.2.91'
3
3
  USER_AGENT = f'SocketPythonCLI/{__version__}'
@@ -79,6 +79,7 @@ class CliConfig:
79
79
  enable_debug: bool = False
80
80
  allow_unverified: bool = False
81
81
  enable_json: bool = False
82
+ json_file: Optional[str] = None
82
83
  enable_sarif: bool = False
83
84
  sarif_file: Optional[str] = None
84
85
  sarif_scope: str = "diff"
@@ -86,6 +87,8 @@ class CliConfig:
86
87
  sarif_reachability: str = "all"
87
88
  enable_gitlab_security: bool = False
88
89
  gitlab_security_file: Optional[str] = None
90
+ summary_file: Optional[str] = None
91
+ report_link_file: Optional[str] = None
89
92
  disable_overview: bool = False
90
93
  disable_security_issue: bool = False
91
94
  files: str = None
@@ -137,6 +140,8 @@ class CliConfig:
137
140
  reach_continue_on_no_source_files: bool = False
138
141
  max_purl_batch_size: int = 5000
139
142
  enable_commit_status: bool = False
143
+ legal: bool = False
144
+ legal_format: str = "socket"
140
145
  config_file: Optional[str] = None
141
146
 
142
147
  @classmethod
@@ -194,6 +199,7 @@ class CliConfig:
194
199
  'enable_diff': args.enable_diff,
195
200
  'allow_unverified': args.allow_unverified,
196
201
  'enable_json': args.enable_json,
202
+ 'json_file': args.json_file,
197
203
  'enable_sarif': args.enable_sarif,
198
204
  'sarif_file': args.sarif_file,
199
205
  'sarif_scope': args.sarif_scope,
@@ -201,6 +207,8 @@ class CliConfig:
201
207
  'sarif_reachability': args.sarif_reachability,
202
208
  'enable_gitlab_security': args.enable_gitlab_security,
203
209
  'gitlab_security_file': args.gitlab_security_file,
210
+ 'summary_file': args.summary_file,
211
+ 'report_link_file': args.report_link_file,
204
212
  'disable_overview': args.disable_overview,
205
213
  'disable_security_issue': args.disable_security_issue,
206
214
  'files': args.files,
@@ -246,9 +254,40 @@ class CliConfig:
246
254
  'reach_continue_on_no_source_files': args.reach_continue_on_no_source_files,
247
255
  'max_purl_batch_size': args.max_purl_batch_size,
248
256
  'enable_commit_status': args.enable_commit_status,
257
+ 'legal': args.legal or args.legal_format == "fossa",
258
+ 'legal_format': args.legal_format,
249
259
  'config_file': args.config_file,
250
260
  'version': __version__
251
261
  }
262
+
263
+ if config_args['legal']:
264
+ config_args['generate_license'] = True
265
+ if not config_args['json_file']:
266
+ config_args['json_file'] = "socket-report.json"
267
+ if not config_args['summary_file']:
268
+ config_args['summary_file'] = "socket-summary.txt"
269
+ if not config_args['report_link_file']:
270
+ config_args['report_link_file'] = "socket-report-link.txt"
271
+ if not config_args['sbom_file']:
272
+ config_args['sbom_file'] = "socket-sbom.json"
273
+ if config_args['license_file_name'] == "license_output.json":
274
+ config_args['license_file_name'] = "socket-license.json"
275
+
276
+ if config_args['legal_format'] == "fossa":
277
+ if not args.json_file:
278
+ config_args['json_file'] = "fossa-analyze.json"
279
+ if not args.summary_file:
280
+ config_args['summary_file'] = "fossa-test.txt"
281
+ if not args.report_link_file:
282
+ config_args['report_link_file'] = "fossa-link.txt"
283
+ if not args.license_file_name:
284
+ # argparse always provides a default, so this branch is defensive only
285
+ config_args['license_file_name'] = "fossa-sbom.json"
286
+ elif args.license_file_name == "license_output.json":
287
+ config_args['license_file_name'] = "fossa-sbom.json"
288
+ if not args.sbom_file:
289
+ # FOSSA's "SBOM" artifact is the attribution payload; suppress the extra Socket-only SBOM file by default.
290
+ config_args['sbom_file'] = None
252
291
  excluded_ecosystems = config_args["excluded_ecosystems"]
253
292
  if isinstance(excluded_ecosystems, list):
254
293
  config_args["excluded_ecosystems"] = excluded_ecosystems
@@ -570,6 +609,12 @@ def create_argument_parser() -> argparse.ArgumentParser:
570
609
  action="store_true",
571
610
  help="Output in JSON format"
572
611
  )
612
+ output_group.add_argument(
613
+ "--json-file",
614
+ dest="json_file",
615
+ metavar="<path>",
616
+ help="Output file path for JSON report"
617
+ )
573
618
  output_group.add_argument(
574
619
  "--enable-sarif",
575
620
  dest="enable_sarif",
@@ -617,6 +662,18 @@ def create_argument_parser() -> argparse.ArgumentParser:
617
662
  default="gl-dependency-scanning-report.json",
618
663
  help="Output file path for GitLab Security report (default: gl-dependency-scanning-report.json)"
619
664
  )
665
+ output_group.add_argument(
666
+ "--summary-file",
667
+ dest="summary_file",
668
+ metavar="<path>",
669
+ help="Output file path for a plain-text summary report"
670
+ )
671
+ output_group.add_argument(
672
+ "--report-link-file",
673
+ dest="report_link_file",
674
+ metavar="<path>",
675
+ help="Output file path for the Socket report link"
676
+ )
620
677
  output_group.add_argument(
621
678
  "--disable-overview",
622
679
  dest="disable_overview",
@@ -750,6 +807,19 @@ def create_argument_parser() -> argparse.ArgumentParser:
750
807
  action="store_true",
751
808
  help="Disable SSL certificate verification for API requests"
752
809
  )
810
+ advanced_group.add_argument(
811
+ "--legal",
812
+ dest="legal",
813
+ action="store_true",
814
+ help="Enable legal/compliance-friendly defaults and file outputs"
815
+ )
816
+ advanced_group.add_argument(
817
+ "--legal-format",
818
+ dest="legal_format",
819
+ choices=["socket", "fossa"],
820
+ default="socket",
821
+ help="Select the legal artifact format. 'socket' keeps Socket-native outputs; 'fossa' emits compatibility-shaped JSON artifacts."
822
+ )
753
823
  config_group.add_argument(
754
824
  "--include-module-folders",
755
825
  dest="include_module_folders",