socketsecurity 2.2.0__tar.gz → 2.2.4__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 (91) hide show
  1. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/Dockerfile +1 -1
  2. socketsecurity-2.2.4/Makefile +62 -0
  3. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/PKG-INFO +85 -13
  4. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/README.md +82 -10
  5. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/pyproject.toml +3 -3
  6. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/scripts/deploy-test-docker.sh +1 -1
  7. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/__init__.py +1 -1
  8. socketsecurity-2.2.4/socketsecurity/core/scm/client.py +84 -0
  9. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/core/scm/gitlab.py +112 -8
  10. socketsecurity-2.2.4/tests/unit/test_gitlab_auth.py +116 -0
  11. socketsecurity-2.2.4/tests/unit/test_gitlab_auth_fallback.py +148 -0
  12. socketsecurity-2.2.4/uv.lock +1388 -0
  13. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/workflows/gitlab-ci.yml +3 -0
  14. socketsecurity-2.2.0/Makefile +0 -69
  15. socketsecurity-2.2.0/requirements-dev.lock +0 -73
  16. socketsecurity-2.2.0/requirements-dev.txt +0 -73
  17. socketsecurity-2.2.0/requirements.lock +0 -71
  18. socketsecurity-2.2.0/requirements.txt +0 -71
  19. socketsecurity-2.2.0/socketsecurity/core/scm/client.py +0 -41
  20. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/.github/CODEOWNERS +0 -0
  21. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/.github/PULL_REQUEST_TEMPLATE/bug-fix.md +0 -0
  22. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/.github/PULL_REQUEST_TEMPLATE/feature.md +0 -0
  23. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/.github/PULL_REQUEST_TEMPLATE/improvement.md +0 -0
  24. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  25. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/.github/workflows/docker-stable.yml +0 -0
  26. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/.github/workflows/pr-preview.yml +0 -0
  27. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/.github/workflows/release.yml +0 -0
  28. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/.github/workflows/version-check.yml +0 -0
  29. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/.gitignore +0 -0
  30. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/.hooks/sync_version.py +0 -0
  31. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/.pre-commit-config.yaml +0 -0
  32. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/.python-version +0 -0
  33. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/LICENSE +0 -0
  34. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/Pipfile.lock +0 -0
  35. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/docs/README.md +0 -0
  36. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/pytest.ini +0 -0
  37. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/scripts/build_container.sh +0 -0
  38. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/scripts/deploy-test-pypi.sh +0 -0
  39. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/scripts/run.sh +0 -0
  40. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/config.py +0 -0
  41. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/core/__init__.py +0 -0
  42. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/core/classes.py +0 -0
  43. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/core/cli_client.py +0 -0
  44. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/core/exceptions.py +0 -0
  45. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/core/git_interface.py +0 -0
  46. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/core/helper/__init__.py +0 -0
  47. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/core/lazy_file_loader.py +0 -0
  48. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/core/logging.py +0 -0
  49. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/core/messages.py +0 -0
  50. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/core/resource_utils.py +0 -0
  51. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/core/scm/__init__.py +0 -0
  52. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/core/scm/base.py +0 -0
  53. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/core/scm/github.py +0 -0
  54. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/core/scm_comments.py +0 -0
  55. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/core/socket_config.py +0 -0
  56. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/core/utils.py +0 -0
  57. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/output.py +0 -0
  58. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/plugins/__init__.py +0 -0
  59. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/plugins/base.py +0 -0
  60. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/plugins/jira.py +0 -0
  61. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/plugins/manager.py +0 -0
  62. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/plugins/slack.py +0 -0
  63. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/plugins/teams.py +0 -0
  64. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/plugins/webhook.py +0 -0
  65. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/socketsecurity/socketcli.py +0 -0
  66. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/tests/__init__.py +0 -0
  67. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/tests/core/conftest.py +0 -0
  68. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/tests/core/create_diff_input.json +0 -0
  69. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/tests/core/test_diff_generation.py +0 -0
  70. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/tests/core/test_package_and_alerts.py +0 -0
  71. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/tests/core/test_sdk_methods.py +0 -0
  72. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/tests/core/test_supporting_methods.py +0 -0
  73. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/tests/data/fullscans/create_response.json +0 -0
  74. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/tests/data/fullscans/diff/stream_diff.json +0 -0
  75. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/tests/data/fullscans/diff/stream_diff_full.json +0 -0
  76. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/tests/data/fullscans/head_scan/metadata.json +0 -0
  77. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/tests/data/fullscans/head_scan/stream_scan.json +0 -0
  78. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/tests/data/fullscans/head_scan/stream_scan_full.json +0 -0
  79. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/tests/data/fullscans/new_scan/metadata.json +0 -0
  80. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/tests/data/fullscans/new_scan/stream_scan.json +0 -0
  81. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/tests/data/repos/repo_info_error.json +0 -0
  82. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/tests/data/repos/repo_info_no_head.json +0 -0
  83. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/tests/data/repos/repo_info_success.json +0 -0
  84. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/tests/data/settings/security-policy.json +0 -0
  85. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/tests/unit/__init__.py +0 -0
  86. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/tests/unit/test_cli_config.py +0 -0
  87. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/tests/unit/test_client.py +0 -0
  88. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/tests/unit/test_config.py +0 -0
  89. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/tests/unit/test_output.py +0 -0
  90. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/workflows/bitbucket-pipelines.yml +0 -0
  91. {socketsecurity-2.2.0 → socketsecurity-2.2.4}/workflows/github-actions.yml +0 -0
@@ -18,5 +18,5 @@ RUN for i in $(seq 1 10); do \
18
18
  sleep 30; \
19
19
  done && \
20
20
  if [ ! -z "$SDK_VERSION" ]; then \
21
- pip install --index-url ${PIP_INDEX_URL} --extra-index-url ${PIP_EXTRA_INDEX_URL} socket-sdk-python==${SDK_VERSION}; \
21
+ pip install --index-url ${PIP_INDEX_URL} --extra-index-url ${PIP_EXTRA_INDEX_URL} socketdev==${SDK_VERSION}; \
22
22
  fi
@@ -0,0 +1,62 @@
1
+ .PHONY: setup sync clean test lint update-lock local-dev first-time-setup dev-setup sync-all first-time-local-setup
2
+
3
+ # Environment variable for local SDK path (optional)
4
+ SOCKET_SDK_PATH ?= ../socketdev
5
+
6
+ # Environment variable to control local development mode
7
+ USE_LOCAL_SDK ?= false
8
+
9
+ # === High-level workflow targets ===
10
+
11
+ # First-time repo setup after cloning (using PyPI packages)
12
+ first-time-setup: clean setup
13
+
14
+ # First-time setup for local development (using local SDK)
15
+ first-time-local-setup:
16
+ $(MAKE) clean
17
+ $(MAKE) USE_LOCAL_SDK=true dev-setup
18
+
19
+ # Update lock file after changing pyproject.toml
20
+ update-lock:
21
+ uv lock
22
+
23
+ # Setup for local development
24
+ dev-setup: clean local-dev setup
25
+
26
+ # Sync all dependencies after pulling changes
27
+ sync-all: sync
28
+
29
+ # === Implementation targets ===
30
+
31
+ # Installs dependencies needed for local development
32
+ # Currently: socketdev from test PyPI or local path
33
+ local-dev:
34
+ ifeq ($(USE_LOCAL_SDK),true)
35
+ uv add --editable $(SOCKET_SDK_PATH)
36
+ endif
37
+
38
+ # Creates virtual environment and installs dependencies from uv.lock
39
+ setup: update-lock
40
+ uv sync --all-extras
41
+ ifeq ($(USE_LOCAL_SDK),true)
42
+ uv add --editable $(SOCKET_SDK_PATH)
43
+ endif
44
+
45
+ # Installs exact versions from uv.lock into your virtual environment
46
+ sync:
47
+ uv sync --all-extras
48
+ ifeq ($(USE_LOCAL_SDK),true)
49
+ uv add --editable $(SOCKET_SDK_PATH)
50
+ endif
51
+
52
+ # Removes virtual environment and cache files
53
+ clean:
54
+ rm -rf .venv
55
+ find . -type d -name "__pycache__" -exec rm -rf {} +
56
+
57
+ test:
58
+ uv run pytest
59
+
60
+ lint:
61
+ uv run ruff check .
62
+ uv run ruff format --check .
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: socketsecurity
3
- Version: 2.2.0
3
+ Version: 2.2.4
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,13 +39,13 @@ Requires-Dist: packaging
39
39
  Requires-Dist: prettytable
40
40
  Requires-Dist: python-dotenv
41
41
  Requires-Dist: requests
42
- Requires-Dist: socket-sdk-python<3,>=2.1.8
42
+ Requires-Dist: socketdev<4.0.0,>=3.0.0
43
43
  Provides-Extra: dev
44
44
  Requires-Dist: hatch; extra == 'dev'
45
- Requires-Dist: pip-tools>=7.4.0; extra == 'dev'
46
45
  Requires-Dist: pre-commit; extra == 'dev'
47
46
  Requires-Dist: ruff>=0.3.0; extra == 'dev'
48
47
  Requires-Dist: twine; extra == 'dev'
48
+ Requires-Dist: uv>=0.1.0; extra == 'dev'
49
49
  Provides-Extra: test
50
50
  Requires-Dist: pytest-asyncio>=0.23.0; extra == 'test'
51
51
  Requires-Dist: pytest-cov>=4.1.0; extra == 'test'
@@ -235,6 +235,74 @@ The CLI uses intelligent default branch detection with the following priority:
235
235
 
236
236
  Both `--default-branch` and `--pending-head` parameters are automatically synchronized to ensure consistent behavior.
237
237
 
238
+ ## GitLab Token Configuration
239
+
240
+ The CLI supports GitLab integration with automatic authentication pattern detection for different token types.
241
+
242
+ ### Supported Token Types
243
+
244
+ GitLab API supports two authentication methods, and the CLI automatically detects which one to use:
245
+
246
+ 1. **Bearer Token Authentication** (`Authorization: Bearer <token>`)
247
+ - GitLab CI Job Tokens (`$CI_JOB_TOKEN`)
248
+ - Personal Access Tokens with `glpat-` prefix
249
+ - OAuth 2.0 tokens (long alphanumeric tokens)
250
+
251
+ 2. **Private Token Authentication** (`PRIVATE-TOKEN: <token>`)
252
+ - Legacy personal access tokens
253
+ - Custom tokens that don't match Bearer patterns
254
+
255
+ ### Token Detection Logic
256
+
257
+ The CLI automatically determines the authentication method using this logic:
258
+
259
+ ```
260
+ if token == $CI_JOB_TOKEN:
261
+ use Bearer authentication
262
+ elif token starts with "glpat-":
263
+ use Bearer authentication
264
+ elif token is long (>40 chars) and alphanumeric:
265
+ use Bearer authentication
266
+ else:
267
+ use PRIVATE-TOKEN authentication
268
+ ```
269
+
270
+ ### Automatic Fallback
271
+
272
+ If the initial authentication method fails with a 401 error, the CLI automatically retries with the alternative method:
273
+
274
+ - **Bearer → PRIVATE-TOKEN**: If Bearer authentication fails, retry with PRIVATE-TOKEN
275
+ - **PRIVATE-TOKEN → Bearer**: If PRIVATE-TOKEN fails, retry with Bearer authentication
276
+
277
+ This ensures maximum compatibility across different GitLab configurations and token types.
278
+
279
+ ### Environment Variables
280
+
281
+ | Variable | Description | Example |
282
+ |:---------|:------------|:--------|
283
+ | `GITLAB_TOKEN` | GitLab API token (required for GitLab integration) | `glpat-xxxxxxxxxxxxxxxxxxxx` |
284
+ | `CI_JOB_TOKEN` | GitLab CI job token (automatically used in GitLab CI) | Automatically provided by GitLab CI |
285
+
286
+ ### Usage Examples
287
+
288
+ **GitLab CI with job token (recommended):**
289
+ ```yaml
290
+ variables:
291
+ GITLAB_TOKEN: $CI_JOB_TOKEN
292
+ ```
293
+
294
+ **GitLab CI with personal access token:**
295
+ ```yaml
296
+ variables:
297
+ GITLAB_TOKEN: $GITLAB_PERSONAL_ACCESS_TOKEN # Set in GitLab project/group variables
298
+ ```
299
+
300
+ **Local development:**
301
+ ```bash
302
+ export GITLAB_TOKEN="glpat-your-personal-access-token"
303
+ socketcli --integration gitlab --repo owner/repo --pr-number 123
304
+ ```
305
+
238
306
  ### Scan Behavior
239
307
 
240
308
  The CLI determines scanning behavior intelligently:
@@ -359,9 +427,9 @@ make first-time-setup
359
427
  2. Local Development Setup (for SDK development):
360
428
  ```bash
361
429
  pyenv local 3.11 # Ensure correct Python version
362
- SOCKET_SDK_PATH=~/path/to/socket-sdk-python make first-time-local-setup
430
+ SOCKET_SDK_PATH=~/path/to/socketdev make first-time-local-setup
363
431
  ```
364
- The default SDK path is `../socket-sdk-python` if not specified.
432
+ The default SDK path is `../socketdev` if not specified.
365
433
 
366
434
  #### Ongoing Development Tasks
367
435
 
@@ -380,20 +448,24 @@ make sync-all
380
448
  High-level workflows:
381
449
  - `make first-time-setup`: Complete setup using PyPI packages
382
450
  - `make first-time-local-setup`: Complete setup for local SDK development
383
- - `make update-deps`: Update requirements.txt files and sync dependencies
451
+ - `make update-lock`: Update uv.lock file after changing pyproject.toml
384
452
  - `make sync-all`: Sync dependencies after pulling changes
385
453
  - `make dev-setup`: Setup for local development (included in first-time-local-setup)
386
454
 
387
455
  Implementation targets:
388
- - `make init-tools`: Creates virtual environment and installs pip-tools
389
456
  - `make local-dev`: Installs dependencies needed for local development
390
- - `make compile-deps`: Generates requirements.txt files with locked versions
391
- - `make setup`: Creates virtual environment and installs dependencies
392
- - `make sync-deps`: Installs exact versions from requirements.txt
457
+ - `make setup`: Creates virtual environment and installs dependencies from uv.lock
458
+ - `make sync`: Installs exact versions from uv.lock
393
459
  - `make clean`: Removes virtual environment and cache files
394
- - `make test`: Runs pytest suite
395
- - `make lint`: Runs ruff for code formatting and linting
460
+ - `make test`: Runs pytest suite using uv run
461
+ - `make lint`: Runs ruff for code formatting and linting using uv run
396
462
 
397
463
  ### Environment Variables
398
464
 
399
- - `SOCKET_SDK_PATH`: Path to local socket-sdk-python repository (default: ../socket-sdk-python)
465
+ #### Core Configuration
466
+ - `SOCKET_SECURITY_API_KEY`: Socket Security API token (alternative to --api-token parameter)
467
+ - `SOCKET_SDK_PATH`: Path to local socketdev repository (default: ../socketdev)
468
+
469
+ #### GitLab Integration
470
+ - `GITLAB_TOKEN`: GitLab API token for GitLab integration (supports both Bearer and PRIVATE-TOKEN authentication)
471
+ - `CI_JOB_TOKEN`: GitLab CI job token (automatically provided in GitLab CI environments)
@@ -179,6 +179,74 @@ The CLI uses intelligent default branch detection with the following priority:
179
179
 
180
180
  Both `--default-branch` and `--pending-head` parameters are automatically synchronized to ensure consistent behavior.
181
181
 
182
+ ## GitLab Token Configuration
183
+
184
+ The CLI supports GitLab integration with automatic authentication pattern detection for different token types.
185
+
186
+ ### Supported Token Types
187
+
188
+ GitLab API supports two authentication methods, and the CLI automatically detects which one to use:
189
+
190
+ 1. **Bearer Token Authentication** (`Authorization: Bearer <token>`)
191
+ - GitLab CI Job Tokens (`$CI_JOB_TOKEN`)
192
+ - Personal Access Tokens with `glpat-` prefix
193
+ - OAuth 2.0 tokens (long alphanumeric tokens)
194
+
195
+ 2. **Private Token Authentication** (`PRIVATE-TOKEN: <token>`)
196
+ - Legacy personal access tokens
197
+ - Custom tokens that don't match Bearer patterns
198
+
199
+ ### Token Detection Logic
200
+
201
+ The CLI automatically determines the authentication method using this logic:
202
+
203
+ ```
204
+ if token == $CI_JOB_TOKEN:
205
+ use Bearer authentication
206
+ elif token starts with "glpat-":
207
+ use Bearer authentication
208
+ elif token is long (>40 chars) and alphanumeric:
209
+ use Bearer authentication
210
+ else:
211
+ use PRIVATE-TOKEN authentication
212
+ ```
213
+
214
+ ### Automatic Fallback
215
+
216
+ If the initial authentication method fails with a 401 error, the CLI automatically retries with the alternative method:
217
+
218
+ - **Bearer → PRIVATE-TOKEN**: If Bearer authentication fails, retry with PRIVATE-TOKEN
219
+ - **PRIVATE-TOKEN → Bearer**: If PRIVATE-TOKEN fails, retry with Bearer authentication
220
+
221
+ This ensures maximum compatibility across different GitLab configurations and token types.
222
+
223
+ ### Environment Variables
224
+
225
+ | Variable | Description | Example |
226
+ |:---------|:------------|:--------|
227
+ | `GITLAB_TOKEN` | GitLab API token (required for GitLab integration) | `glpat-xxxxxxxxxxxxxxxxxxxx` |
228
+ | `CI_JOB_TOKEN` | GitLab CI job token (automatically used in GitLab CI) | Automatically provided by GitLab CI |
229
+
230
+ ### Usage Examples
231
+
232
+ **GitLab CI with job token (recommended):**
233
+ ```yaml
234
+ variables:
235
+ GITLAB_TOKEN: $CI_JOB_TOKEN
236
+ ```
237
+
238
+ **GitLab CI with personal access token:**
239
+ ```yaml
240
+ variables:
241
+ GITLAB_TOKEN: $GITLAB_PERSONAL_ACCESS_TOKEN # Set in GitLab project/group variables
242
+ ```
243
+
244
+ **Local development:**
245
+ ```bash
246
+ export GITLAB_TOKEN="glpat-your-personal-access-token"
247
+ socketcli --integration gitlab --repo owner/repo --pr-number 123
248
+ ```
249
+
182
250
  ### Scan Behavior
183
251
 
184
252
  The CLI determines scanning behavior intelligently:
@@ -303,9 +371,9 @@ make first-time-setup
303
371
  2. Local Development Setup (for SDK development):
304
372
  ```bash
305
373
  pyenv local 3.11 # Ensure correct Python version
306
- SOCKET_SDK_PATH=~/path/to/socket-sdk-python make first-time-local-setup
374
+ SOCKET_SDK_PATH=~/path/to/socketdev make first-time-local-setup
307
375
  ```
308
- The default SDK path is `../socket-sdk-python` if not specified.
376
+ The default SDK path is `../socketdev` if not specified.
309
377
 
310
378
  #### Ongoing Development Tasks
311
379
 
@@ -324,20 +392,24 @@ make sync-all
324
392
  High-level workflows:
325
393
  - `make first-time-setup`: Complete setup using PyPI packages
326
394
  - `make first-time-local-setup`: Complete setup for local SDK development
327
- - `make update-deps`: Update requirements.txt files and sync dependencies
395
+ - `make update-lock`: Update uv.lock file after changing pyproject.toml
328
396
  - `make sync-all`: Sync dependencies after pulling changes
329
397
  - `make dev-setup`: Setup for local development (included in first-time-local-setup)
330
398
 
331
399
  Implementation targets:
332
- - `make init-tools`: Creates virtual environment and installs pip-tools
333
400
  - `make local-dev`: Installs dependencies needed for local development
334
- - `make compile-deps`: Generates requirements.txt files with locked versions
335
- - `make setup`: Creates virtual environment and installs dependencies
336
- - `make sync-deps`: Installs exact versions from requirements.txt
401
+ - `make setup`: Creates virtual environment and installs dependencies from uv.lock
402
+ - `make sync`: Installs exact versions from uv.lock
337
403
  - `make clean`: Removes virtual environment and cache files
338
- - `make test`: Runs pytest suite
339
- - `make lint`: Runs ruff for code formatting and linting
404
+ - `make test`: Runs pytest suite using uv run
405
+ - `make lint`: Runs ruff for code formatting and linting using uv run
340
406
 
341
407
  ### Environment Variables
342
408
 
343
- - `SOCKET_SDK_PATH`: Path to local socket-sdk-python repository (default: ../socket-sdk-python)
409
+ #### Core Configuration
410
+ - `SOCKET_SECURITY_API_KEY`: Socket Security API token (alternative to --api-token parameter)
411
+ - `SOCKET_SDK_PATH`: Path to local socketdev repository (default: ../socketdev)
412
+
413
+ #### GitLab Integration
414
+ - `GITLAB_TOKEN`: GitLab API token for GitLab integration (supports both Bearer and PRIVATE-TOKEN authentication)
415
+ - `CI_JOB_TOKEN`: GitLab CI job token (automatically provided in GitLab CI environments)
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
 
7
7
  [project]
8
8
  name = "socketsecurity"
9
- version = "2.2.0"
9
+ version = "2.2.4"
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
- 'socket-sdk-python>=2.1.8,<3'
19
+ 'socketdev>=3.0.0,<4.0.0'
20
20
  ]
21
21
  readme = "README.md"
22
22
  description = "Socket Security CLI for CI/CD"
@@ -45,7 +45,7 @@ test = [
45
45
  dev = [
46
46
  "ruff>=0.3.0",
47
47
  "twine", # for building
48
- "pip-tools>=7.4.0", # for pip-compile
48
+ "uv>=0.1.0", # for dependency management
49
49
  "pre-commit",
50
50
  "hatch"
51
51
  ]
@@ -29,7 +29,7 @@ fi
29
29
 
30
30
  if [ -z "$SDK_VERSION" ]; then
31
31
  echo "No SDK version specified, checking TestPyPI for latest version..."
32
- SDK_VERSION=$(get_latest_version "socket-sdk-python")
32
+ SDK_VERSION=$(get_latest_version "socketdev")
33
33
  echo "Latest SDK version on TestPyPI is: $SDK_VERSION"
34
34
  fi
35
35
 
@@ -1,2 +1,2 @@
1
1
  __author__ = 'socket.dev'
2
- __version__ = '2.2.0'
2
+ __version__ = '2.2.4'
@@ -0,0 +1,84 @@
1
+ from abc import abstractmethod
2
+ from typing import Dict
3
+
4
+ from ..cli_client import CliClient
5
+
6
+
7
+ class ScmClient(CliClient):
8
+ def __init__(self, token: str, api_url: str):
9
+ self.token = token
10
+ self.api_url = api_url
11
+
12
+ @abstractmethod
13
+ def get_headers(self) -> Dict:
14
+ """Each SCM implements its own auth headers"""
15
+ pass
16
+
17
+ def request(self, path: str, **kwargs):
18
+ """Override base request to use SCM-specific headers and base_url"""
19
+ headers = kwargs.pop('headers', None) or self.get_headers()
20
+ return super().request(
21
+ path=path,
22
+ headers=headers,
23
+ base_url=self.api_url,
24
+ **kwargs
25
+ )
26
+
27
+ class GithubClient(ScmClient):
28
+ def get_headers(self) -> Dict:
29
+ return {
30
+ 'Authorization': f"Bearer {self.token}",
31
+ 'User-Agent': 'SocketPythonScript/0.0.1',
32
+ "accept": "application/json"
33
+ }
34
+
35
+ class GitlabClient(ScmClient):
36
+ def get_headers(self) -> Dict:
37
+ """
38
+ Determine the appropriate authentication headers for GitLab API.
39
+ Uses the same logic as GitlabConfig._get_auth_headers()
40
+ """
41
+ return self._get_gitlab_auth_headers(self.token)
42
+
43
+ @staticmethod
44
+ def _get_gitlab_auth_headers(token: str) -> dict:
45
+ """
46
+ Determine the appropriate authentication headers for GitLab API.
47
+
48
+ GitLab supports two authentication patterns:
49
+ 1. Bearer token (OAuth 2.0 tokens, personal access tokens with api scope)
50
+ 2. Private token (personal access tokens)
51
+ """
52
+ import os
53
+
54
+ base_headers = {
55
+ 'User-Agent': 'SocketPythonScript/0.0.1',
56
+ "accept": "application/json"
57
+ }
58
+
59
+ # Check if this is a GitLab CI job token
60
+ if token == os.getenv('CI_JOB_TOKEN'):
61
+ return {
62
+ **base_headers,
63
+ 'Authorization': f"Bearer {token}"
64
+ }
65
+
66
+ # Check for personal access token pattern
67
+ if token.startswith('glpat-'):
68
+ return {
69
+ **base_headers,
70
+ 'Authorization': f"Bearer {token}"
71
+ }
72
+
73
+ # Check for OAuth token pattern (typically longer and alphanumeric)
74
+ if len(token) > 40 and token.isalnum():
75
+ return {
76
+ **base_headers,
77
+ 'Authorization': f"Bearer {token}"
78
+ }
79
+
80
+ # Default to PRIVATE-TOKEN for other token types
81
+ return {
82
+ **base_headers,
83
+ 'PRIVATE-TOKEN': f"{token}"
84
+ }
@@ -42,6 +42,9 @@ class GitlabConfig:
42
42
  mr_source_branch = os.getenv('CI_MERGE_REQUEST_SOURCE_BRANCH_NAME')
43
43
  default_branch = os.getenv('CI_DEFAULT_BRANCH', '')
44
44
 
45
+ # Determine which authentication pattern to use
46
+ headers = cls._get_auth_headers(token)
47
+
45
48
  return cls(
46
49
  commit_sha=os.getenv('CI_COMMIT_SHA', ''),
47
50
  api_url=os.getenv('CI_API_V4_URL', ''),
@@ -57,18 +60,119 @@ class GitlabConfig:
57
60
  token=token,
58
61
  repository=project_name,
59
62
  is_default_branch=(mr_source_branch == default_branch if mr_source_branch else False),
60
- headers={
61
- 'Authorization': f"Bearer {token}",
62
- 'User-Agent': 'SocketPythonScript/0.0.1',
63
- "accept": "application/json"
64
- }
63
+ headers=headers
65
64
  )
66
65
 
66
+ @staticmethod
67
+ def _get_auth_headers(token: str) -> dict:
68
+ """
69
+ Determine the appropriate authentication headers for GitLab API.
70
+
71
+ GitLab supports two authentication patterns:
72
+ 1. Bearer token (OAuth 2.0 tokens, personal access tokens with api scope)
73
+ 2. Private token (personal access tokens)
74
+
75
+ Logic for token type determination:
76
+ - CI_JOB_TOKEN: Always use Bearer (GitLab CI job token)
77
+ - Tokens starting with 'glpat-': Personal access tokens, try Bearer first
78
+ - OAuth tokens: Use Bearer
79
+ - Other tokens: Use PRIVATE-TOKEN as fallback
80
+ """
81
+ base_headers = {
82
+ 'User-Agent': 'SocketPythonScript/0.0.1',
83
+ "accept": "application/json"
84
+ }
85
+
86
+ # Check if this is a GitLab CI job token
87
+ if token == os.getenv('CI_JOB_TOKEN'):
88
+ log.debug("Using Bearer authentication for GitLab CI job token")
89
+ return {
90
+ **base_headers,
91
+ 'Authorization': f"Bearer {token}"
92
+ }
93
+
94
+ # Check for personal access token pattern
95
+ if token.startswith('glpat-'):
96
+ log.debug("Using Bearer authentication for GitLab personal access token")
97
+ return {
98
+ **base_headers,
99
+ 'Authorization': f"Bearer {token}"
100
+ }
101
+
102
+ # Check for OAuth token pattern (typically longer and alphanumeric)
103
+ if len(token) > 40 and token.isalnum():
104
+ log.debug("Using Bearer authentication for potential OAuth token")
105
+ return {
106
+ **base_headers,
107
+ 'Authorization': f"Bearer {token}"
108
+ }
109
+
110
+ # Default to PRIVATE-TOKEN for other token types
111
+ log.debug("Using PRIVATE-TOKEN authentication for GitLab token")
112
+ return {
113
+ **base_headers,
114
+ 'PRIVATE-TOKEN': f"{token}"
115
+ }
116
+
67
117
  class Gitlab:
68
118
  def __init__(self, client: CliClient, config: Optional[GitlabConfig] = None):
69
119
  self.config = config or GitlabConfig.from_env()
70
120
  self.client = client
71
121
 
122
+ def _request_with_fallback(self, **kwargs):
123
+ """
124
+ Make a request with automatic fallback between Bearer and PRIVATE-TOKEN authentication.
125
+ This provides robustness when the initial token type detection is incorrect.
126
+ """
127
+ try:
128
+ # Try the initial request with the configured headers
129
+ return self.client.request(**kwargs)
130
+ except Exception as e:
131
+ # Check if this is an authentication error (401)
132
+ if hasattr(e, 'response') and e.response and e.response.status_code == 401:
133
+ log.debug(f"Authentication failed with initial headers, trying fallback method")
134
+
135
+ # Determine the fallback headers
136
+ original_headers = kwargs.get('headers', self.config.headers)
137
+ fallback_headers = self._get_fallback_headers(original_headers)
138
+
139
+ if fallback_headers and fallback_headers != original_headers:
140
+ log.debug("Retrying request with fallback authentication method")
141
+ kwargs['headers'] = fallback_headers
142
+ return self.client.request(**kwargs)
143
+
144
+ # Re-raise the original exception if it's not an auth error or fallback failed
145
+ raise
146
+
147
+ def _get_fallback_headers(self, original_headers: dict) -> dict:
148
+ """
149
+ Generate fallback authentication headers.
150
+ If using Bearer, fallback to PRIVATE-TOKEN and vice versa.
151
+ """
152
+ base_headers = {
153
+ 'User-Agent': 'SocketPythonScript/0.0.1',
154
+ "accept": "application/json"
155
+ }
156
+
157
+ # If currently using Bearer, try PRIVATE-TOKEN
158
+ if 'Authorization' in original_headers and 'Bearer' in original_headers['Authorization']:
159
+ log.debug("Falling back from Bearer to PRIVATE-TOKEN authentication")
160
+ return {
161
+ **base_headers,
162
+ 'PRIVATE-TOKEN': f"{self.config.token}"
163
+ }
164
+
165
+ # If currently using PRIVATE-TOKEN, try Bearer
166
+ elif 'PRIVATE-TOKEN' in original_headers:
167
+ log.debug("Falling back from PRIVATE-TOKEN to Bearer authentication")
168
+ return {
169
+ **base_headers,
170
+ 'Authorization': f"Bearer {self.config.token}"
171
+ }
172
+
173
+ # No fallback available
174
+ return None
175
+
72
176
  def check_event_type(self) -> str:
73
177
  pipeline_source = self.config.pipeline_source.lower()
74
178
  if pipeline_source in ["web", 'merge_request_event', "push", "api"]:
@@ -84,7 +188,7 @@ class Gitlab:
84
188
  def post_comment(self, body: str) -> None:
85
189
  path = f"projects/{self.config.mr_project_id}/merge_requests/{self.config.mr_iid}/notes"
86
190
  payload = {"body": body}
87
- self.client.request(
191
+ self._request_with_fallback(
88
192
  path=path,
89
193
  payload=payload,
90
194
  method="POST",
@@ -95,7 +199,7 @@ class Gitlab:
95
199
  def update_comment(self, body: str, comment_id: str) -> None:
96
200
  path = f"projects/{self.config.mr_project_id}/merge_requests/{self.config.mr_iid}/notes/{comment_id}"
97
201
  payload = {"body": body}
98
- self.client.request(
202
+ self._request_with_fallback(
99
203
  path=path,
100
204
  payload=payload,
101
205
  method="PUT",
@@ -106,7 +210,7 @@ class Gitlab:
106
210
  def get_comments_for_pr(self) -> dict:
107
211
  log.debug(f"Getting Gitlab comments for Repo {self.config.repository} for PR {self.config.mr_iid}")
108
212
  path = f"projects/{self.config.mr_project_id}/merge_requests/{self.config.mr_iid}/notes"
109
- response = self.client.request(
213
+ response = self._request_with_fallback(
110
214
  path=path,
111
215
  headers=self.config.headers,
112
216
  base_url=self.config.api_url