From c62c119b8d07783496b51568f32b550579784c74 Mon Sep 17 00:00:00 2001 From: Douglas Coburn Date: Tue, 21 Oct 2025 11:37:10 -0700 Subject: [PATCH 1/4] Added gates so that resources module doesn't break windows --- Pipfile.lock | 20 ------------------ pyproject.toml | 2 +- socketsecurity/__init__.py | 2 +- socketsecurity/core/resource_utils.py | 29 +++++++++++++++++++-------- 4 files changed, 23 insertions(+), 30 deletions(-) delete mode 100644 Pipfile.lock diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index 77f078c..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,20 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "7e8ad3d0508bf0c279a648ee7a1873fc16334cf0b711f30b2dc54a1da68fef6c" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.12" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/socketsecurity", - "verify_ssl": true - } - ] - }, - "default": {}, - "develop": {} -} diff --git a/pyproject.toml b/pyproject.toml index 22811e7..9ec3c0f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "hatchling.build" [project] name = "socketsecurity" -version = "2.2.11" +version = "2.2.12" requires-python = ">= 3.10" license = {"file" = "LICENSE"} dependencies = [ diff --git a/socketsecurity/__init__.py b/socketsecurity/__init__.py index 9ea1adb..aecfb7d 100644 --- a/socketsecurity/__init__.py +++ b/socketsecurity/__init__.py @@ -1,2 +1,2 @@ __author__ = 'socket.dev' -__version__ = '2.2.11' +__version__ = '2.2.12' diff --git a/socketsecurity/core/resource_utils.py b/socketsecurity/core/resource_utils.py index 2652bbf..b49cc2e 100644 --- a/socketsecurity/core/resource_utils.py +++ b/socketsecurity/core/resource_utils.py @@ -1,8 +1,17 @@ """ System resource utilities for the Socket Security CLI. """ -import resource import logging +import sys + +# The resource module is only available on Unix-like systems +resource_available = False +try: + import resource + resource_available = True +except ImportError: + # On Windows, the resource module is not available + pass log = logging.getLogger("socketdev") @@ -10,10 +19,14 @@ def get_file_descriptor_limit(): """ Get the current file descriptor limit (equivalent to ulimit -n) - + Returns: - tuple: (soft_limit, hard_limit) or (None, None) if error + tuple: (soft_limit, hard_limit) or (None, None) if error or on Windows """ + if not resource_available: + # On Windows, resource module is not available + return None, None + try: soft_limit, hard_limit = resource.getrlimit(resource.RLIMIT_NOFILE) return soft_limit, hard_limit @@ -25,26 +38,26 @@ def get_file_descriptor_limit(): def check_file_count_against_ulimit(file_count, buffer_size=100): """ Check if the number of files would exceed the file descriptor limit - + Args: file_count (int): Number of files to check buffer_size (int): Safety buffer to leave for other file operations - + Returns: dict: Information about the check """ soft_limit, hard_limit = get_file_descriptor_limit() - + if soft_limit is None: return { "can_check": False, "error": "Could not determine file descriptor limit", "safe_to_process": True # Assume safe if we can't check } - + available_fds = soft_limit - buffer_size would_exceed = file_count > available_fds - + return { "can_check": True, "file_count": file_count, From cda0316a7ea3a8bba7a97b82b2fe3eae7903d593 Mon Sep 17 00:00:00 2001 From: Douglas Coburn Date: Thu, 23 Oct 2025 18:18:49 -0700 Subject: [PATCH 2/4] feat: centralize User-Agent string across all API clients - Add USER_AGENT constant to socketsecurity/__init__.py - Replace hardcoded 'SocketPythonScript/0.0.1' and 'SocketPythonCLI/0.0.1' with centralized USER_AGENT - Update all SCM clients (GitHub, GitLab) and CLI client to use USER_AGENT - Update unit tests to reference centralized constant - Pin GitHub Actions to commit SHAs for improved security and reproducibility - Fix minor GitLab client bugs (return type, pipeline source support) --- .github/workflows/pr-preview.yml | 16 ++++++++-------- .github/workflows/release.yml | 14 +++++++------- pyproject.toml | 2 +- socketsecurity/__init__.py | 3 ++- socketsecurity/core/__init__.py | 3 ++- socketsecurity/core/cli_client.py | 3 ++- socketsecurity/core/scm/client.py | 5 +++-- socketsecurity/core/scm/github.py | 3 ++- socketsecurity/core/scm/gitlab.py | 15 ++++++++------- tests/unit/test_gitlab_auth.py | 3 ++- 10 files changed, 37 insertions(+), 30 deletions(-) diff --git a/.github/workflows/pr-preview.yml b/.github/workflows/pr-preview.yml index f3b142a..9386346 100644 --- a/.github/workflows/pr-preview.yml +++ b/.github/workflows/pr-preview.yml @@ -11,10 +11,10 @@ jobs: contents: read pull-requests: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 with: fetch-depth: 0 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 with: python-version: '3.x' @@ -43,14 +43,14 @@ jobs: - name: Publish to Test PyPI if: steps.version_check.outputs.exists != 'true' - uses: pypa/gh-action-pypi-publish@v1.12.4 + uses: pypa/gh-action-pypi-publish@ab69e431e9c9f48a3310be0a56527c679f56e04d with: repository-url: https://test.pypi.org/legacy/ verbose: true - name: Comment on PR if: steps.version_check.outputs.exists != 'true' - uses: actions/github-script@v7 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea env: VERSION: ${{ env.VERSION }} with: @@ -120,21 +120,21 @@ jobs: exit 1 - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 - name: Login to Docker Hub with Organization Token if: steps.verify_package.outputs.success == 'true' - uses: docker/login-action@v3 + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build & Push Docker Preview if: steps.verify_package.outputs.success == 'true' - uses: docker/build-push-action@v5 + uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 env: VERSION: ${{ env.VERSION }} with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b70d26e..20b4bd1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,10 +10,10 @@ jobs: id-token: write contents: read steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 with: fetch-depth: 0 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 with: python-version: '3.x' @@ -66,16 +66,16 @@ jobs: - name: Publish to PyPI if: steps.version_check.outputs.pypi_exists != 'true' - uses: pypa/gh-action-pypi-publish@v1.12.4 + uses: pypa/gh-action-pypi-publish@ab69e431e9c9f48a3310be0a56527c679f56e04d - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 - name: Login to Docker Hub with Organization Token - uses: docker/login-action@v3 + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} @@ -102,7 +102,7 @@ jobs: if: | steps.verify_package.outputs.success == 'true' && steps.docker_check.outputs.docker_exists != 'true' - uses: docker/build-push-action@v5 + uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 env: VERSION: ${{ env.VERSION }} with: diff --git a/pyproject.toml b/pyproject.toml index 9ec3c0f..b24b423 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "hatchling.build" [project] name = "socketsecurity" -version = "2.2.12" +version = "2.2.13" requires-python = ">= 3.10" license = {"file" = "LICENSE"} dependencies = [ diff --git a/socketsecurity/__init__.py b/socketsecurity/__init__.py index aecfb7d..fbe240d 100644 --- a/socketsecurity/__init__.py +++ b/socketsecurity/__init__.py @@ -1,2 +1,3 @@ __author__ = 'socket.dev' -__version__ = '2.2.12' +__version__ = '2.2.13' +USER_AGENT = f'SocketPythonCLI/{__version__}' diff --git a/socketsecurity/core/__init__.py b/socketsecurity/core/__init__.py index 6dd6ecb..1261c43 100644 --- a/socketsecurity/core/__init__.py +++ b/socketsecurity/core/__init__.py @@ -18,7 +18,7 @@ from socketdev.repos import RepositoryInfo from socketdev.settings import SecurityPolicyRule import copy -from socketsecurity import __version__ +from socketsecurity import __version__, USER_AGENT from socketsecurity.core.classes import ( Alert, Diff, @@ -39,6 +39,7 @@ "Core", "log", "__version__", + "USER_AGENT", ] version = __version__ diff --git a/socketsecurity/core/cli_client.py b/socketsecurity/core/cli_client.py index bf8db38..8bb2ed6 100644 --- a/socketsecurity/core/cli_client.py +++ b/socketsecurity/core/cli_client.py @@ -4,6 +4,7 @@ import requests +from socketsecurity import USER_AGENT from .exceptions import APIFailure from .socket_config import SocketConfig @@ -31,7 +32,7 @@ def request( default_headers = { 'Authorization': f"Basic {self._encoded_key}", - 'User-Agent': 'SocketPythonCLI/0.0.1', + 'User-Agent': USER_AGENT, "accept": "application/json" } diff --git a/socketsecurity/core/scm/client.py b/socketsecurity/core/scm/client.py index 1033613..0575711 100644 --- a/socketsecurity/core/scm/client.py +++ b/socketsecurity/core/scm/client.py @@ -1,6 +1,7 @@ from abc import abstractmethod from typing import Dict +from socketsecurity import USER_AGENT from ..cli_client import CliClient @@ -28,7 +29,7 @@ class GithubClient(ScmClient): def get_headers(self) -> Dict: return { 'Authorization': f"Bearer {self.token}", - 'User-Agent': 'SocketPythonScript/0.0.1', + 'User-Agent': USER_AGENT, "accept": "application/json" } @@ -52,7 +53,7 @@ def _get_gitlab_auth_headers(token: str) -> dict: import os base_headers = { - 'User-Agent': 'SocketPythonScript/0.0.1', + 'User-Agent': USER_AGENT, "accept": "application/json" } diff --git a/socketsecurity/core/scm/github.py b/socketsecurity/core/scm/github.py index 1b4fa0e..0870f5c 100644 --- a/socketsecurity/core/scm/github.py +++ b/socketsecurity/core/scm/github.py @@ -5,6 +5,7 @@ from git import Optional +from socketsecurity import USER_AGENT from socketsecurity.core import log from socketsecurity.core.classes import Comment from socketsecurity.core.scm_comments import Comments @@ -83,7 +84,7 @@ def from_env(cls, pr_number: Optional[str] = None) -> 'GithubConfig': event_action=event_action, headers={ 'Authorization': f"Bearer {token}", - 'User-Agent': 'SocketPythonScript/0.0.1', + 'User-Agent': USER_AGENT, "accept": "application/json" } ) diff --git a/socketsecurity/core/scm/gitlab.py b/socketsecurity/core/scm/gitlab.py index b5f46b7..c8aba49 100644 --- a/socketsecurity/core/scm/gitlab.py +++ b/socketsecurity/core/scm/gitlab.py @@ -3,6 +3,7 @@ from dataclasses import dataclass from typing import Optional +from socketsecurity import USER_AGENT from socketsecurity.core import log from socketsecurity.core.classes import Comment from socketsecurity.core.scm_comments import Comments @@ -79,7 +80,7 @@ def _get_auth_headers(token: str) -> dict: - Other tokens: Use PRIVATE-TOKEN as fallback """ base_headers = { - 'User-Agent': 'SocketPythonScript/0.0.1', + 'User-Agent': USER_AGENT, "accept": "application/json" } @@ -150,7 +151,7 @@ def _get_fallback_headers(self, original_headers: dict) -> dict: If using Bearer, fallback to PRIVATE-TOKEN and vice versa. """ base_headers = { - 'User-Agent': 'SocketPythonScript/0.0.1', + 'User-Agent': USER_AGENT, "accept": "application/json" } @@ -171,11 +172,11 @@ def _get_fallback_headers(self, original_headers: dict) -> dict: } # No fallback available - return None + return {} def check_event_type(self) -> str: pipeline_source = self.config.pipeline_source.lower() - if pipeline_source in ["web", 'merge_request_event', "push", "api"]: + if pipeline_source in ["web", 'merge_request_event', "push", "api", 'pipeline']: if not self.config.mr_iid: return "main" return "diff" @@ -234,8 +235,8 @@ def add_socket_comments( new_security_comment: bool = True, new_overview_comment: bool = True ) -> None: - existing_overview_comment = comments.get("overview") - existing_security_comment = comments.get("security") + existing_overview_comment = comments.get("overview", "") + existing_security_comment = comments.get("security", "") if new_overview_comment: log.debug("New Dependency Overview comment") if existing_overview_comment is not None: @@ -256,7 +257,7 @@ def add_socket_comments( self.post_comment(security_comment) def remove_comment_alerts(self, comments: dict): - security_alert = comments.get("security") + security_alert = comments.get("security", "") if security_alert is not None: security_alert: Comment new_body = Comments.process_security_comment(security_alert, comments) diff --git a/tests/unit/test_gitlab_auth.py b/tests/unit/test_gitlab_auth.py index be34224..3c6d6dd 100644 --- a/tests/unit/test_gitlab_auth.py +++ b/tests/unit/test_gitlab_auth.py @@ -3,6 +3,7 @@ import pytest from unittest.mock import patch, MagicMock +from socketsecurity import USER_AGENT from socketsecurity.core.scm.gitlab import GitlabConfig @@ -58,7 +59,7 @@ def test_all_headers_include_base_headers(self): for token in test_tokens: headers = GitlabConfig._get_auth_headers(token) - assert headers['User-Agent'] == 'SocketPythonScript/0.0.1' + assert headers['User-Agent'] == USER_AGENT assert headers['accept'] == 'application/json' @patch.dict(os.environ, {'CI_JOB_TOKEN': 'ci-token-123'}) From 8e1f4f1f21e3e30595ee1323f57964297996aa17 Mon Sep 17 00:00:00 2001 From: Douglas Coburn Date: Thu, 23 Oct 2025 18:25:48 -0700 Subject: [PATCH 3/4] Updated version-check.yml to used commit hashes --- .github/workflows/version-check.yml | 4 ++-- pyproject.toml | 2 +- socketsecurity/__init__.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/version-check.yml b/.github/workflows/version-check.yml index fa20938..5e4335c 100644 --- a/.github/workflows/version-check.yml +++ b/.github/workflows/version-check.yml @@ -11,7 +11,7 @@ jobs: check_version: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 with: fetch-depth: 0 # Fetch all history for all branches @@ -39,7 +39,7 @@ jobs: " - name: Manage PR Comment - uses: actions/github-script@v7 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea if: always() env: MAIN_VERSION: ${{ env.MAIN_VERSION }} diff --git a/pyproject.toml b/pyproject.toml index b24b423..13d87a9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "hatchling.build" [project] name = "socketsecurity" -version = "2.2.13" +version = "2.2.14" requires-python = ">= 3.10" license = {"file" = "LICENSE"} dependencies = [ diff --git a/socketsecurity/__init__.py b/socketsecurity/__init__.py index fbe240d..ecf0913 100644 --- a/socketsecurity/__init__.py +++ b/socketsecurity/__init__.py @@ -1,3 +1,3 @@ __author__ = 'socket.dev' -__version__ = '2.2.13' +__version__ = '2.2.14' USER_AGENT = f'SocketPythonCLI/{__version__}' From 5583085b24bed3ae695e42bcdfe44f834f1ffbbb Mon Sep 17 00:00:00 2001 From: Douglas Coburn Date: Thu, 23 Oct 2025 18:40:17 -0700 Subject: [PATCH 4/4] Minor type fixes --- pyproject.toml | 2 +- socketsecurity/__init__.py | 2 +- socketsecurity/socketcli.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 13d87a9..6b2ea18 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "hatchling.build" [project] name = "socketsecurity" -version = "2.2.14" +version = "2.2.15" requires-python = ">= 3.10" license = {"file" = "LICENSE"} dependencies = [ diff --git a/socketsecurity/__init__.py b/socketsecurity/__init__.py index ecf0913..c4b1ae5 100644 --- a/socketsecurity/__init__.py +++ b/socketsecurity/__init__.py @@ -1,3 +1,3 @@ __author__ = 'socket.dev' -__version__ = '2.2.14' +__version__ = '2.2.15' USER_AGENT = f'SocketPythonCLI/{__version__}' diff --git a/socketsecurity/socketcli.py b/socketsecurity/socketcli.py index 2813790..79b8374 100644 --- a/socketsecurity/socketcli.py +++ b/socketsecurity/socketcli.py @@ -114,7 +114,7 @@ def main_code(): # Git setup is_repo = False - git_repo = None + git_repo: Git try: git_repo = Git(config.target_path) is_repo = True