socketsecurity 2.2.9__tar.gz → 2.2.15__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 (86) hide show
  1. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/.github/workflows/pr-preview.yml +8 -8
  2. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/.github/workflows/release.yml +7 -7
  3. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/.github/workflows/version-check.yml +2 -2
  4. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/PKG-INFO +65 -17
  5. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/README.md +63 -15
  6. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/pyproject.toml +2 -2
  7. socketsecurity-2.2.15/socketsecurity/__init__.py +3 -0
  8. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/config.py +8 -7
  9. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/core/__init__.py +40 -29
  10. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/core/cli_client.py +2 -1
  11. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/core/resource_utils.py +21 -8
  12. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/core/scm/client.py +3 -2
  13. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/core/scm/github.py +2 -1
  14. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/core/scm/gitlab.py +8 -7
  15. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/socketcli.py +39 -26
  16. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/unit/test_gitlab_auth.py +2 -1
  17. socketsecurity-2.2.9/Pipfile.lock +0 -20
  18. socketsecurity-2.2.9/socketsecurity/__init__.py +0 -2
  19. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/.github/CODEOWNERS +0 -0
  20. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/.github/PULL_REQUEST_TEMPLATE/bug-fix.md +0 -0
  21. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/.github/PULL_REQUEST_TEMPLATE/feature.md +0 -0
  22. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/.github/PULL_REQUEST_TEMPLATE/improvement.md +0 -0
  23. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  24. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/.github/workflows/docker-stable.yml +0 -0
  25. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/.gitignore +0 -0
  26. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/.hooks/sync_version.py +0 -0
  27. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/.pre-commit-config.yaml +0 -0
  28. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/.python-version +0 -0
  29. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/Dockerfile +0 -0
  30. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/LICENSE +0 -0
  31. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/Makefile +0 -0
  32. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/docs/README.md +0 -0
  33. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/pytest.ini +0 -0
  34. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/scripts/build_container.sh +0 -0
  35. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/scripts/deploy-test-docker.sh +0 -0
  36. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/scripts/deploy-test-pypi.sh +0 -0
  37. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/scripts/run.sh +0 -0
  38. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/core/classes.py +0 -0
  39. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/core/exceptions.py +0 -0
  40. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/core/git_interface.py +0 -0
  41. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/core/helper/__init__.py +0 -0
  42. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/core/lazy_file_loader.py +0 -0
  43. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/core/logging.py +0 -0
  44. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/core/messages.py +0 -0
  45. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/core/scm/__init__.py +0 -0
  46. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/core/scm/base.py +0 -0
  47. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/core/scm_comments.py +0 -0
  48. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/core/socket_config.py +0 -0
  49. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/core/utils.py +0 -0
  50. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/output.py +0 -0
  51. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/plugins/__init__.py +0 -0
  52. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/plugins/base.py +0 -0
  53. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/plugins/jira.py +0 -0
  54. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/plugins/manager.py +0 -0
  55. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/plugins/slack.py +0 -0
  56. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/plugins/teams.py +0 -0
  57. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/socketsecurity/plugins/webhook.py +0 -0
  58. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/__init__.py +0 -0
  59. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/core/conftest.py +0 -0
  60. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/core/create_diff_input.json +0 -0
  61. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/core/test_diff_generation.py +0 -0
  62. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/core/test_package_and_alerts.py +0 -0
  63. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/core/test_sdk_methods.py +0 -0
  64. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/core/test_supporting_methods.py +0 -0
  65. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/data/fullscans/create_response.json +0 -0
  66. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/data/fullscans/diff/stream_diff.json +0 -0
  67. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/data/fullscans/diff/stream_diff_full.json +0 -0
  68. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/data/fullscans/head_scan/metadata.json +0 -0
  69. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/data/fullscans/head_scan/stream_scan.json +0 -0
  70. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/data/fullscans/head_scan/stream_scan_full.json +0 -0
  71. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/data/fullscans/new_scan/metadata.json +0 -0
  72. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/data/fullscans/new_scan/stream_scan.json +0 -0
  73. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/data/repos/repo_info_error.json +0 -0
  74. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/data/repos/repo_info_no_head.json +0 -0
  75. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/data/repos/repo_info_success.json +0 -0
  76. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/data/settings/security-policy.json +0 -0
  77. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/unit/__init__.py +0 -0
  78. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/unit/test_cli_config.py +0 -0
  79. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/unit/test_client.py +0 -0
  80. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/unit/test_config.py +0 -0
  81. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/unit/test_gitlab_auth_fallback.py +0 -0
  82. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/tests/unit/test_output.py +0 -0
  83. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/uv.lock +0 -0
  84. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/workflows/bitbucket-pipelines.yml +0 -0
  85. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/workflows/github-actions.yml +0 -0
  86. {socketsecurity-2.2.9 → socketsecurity-2.2.15}/workflows/gitlab-ci.yml +0 -0
@@ -11,10 +11,10 @@ jobs:
11
11
  contents: read
12
12
  pull-requests: write
13
13
  steps:
14
- - uses: actions/checkout@v4
14
+ - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871
15
15
  with:
16
16
  fetch-depth: 0
17
- - uses: actions/setup-python@v5
17
+ - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3
18
18
  with:
19
19
  python-version: '3.x'
20
20
 
@@ -43,14 +43,14 @@ jobs:
43
43
 
44
44
  - name: Publish to Test PyPI
45
45
  if: steps.version_check.outputs.exists != 'true'
46
- uses: pypa/gh-action-pypi-publish@v1.12.4
46
+ uses: pypa/gh-action-pypi-publish@ab69e431e9c9f48a3310be0a56527c679f56e04d
47
47
  with:
48
48
  repository-url: https://test.pypi.org/legacy/
49
49
  verbose: true
50
50
 
51
51
  - name: Comment on PR
52
52
  if: steps.version_check.outputs.exists != 'true'
53
- uses: actions/github-script@v7
53
+ uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea
54
54
  env:
55
55
  VERSION: ${{ env.VERSION }}
56
56
  with:
@@ -120,21 +120,21 @@ jobs:
120
120
  exit 1
121
121
 
122
122
  - name: Set up QEMU
123
- uses: docker/setup-qemu-action@v3
123
+ uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf
124
124
 
125
125
  - name: Set up Docker Buildx
126
- uses: docker/setup-buildx-action@v3
126
+ uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349
127
127
 
128
128
  - name: Login to Docker Hub with Organization Token
129
129
  if: steps.verify_package.outputs.success == 'true'
130
- uses: docker/login-action@v3
130
+ uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567
131
131
  with:
132
132
  username: ${{ secrets.DOCKERHUB_USERNAME }}
133
133
  password: ${{ secrets.DOCKERHUB_TOKEN }}
134
134
 
135
135
  - name: Build & Push Docker Preview
136
136
  if: steps.verify_package.outputs.success == 'true'
137
- uses: docker/build-push-action@v5
137
+ uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75
138
138
  env:
139
139
  VERSION: ${{ env.VERSION }}
140
140
  with:
@@ -10,10 +10,10 @@ jobs:
10
10
  id-token: write
11
11
  contents: read
12
12
  steps:
13
- - uses: actions/checkout@v4
13
+ - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871
14
14
  with:
15
15
  fetch-depth: 0
16
- - uses: actions/setup-python@v5
16
+ - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3
17
17
  with:
18
18
  python-version: '3.x'
19
19
 
@@ -66,16 +66,16 @@ jobs:
66
66
 
67
67
  - name: Publish to PyPI
68
68
  if: steps.version_check.outputs.pypi_exists != 'true'
69
- uses: pypa/gh-action-pypi-publish@v1.12.4
69
+ uses: pypa/gh-action-pypi-publish@ab69e431e9c9f48a3310be0a56527c679f56e04d
70
70
 
71
71
  - name: Set up QEMU
72
- uses: docker/setup-qemu-action@v3
72
+ uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf
73
73
 
74
74
  - name: Set up Docker Buildx
75
- uses: docker/setup-buildx-action@v3
75
+ uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349
76
76
 
77
77
  - name: Login to Docker Hub with Organization Token
78
- uses: docker/login-action@v3
78
+ uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567
79
79
  with:
80
80
  username: ${{ secrets.DOCKERHUB_USERNAME }}
81
81
  password: ${{ secrets.DOCKERHUB_TOKEN }}
@@ -102,7 +102,7 @@ jobs:
102
102
  if: |
103
103
  steps.verify_package.outputs.success == 'true' &&
104
104
  steps.docker_check.outputs.docker_exists != 'true'
105
- uses: docker/build-push-action@v5
105
+ uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75
106
106
  env:
107
107
  VERSION: ${{ env.VERSION }}
108
108
  with:
@@ -11,7 +11,7 @@ jobs:
11
11
  check_version:
12
12
  runs-on: ubuntu-latest
13
13
  steps:
14
- - uses: actions/checkout@v4
14
+ - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871
15
15
  with:
16
16
  fetch-depth: 0 # Fetch all history for all branches
17
17
 
@@ -39,7 +39,7 @@ jobs:
39
39
  "
40
40
 
41
41
  - name: Manage PR Comment
42
- uses: actions/github-script@v7
42
+ uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea
43
43
  if: always()
44
44
  env:
45
45
  MAIN_VERSION: ${{ env.MAIN_VERSION }}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: socketsecurity
3
- Version: 2.2.9
3
+ Version: 2.2.15
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>
@@ -39,7 +39,7 @@ Requires-Dist: packaging
39
39
  Requires-Dist: prettytable
40
40
  Requires-Dist: python-dotenv
41
41
  Requires-Dist: requests
42
- Requires-Dist: socketdev<4.0.0,>=3.0.5
42
+ Requires-Dist: socketdev<4.0.0,>=3.0.6
43
43
  Provides-Extra: dev
44
44
  Requires-Dist: hatch; extra == 'dev'
45
45
  Requires-Dist: pre-commit; extra == 'dev'
@@ -97,15 +97,60 @@ Pre-configured workflow examples are available in the [`workflows/`](workflows/)
97
97
 
98
98
  These examples are production-ready and include best practices for each platform.
99
99
 
100
+ ## Monorepo Workspace Support
101
+
102
+ The Socket CLI supports scanning specific workspaces within monorepo structures while preserving git context from the repository root. This is useful for organizations that maintain multiple applications or services in a single repository.
103
+
104
+ ### Key Features
105
+
106
+ - **Multiple Sub-paths**: Specify multiple `--sub-path` options to scan different directories within your monorepo
107
+ - **Combined Workspace**: All sub-paths are scanned together as a single workspace in Socket
108
+ - **Git Context Preserved**: Repository metadata (commits, branches, etc.) comes from the main target-path
109
+ - **Workspace Naming**: Use `--workspace-name` to differentiate scans from different parts of your monorepo
110
+
111
+ ### Usage Examples
112
+
113
+ **Scan multiple frontend and backend workspaces:**
114
+ ```bash
115
+ socketcli --target-path /path/to/monorepo \
116
+ --sub-path frontend \
117
+ --sub-path backend \
118
+ --sub-path services/api \
119
+ --workspace-name main-app
120
+ ```
121
+
122
+ **GitHub Actions for monorepo workspace:**
123
+ ```bash
124
+ socketcli --target-path $GITHUB_WORKSPACE \
125
+ --sub-path packages/web \
126
+ --sub-path packages/mobile \
127
+ --workspace-name mobile-web \
128
+ --scm github \
129
+ --pr-number $PR_NUMBER
130
+ ```
131
+
132
+ This will:
133
+ - Scan manifest files in `./packages/web/` and `./packages/mobile/`
134
+ - Combine them into a single workspace scan
135
+ - Create a repository in Socket named like `my-repo-mobile-web`
136
+ - Preserve git context (commits, branch info) from the repository root
137
+
138
+ ### Requirements
139
+
140
+ - Both `--sub-path` and `--workspace-name` must be specified together
141
+ - `--sub-path` can be used multiple times to include multiple directories
142
+ - All specified sub-paths must exist within the target-path
143
+
100
144
  ## Usage
101
145
 
102
146
  ```` shell
103
- socketcli [-h] [--api-token API_TOKEN] [--repo REPO] [--integration {api,github,gitlab}] [--owner OWNER] [--branch BRANCH]
104
- [--committers [COMMITTERS ...]] [--pr-number PR_NUMBER] [--commit-message COMMIT_MESSAGE] [--commit-sha COMMIT_SHA]
105
- [--target-path TARGET_PATH] [--sbom-file SBOM_FILE] [--files FILES] [--save-submitted-files-list SAVE_SUBMITTED_FILES_LIST]
106
- [--default-branch] [--pending-head] [--generate-license] [--enable-debug] [--enable-json] [--enable-sarif]
107
- [--disable-overview] [--disable-security-issue] [--allow-unverified] [--ignore-commit-files] [--disable-blocking]
108
- [--scm SCM] [--timeout TIMEOUT] [--exclude-license-details]
147
+ socketcli [-h] [--api-token API_TOKEN] [--repo REPO] [--repo-is-public] [--branch BRANCH] [--integration {api,github,gitlab,azure,bitbucket}]
148
+ [--owner OWNER] [--pr-number PR_NUMBER] [--commit-message COMMIT_MESSAGE] [--commit-sha COMMIT_SHA] [--committers [COMMITTERS ...]]
149
+ [--target-path TARGET_PATH] [--sbom-file SBOM_FILE] [--license-file-name LICENSE_FILE_NAME] [--save-submitted-files-list SAVE_SUBMITTED_FILES_LIST]
150
+ [--save-manifest-tar SAVE_MANIFEST_TAR] [--files FILES] [--sub-path SUB_PATH] [--workspace-name WORKSPACE_NAME]
151
+ [--excluded-ecosystems EXCLUDED_ECOSYSTEMS] [--default-branch] [--pending-head] [--generate-license] [--enable-debug]
152
+ [--enable-json] [--enable-sarif] [--disable-overview] [--exclude-license-details] [--allow-unverified] [--disable-security-issue]
153
+ [--ignore-commit-files] [--disable-blocking] [--enable-diff] [--scm SCM] [--timeout TIMEOUT] [--include-module-folders] [--version]
109
154
  ````
110
155
 
111
156
  If you don't want to provide the Socket API Token every time then you can use the environment variable `SOCKET_SECURITY_API_KEY`
@@ -121,11 +166,11 @@ If you don't want to provide the Socket API Token every time then you can use th
121
166
  | Parameter | Required | Default | Description |
122
167
  |:-----------------|:---------|:--------|:------------------------------------------------------------------------|
123
168
  | --repo | False | *auto* | Repository name in owner/repo format (auto-detected from git remote) |
124
- | --integration | False | api | Integration type (api, github, gitlab) |
169
+ | --repo-is-public | False | False | If set, flags a new repository creation as public. Defaults to false. |
170
+ | --integration | False | api | Integration type (api, github, gitlab, azure, bitbucket) |
125
171
  | --owner | False | | Name of the integration owner, defaults to the socket organization slug |
126
172
  | --branch | False | *auto* | Branch name (auto-detected from git) |
127
173
  | --committers | False | *auto* | Committer(s) to filter by (auto-detected from git commit) |
128
- | --repo-is-public | False | False | If set, flags a new repository creation as public. Defaults to false. |
129
174
 
130
175
  #### Pull Request and Commit
131
176
  | Parameter | Required | Default | Description |
@@ -139,17 +184,20 @@ If you don't want to provide the Socket API Token every time then you can use th
139
184
  |:----------------------------|:---------|:----------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
140
185
  | --target-path | False | ./ | Target path for analysis |
141
186
  | --sbom-file | False | | SBOM file path |
142
- | --files | False | *auto* | Files to analyze (JSON array string). Auto-detected from git commit changes when not specified |
143
- | --excluded-ecosystems | False | [] | List of ecosystems to exclude from analysis (JSON array string). You can get supported files from the [Supported Files API](https://docs.socket.dev/reference/getsupportedfiles) |
144
187
  | --license-file-name | False | `license_output.json` | Name of the file to save the license details to if enabled |
145
188
  | --save-submitted-files-list | False | | Save list of submitted file names to JSON file for debugging purposes |
146
189
  | --save-manifest-tar | False | | Save all manifest files to a compressed tar.gz archive with original directory structure |
190
+ | --files | False | *auto* | Files to analyze (JSON array string). Auto-detected from git commit changes when not specified |
191
+ | --sub-path | False | | Sub-path within target-path for manifest file scanning (can be specified multiple times). All sub-paths are combined into a single workspace scan while preserving git context from target-path. Must be used with --workspace-name |
192
+ | --workspace-name | False | | Workspace name suffix to append to repository name (repo-name-workspace_name). Must be used with --sub-path |
193
+ | --excluded-ecosystems | False | [] | List of ecosystems to exclude from analysis (JSON array string). You can get supported files from the [Supported Files API](https://docs.socket.dev/reference/getsupportedfiles) |
147
194
 
148
195
  #### Branch and Scan Configuration
149
- | Parameter | Required | Default | Description |
150
- |:-----------------|:---------|:--------|:------------------------------------------------------------------------------------------------------|
151
- | --default-branch | False | *auto* | Make this branch the default branch (auto-detected from git and CI environment when not specified) |
152
- | --pending-head | False | *auto* | If true, the new scan will be set as the branch's head scan (automatically synced with default-branch) |
196
+ | Parameter | Required | Default | Description |
197
+ |:-------------------------|:---------|:--------|:------------------------------------------------------------------------------------------------------|
198
+ | --default-branch | False | *auto* | Make this branch the default branch (auto-detected from git and CI environment when not specified) |
199
+ | --pending-head | False | *auto* | If true, the new scan will be set as the branch's head scan (automatically synced with default-branch) |
200
+ | --include-module-folders | False | False | If enabled will include manifest files from folders like node_modules |
153
201
 
154
202
  #### Output Configuration
155
203
  | Parameter | Required | Default | Description |
@@ -160,6 +208,7 @@ If you don't want to provide the Socket API Token every time then you can use th
160
208
  | --enable-sarif | False | False | Enable SARIF output of results instead of table or JSON format |
161
209
  | --disable-overview | False | False | Disable overview output |
162
210
  | --exclude-license-details | False | False | Exclude license details from the diff report (boosts performance for large repos) |
211
+ | --version | False | False | Show program's version number and exit |
163
212
 
164
213
  #### Security Configuration
165
214
  | Parameter | Required | Default | Description |
@@ -175,7 +224,6 @@ If you don't want to provide the Socket API Token every time then you can use th
175
224
  | --enable-diff | False | False | Enable diff mode even when using --integration api (forces diff mode without SCM integration) |
176
225
  | --scm | False | api | Source control management type |
177
226
  | --timeout | False | | Timeout in seconds for API requests |
178
- | --include-module-folders | False | False | If enabled will include manifest files from folders like node_modules |
179
227
 
180
228
  #### Plugins
181
229
 
@@ -41,15 +41,60 @@ Pre-configured workflow examples are available in the [`workflows/`](workflows/)
41
41
 
42
42
  These examples are production-ready and include best practices for each platform.
43
43
 
44
+ ## Monorepo Workspace Support
45
+
46
+ The Socket CLI supports scanning specific workspaces within monorepo structures while preserving git context from the repository root. This is useful for organizations that maintain multiple applications or services in a single repository.
47
+
48
+ ### Key Features
49
+
50
+ - **Multiple Sub-paths**: Specify multiple `--sub-path` options to scan different directories within your monorepo
51
+ - **Combined Workspace**: All sub-paths are scanned together as a single workspace in Socket
52
+ - **Git Context Preserved**: Repository metadata (commits, branches, etc.) comes from the main target-path
53
+ - **Workspace Naming**: Use `--workspace-name` to differentiate scans from different parts of your monorepo
54
+
55
+ ### Usage Examples
56
+
57
+ **Scan multiple frontend and backend workspaces:**
58
+ ```bash
59
+ socketcli --target-path /path/to/monorepo \
60
+ --sub-path frontend \
61
+ --sub-path backend \
62
+ --sub-path services/api \
63
+ --workspace-name main-app
64
+ ```
65
+
66
+ **GitHub Actions for monorepo workspace:**
67
+ ```bash
68
+ socketcli --target-path $GITHUB_WORKSPACE \
69
+ --sub-path packages/web \
70
+ --sub-path packages/mobile \
71
+ --workspace-name mobile-web \
72
+ --scm github \
73
+ --pr-number $PR_NUMBER
74
+ ```
75
+
76
+ This will:
77
+ - Scan manifest files in `./packages/web/` and `./packages/mobile/`
78
+ - Combine them into a single workspace scan
79
+ - Create a repository in Socket named like `my-repo-mobile-web`
80
+ - Preserve git context (commits, branch info) from the repository root
81
+
82
+ ### Requirements
83
+
84
+ - Both `--sub-path` and `--workspace-name` must be specified together
85
+ - `--sub-path` can be used multiple times to include multiple directories
86
+ - All specified sub-paths must exist within the target-path
87
+
44
88
  ## Usage
45
89
 
46
90
  ```` shell
47
- socketcli [-h] [--api-token API_TOKEN] [--repo REPO] [--integration {api,github,gitlab}] [--owner OWNER] [--branch BRANCH]
48
- [--committers [COMMITTERS ...]] [--pr-number PR_NUMBER] [--commit-message COMMIT_MESSAGE] [--commit-sha COMMIT_SHA]
49
- [--target-path TARGET_PATH] [--sbom-file SBOM_FILE] [--files FILES] [--save-submitted-files-list SAVE_SUBMITTED_FILES_LIST]
50
- [--default-branch] [--pending-head] [--generate-license] [--enable-debug] [--enable-json] [--enable-sarif]
51
- [--disable-overview] [--disable-security-issue] [--allow-unverified] [--ignore-commit-files] [--disable-blocking]
52
- [--scm SCM] [--timeout TIMEOUT] [--exclude-license-details]
91
+ socketcli [-h] [--api-token API_TOKEN] [--repo REPO] [--repo-is-public] [--branch BRANCH] [--integration {api,github,gitlab,azure,bitbucket}]
92
+ [--owner OWNER] [--pr-number PR_NUMBER] [--commit-message COMMIT_MESSAGE] [--commit-sha COMMIT_SHA] [--committers [COMMITTERS ...]]
93
+ [--target-path TARGET_PATH] [--sbom-file SBOM_FILE] [--license-file-name LICENSE_FILE_NAME] [--save-submitted-files-list SAVE_SUBMITTED_FILES_LIST]
94
+ [--save-manifest-tar SAVE_MANIFEST_TAR] [--files FILES] [--sub-path SUB_PATH] [--workspace-name WORKSPACE_NAME]
95
+ [--excluded-ecosystems EXCLUDED_ECOSYSTEMS] [--default-branch] [--pending-head] [--generate-license] [--enable-debug]
96
+ [--enable-json] [--enable-sarif] [--disable-overview] [--exclude-license-details] [--allow-unverified] [--disable-security-issue]
97
+ [--ignore-commit-files] [--disable-blocking] [--enable-diff] [--scm SCM] [--timeout TIMEOUT] [--include-module-folders] [--version]
53
98
  ````
54
99
 
55
100
  If you don't want to provide the Socket API Token every time then you can use the environment variable `SOCKET_SECURITY_API_KEY`
@@ -65,11 +110,11 @@ If you don't want to provide the Socket API Token every time then you can use th
65
110
  | Parameter | Required | Default | Description |
66
111
  |:-----------------|:---------|:--------|:------------------------------------------------------------------------|
67
112
  | --repo | False | *auto* | Repository name in owner/repo format (auto-detected from git remote) |
68
- | --integration | False | api | Integration type (api, github, gitlab) |
113
+ | --repo-is-public | False | False | If set, flags a new repository creation as public. Defaults to false. |
114
+ | --integration | False | api | Integration type (api, github, gitlab, azure, bitbucket) |
69
115
  | --owner | False | | Name of the integration owner, defaults to the socket organization slug |
70
116
  | --branch | False | *auto* | Branch name (auto-detected from git) |
71
117
  | --committers | False | *auto* | Committer(s) to filter by (auto-detected from git commit) |
72
- | --repo-is-public | False | False | If set, flags a new repository creation as public. Defaults to false. |
73
118
 
74
119
  #### Pull Request and Commit
75
120
  | Parameter | Required | Default | Description |
@@ -83,17 +128,20 @@ If you don't want to provide the Socket API Token every time then you can use th
83
128
  |:----------------------------|:---------|:----------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
84
129
  | --target-path | False | ./ | Target path for analysis |
85
130
  | --sbom-file | False | | SBOM file path |
86
- | --files | False | *auto* | Files to analyze (JSON array string). Auto-detected from git commit changes when not specified |
87
- | --excluded-ecosystems | False | [] | List of ecosystems to exclude from analysis (JSON array string). You can get supported files from the [Supported Files API](https://docs.socket.dev/reference/getsupportedfiles) |
88
131
  | --license-file-name | False | `license_output.json` | Name of the file to save the license details to if enabled |
89
132
  | --save-submitted-files-list | False | | Save list of submitted file names to JSON file for debugging purposes |
90
133
  | --save-manifest-tar | False | | Save all manifest files to a compressed tar.gz archive with original directory structure |
134
+ | --files | False | *auto* | Files to analyze (JSON array string). Auto-detected from git commit changes when not specified |
135
+ | --sub-path | False | | Sub-path within target-path for manifest file scanning (can be specified multiple times). All sub-paths are combined into a single workspace scan while preserving git context from target-path. Must be used with --workspace-name |
136
+ | --workspace-name | False | | Workspace name suffix to append to repository name (repo-name-workspace_name). Must be used with --sub-path |
137
+ | --excluded-ecosystems | False | [] | List of ecosystems to exclude from analysis (JSON array string). You can get supported files from the [Supported Files API](https://docs.socket.dev/reference/getsupportedfiles) |
91
138
 
92
139
  #### Branch and Scan Configuration
93
- | Parameter | Required | Default | Description |
94
- |:-----------------|:---------|:--------|:------------------------------------------------------------------------------------------------------|
95
- | --default-branch | False | *auto* | Make this branch the default branch (auto-detected from git and CI environment when not specified) |
96
- | --pending-head | False | *auto* | If true, the new scan will be set as the branch's head scan (automatically synced with default-branch) |
140
+ | Parameter | Required | Default | Description |
141
+ |:-------------------------|:---------|:--------|:------------------------------------------------------------------------------------------------------|
142
+ | --default-branch | False | *auto* | Make this branch the default branch (auto-detected from git and CI environment when not specified) |
143
+ | --pending-head | False | *auto* | If true, the new scan will be set as the branch's head scan (automatically synced with default-branch) |
144
+ | --include-module-folders | False | False | If enabled will include manifest files from folders like node_modules |
97
145
 
98
146
  #### Output Configuration
99
147
  | Parameter | Required | Default | Description |
@@ -104,6 +152,7 @@ If you don't want to provide the Socket API Token every time then you can use th
104
152
  | --enable-sarif | False | False | Enable SARIF output of results instead of table or JSON format |
105
153
  | --disable-overview | False | False | Disable overview output |
106
154
  | --exclude-license-details | False | False | Exclude license details from the diff report (boosts performance for large repos) |
155
+ | --version | False | False | Show program's version number and exit |
107
156
 
108
157
  #### Security Configuration
109
158
  | Parameter | Required | Default | Description |
@@ -119,7 +168,6 @@ If you don't want to provide the Socket API Token every time then you can use th
119
168
  | --enable-diff | False | False | Enable diff mode even when using --integration api (forces diff mode without SCM integration) |
120
169
  | --scm | False | api | Source control management type |
121
170
  | --timeout | False | | Timeout in seconds for API requests |
122
- | --include-module-folders | False | False | If enabled will include manifest files from folders like node_modules |
123
171
 
124
172
  #### Plugins
125
173
 
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
 
7
7
  [project]
8
8
  name = "socketsecurity"
9
- version = "2.2.9"
9
+ version = "2.2.15"
10
10
  requires-python = ">= 3.10"
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.0.5,<4.0.0'
19
+ 'socketdev>=3.0.6,<4.0.0'
20
20
  ]
21
21
  readme = "README.md"
22
22
  description = "Socket Security CLI for CI/CD"
@@ -0,0 +1,3 @@
1
+ __author__ = 'socket.dev'
2
+ __version__ = '2.2.15'
3
+ USER_AGENT = f'SocketPythonCLI/{__version__}'
@@ -60,7 +60,7 @@ class CliConfig:
60
60
  license_file_name: str = "license_output.json"
61
61
  save_submitted_files_list: Optional[str] = None
62
62
  save_manifest_tar: Optional[str] = None
63
- sub_path: Optional[str] = None
63
+ sub_paths: List[str] = field(default_factory=list)
64
64
  workspace_name: Optional[str] = None
65
65
 
66
66
  @classmethod
@@ -108,7 +108,7 @@ class CliConfig:
108
108
  'license_file_name': args.license_file_name,
109
109
  'save_submitted_files_list': args.save_submitted_files_list,
110
110
  'save_manifest_tar': args.save_manifest_tar,
111
- 'sub_path': args.sub_path,
111
+ 'sub_paths': args.sub_paths or [],
112
112
  'workspace_name': args.workspace_name,
113
113
  'version': __version__
114
114
  }
@@ -133,11 +133,11 @@ class CliConfig:
133
133
  if args.owner:
134
134
  config_args['integration_org_slug'] = args.owner
135
135
 
136
- # Validate that sub_path and workspace_name are used together
137
- if args.sub_path and not args.workspace_name:
136
+ # Validate that sub_paths and workspace_name are used together
137
+ if args.sub_paths and not args.workspace_name:
138
138
  logging.error("--sub-path requires --workspace-name to be specified")
139
139
  exit(1)
140
- if args.workspace_name and not args.sub_path:
140
+ if args.workspace_name and not args.sub_paths:
141
141
  logging.error("--workspace-name requires --sub-path to be specified")
142
142
  exit(1)
143
143
 
@@ -299,9 +299,10 @@ def create_argument_parser() -> argparse.ArgumentParser:
299
299
  )
300
300
  path_group.add_argument(
301
301
  "--sub-path",
302
- dest="sub_path",
302
+ dest="sub_paths",
303
303
  metavar="<path>",
304
- help="Sub-path within target-path for manifest file scanning (while preserving git context from target-path)"
304
+ action="append",
305
+ help="Sub-path within target-path for manifest file scanning (can be specified multiple times). All sub-paths will be combined into a single workspace scan while preserving git context from target-path"
305
306
  )
306
307
  path_group.add_argument(
307
308
  "--workspace-name",
@@ -18,7 +18,7 @@ from socketdev.org import Organization
18
18
  from socketdev.repos import RepositoryInfo
19
19
  from socketdev.settings import SecurityPolicyRule
20
20
  import copy
21
- from socketsecurity import __version__
21
+ from socketsecurity import __version__, USER_AGENT
22
22
  from socketsecurity.core.classes import (
23
23
  Alert,
24
24
  Diff,
@@ -39,6 +39,7 @@ __all__ = [
39
39
  "Core",
40
40
  "log",
41
41
  "__version__",
42
+ "USER_AGENT",
42
43
  ]
43
44
 
44
45
  version = __version__
@@ -451,14 +452,14 @@ class Core:
451
452
  log.debug(f"Created temporary empty file for baseline scan: {temp_path}")
452
453
  return [temp_path]
453
454
 
454
- def create_full_scan(self, files: List[str], params: FullScanParams, base_path: str = None) -> FullScan:
455
+ def create_full_scan(self, files: List[str], params: FullScanParams, base_paths: List[str] = None) -> FullScan:
455
456
  """
456
457
  Creates a new full scan via the Socket API.
457
458
 
458
459
  Args:
459
460
  files: List of file paths to scan
460
461
  params: Parameters for the full scan
461
- base_path: Base path for the scan (optional)
462
+ base_paths: List of base paths for the scan (optional)
462
463
 
463
464
  Returns:
464
465
  FullScan object with scan results
@@ -466,7 +467,7 @@ class Core:
466
467
  log.info("Creating new full scan")
467
468
  create_full_start = time.time()
468
469
 
469
- res = self.sdk.fullscans.post(files, params, use_types=True, use_lazy_loading=True, max_open_files=50, base_path=base_path)
470
+ res = self.sdk.fullscans.post(files, params, use_types=True, use_lazy_loading=True, max_open_files=50, base_paths=base_paths)
470
471
  if not res.success:
471
472
  log.error(f"Error creating full scan: {res.message}, status: {res.status}")
472
473
  raise Exception(f"Error creating full scan: {res.message}, status: {res.status}")
@@ -480,20 +481,22 @@ class Core:
480
481
 
481
482
  def create_full_scan_with_report_url(
482
483
  self,
483
- path: str,
484
+ paths: List[str],
484
485
  params: FullScanParams,
485
486
  no_change: bool = False,
486
487
  save_files_list_path: str = None,
487
- save_manifest_tar_path: str = None
488
+ save_manifest_tar_path: str = None,
489
+ base_paths: List[str] = None
488
490
  ) -> Diff:
489
491
  """Create a new full scan and return with html_report_url.
490
492
 
491
493
  Args:
492
- path: Path to look for manifest files
494
+ paths: List of paths to look for manifest files
493
495
  params: Query params for the Full Scan endpoint
494
496
  no_change: If True, return empty result
495
497
  save_files_list_path: Optional path to save submitted files list for debugging
496
498
  save_manifest_tar_path: Optional path to save manifest files tar.gz archive
499
+ base_paths: List of base paths for the scan (optional)
497
500
 
498
501
  Returns:
499
502
  Dict with full scan data including html_report_url
@@ -507,24 +510,27 @@ class Core:
507
510
  if no_change:
508
511
  return diff
509
512
 
510
- # Find manifest files
511
- files = self.find_files(path)
513
+ # Find manifest files from all paths
514
+ all_files = []
515
+ for path in paths:
516
+ files = self.find_files(path)
517
+ all_files.extend(files)
512
518
 
513
519
  # Save submitted files list if requested
514
- if save_files_list_path and files:
515
- self.save_submitted_files_list(files, save_files_list_path)
520
+ if save_files_list_path and all_files:
521
+ self.save_submitted_files_list(all_files, save_files_list_path)
516
522
 
517
- # Save manifest tar.gz if requested
518
- if save_manifest_tar_path and files:
519
- self.save_manifest_tar(files, save_manifest_tar_path, path)
523
+ # Save manifest tar.gz if requested (use first path as base)
524
+ if save_manifest_tar_path and all_files and paths:
525
+ self.save_manifest_tar(all_files, save_manifest_tar_path, paths[0])
520
526
 
521
- if not files:
527
+ if not all_files:
522
528
  return diff
523
529
 
524
530
  try:
525
531
  # Create new scan
526
532
  new_scan_start = time.time()
527
- new_full_scan = self.create_full_scan(files, params, base_path=path)
533
+ new_full_scan = self.create_full_scan(all_files, params, base_paths=base_paths)
528
534
  new_scan_end = time.time()
529
535
  log.info(f"Total time to create new full scan: {new_scan_end - new_scan_start:.2f}")
530
536
  except APIFailure as e:
@@ -847,37 +853,42 @@ class Core:
847
853
 
848
854
  def create_new_diff(
849
855
  self,
850
- path: str,
856
+ paths: List[str],
851
857
  params: FullScanParams,
852
858
  no_change: bool = False,
853
859
  save_files_list_path: str = None,
854
- save_manifest_tar_path: str = None
860
+ save_manifest_tar_path: str = None,
861
+ base_paths: List[str] = None
855
862
  ) -> Diff:
856
863
  """Create a new diff using the Socket SDK.
857
864
 
858
865
  Args:
859
- path: Path to look for manifest files
866
+ paths: List of paths to look for manifest files
860
867
  params: Query params for the Full Scan endpoint
861
868
  no_change: If True, return empty diff
862
869
  save_files_list_path: Optional path to save submitted files list for debugging
863
870
  save_manifest_tar_path: Optional path to save manifest files tar.gz archive
871
+ base_paths: List of base paths for the scan (optional)
864
872
  """
865
873
  log.debug(f"starting create_new_diff with no_change: {no_change}")
866
874
  if no_change:
867
875
  return Diff(id="NO_DIFF_RAN", diff_url="", report_url="")
868
876
 
869
- # Find manifest files
870
- files = self.find_files(path)
877
+ # Find manifest files from all paths
878
+ all_files = []
879
+ for path in paths:
880
+ files = self.find_files(path)
881
+ all_files.extend(files)
871
882
 
872
883
  # Save submitted files list if requested
873
- if save_files_list_path and files:
874
- self.save_submitted_files_list(files, save_files_list_path)
884
+ if save_files_list_path and all_files:
885
+ self.save_submitted_files_list(all_files, save_files_list_path)
875
886
 
876
- # Save manifest tar.gz if requested
877
- if save_manifest_tar_path and files:
878
- self.save_manifest_tar(files, save_manifest_tar_path, path)
887
+ # Save manifest tar.gz if requested (use first path as base)
888
+ if save_manifest_tar_path and all_files and paths:
889
+ self.save_manifest_tar(all_files, save_manifest_tar_path, paths[0])
879
890
 
880
- if not files:
891
+ if not all_files:
881
892
  return Diff(id="NO_DIFF_RAN", diff_url="", report_url="")
882
893
 
883
894
  try:
@@ -900,7 +911,7 @@ class Core:
900
911
  # Create baseline scan with empty file
901
912
  empty_files = Core.empty_head_scan_file()
902
913
  try:
903
- head_full_scan = self.create_full_scan(empty_files, tmp_params, base_path=path)
914
+ head_full_scan = self.create_full_scan(empty_files, tmp_params, base_paths=base_paths)
904
915
  head_full_scan_id = head_full_scan.id
905
916
  log.debug(f"Created empty baseline scan: {head_full_scan_id}")
906
917
 
@@ -923,7 +934,7 @@ class Core:
923
934
  # Create new scan
924
935
  try:
925
936
  new_scan_start = time.time()
926
- new_full_scan = self.create_full_scan(files, params, base_path=path)
937
+ new_full_scan = self.create_full_scan(all_files, params, base_paths=base_paths)
927
938
  new_scan_end = time.time()
928
939
  log.info(f"Total time to create new full scan: {new_scan_end - new_scan_start:.2f}")
929
940
  except APIFailure as e: