From f5da0a9329996f27ef74fa4c00a57c4d544ab03f Mon Sep 17 00:00:00 2001 From: Douglas Coburn Date: Mon, 28 Jul 2025 19:24:47 -0700 Subject: [PATCH 1/5] fix: robust changed file detection for PRs/MRs in GitHub, GitLab, and Bitbucket - Use git diff with appropriate refs and environment variables to detect changed files in pull/merge requests across GitHub Actions, GitLab CI, and Bitbucket Pipelines. - Fallback to git show for single commit detection. - Ensures manifest and other file changes are correctly picked up in all major --- pyproject.toml | 2 +- socketsecurity/__init__.py | 2 +- socketsecurity/core/git_interface.py | 51 +++++++++++++++++++++++++++- 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 5734b33..72367f4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "hatchling.build" [project] name = "socketsecurity" -version = "2.1.28" +version = "2.1.29" requires-python = ">= 3.10" license = {"file" = "LICENSE"} dependencies = [ diff --git a/socketsecurity/__init__.py b/socketsecurity/__init__.py index fce5d74..c2aa6cf 100644 --- a/socketsecurity/__init__.py +++ b/socketsecurity/__init__.py @@ -1,2 +1,2 @@ __author__ = 'socket.dev' -__version__ = '2.1.28' +__version__ = '2.1.29' diff --git a/socketsecurity/core/git_interface.py b/socketsecurity/core/git_interface.py index 995634b..ceb806c 100644 --- a/socketsecurity/core/git_interface.py +++ b/socketsecurity/core/git_interface.py @@ -128,7 +128,56 @@ def __init__(self, path: str): self.commit_sha = self.commit.binsha self.commit_message = self.commit.message self.committer = self.commit.committer - self.show_files = self.repo.git.show(self.commit, name_only=True, format="%n").splitlines() + # Detect changed files in PR/MR context for GitHub, GitLab, Bitbucket; fallback to git show + self.show_files = [] + detected = False + # GitHub Actions PR context + github_base_ref = os.getenv('GITHUB_BASE_REF') + github_head_ref = os.getenv('GITHUB_HEAD_REF') + if github_base_ref and github_head_ref: + try: + self.repo.git.fetch('origin', github_base_ref, github_head_ref) + diff_range = f"origin/{github_base_ref}...{self.commit.hexsha}" + diff_files = self.repo.git.diff('--name-only', diff_range) + self.show_files = diff_files.splitlines() + log.debug(f"Changed files detected via git diff (GitHub): {self.show_files}") + detected = True + except Exception as error: + log.debug(f"Failed to get changed files via git diff (GitHub): {error}") + # GitLab CI Merge Request context + if not detected: + gitlab_target = os.getenv('CI_MERGE_REQUEST_TARGET_BRANCH_NAME') + gitlab_source = os.getenv('CI_MERGE_REQUEST_SOURCE_BRANCH_NAME') + if gitlab_target and gitlab_source: + try: + self.repo.git.fetch('origin', gitlab_target, gitlab_source) + diff_range = f"origin/{gitlab_target}...origin/{gitlab_source}" + diff_files = self.repo.git.diff('--name-only', diff_range) + self.show_files = diff_files.splitlines() + log.debug(f"Changed files detected via git diff (GitLab): {self.show_files}") + detected = True + except Exception as error: + log.debug(f"Failed to get changed files via git diff (GitLab): {error}") + # Bitbucket Pipelines PR context + if not detected: + bitbucket_pr_id = os.getenv('BITBUCKET_PR_ID') + bitbucket_source = os.getenv('BITBUCKET_BRANCH') + bitbucket_dest = os.getenv('BITBUCKET_PR_DESTINATION_BRANCH') + # BITBUCKET_BRANCH is the source branch in PR builds + if bitbucket_pr_id and bitbucket_source and bitbucket_dest: + try: + self.repo.git.fetch('origin', bitbucket_dest, bitbucket_source) + diff_range = f"origin/{bitbucket_dest}...origin/{bitbucket_source}" + diff_files = self.repo.git.diff('--name-only', diff_range) + self.show_files = diff_files.splitlines() + log.debug(f"Changed files detected via git diff (Bitbucket): {self.show_files}") + detected = True + except Exception as error: + log.debug(f"Failed to get changed files via git diff (Bitbucket): {error}") + # Fallback to git show for single commit + if not detected: + self.show_files = self.repo.git.show(self.commit, name_only=True, format="%n").splitlines() + log.debug(f"Changed files detected via git show: {self.show_files}") self.changed_files = [] for item in self.show_files: if item != "": From eca3b11d85fd3aff479e74239144bc81c62f9b6b Mon Sep 17 00:00:00 2001 From: Douglas Coburn Date: Mon, 28 Jul 2025 19:59:15 -0700 Subject: [PATCH 2/5] Fixing logic for Github changed files --- pyproject.toml | 2 +- socketsecurity/__init__.py | 2 +- socketsecurity/core/git_interface.py | 17 +++++++++++++---- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 72367f4..32c31f3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "hatchling.build" [project] name = "socketsecurity" -version = "2.1.29" +version = "2.1.30" requires-python = ">= 3.10" license = {"file" = "LICENSE"} dependencies = [ diff --git a/socketsecurity/__init__.py b/socketsecurity/__init__.py index c2aa6cf..f4461a1 100644 --- a/socketsecurity/__init__.py +++ b/socketsecurity/__init__.py @@ -1,2 +1,2 @@ __author__ = 'socket.dev' -__version__ = '2.1.29' +__version__ = '2.1.30' diff --git a/socketsecurity/core/git_interface.py b/socketsecurity/core/git_interface.py index ceb806c..317386e 100644 --- a/socketsecurity/core/git_interface.py +++ b/socketsecurity/core/git_interface.py @@ -134,16 +134,25 @@ def __init__(self, path: str): # GitHub Actions PR context github_base_ref = os.getenv('GITHUB_BASE_REF') github_head_ref = os.getenv('GITHUB_HEAD_REF') - if github_base_ref and github_head_ref: + github_event_name = os.getenv('GITHUB_EVENT_NAME') + if github_event_name == 'pull_request' and github_base_ref and github_head_ref: try: self.repo.git.fetch('origin', github_base_ref, github_head_ref) - diff_range = f"origin/{github_base_ref}...{self.commit.hexsha}" + diff_range = f"origin/{github_base_ref}...origin/{github_head_ref}" diff_files = self.repo.git.diff('--name-only', diff_range) self.show_files = diff_files.splitlines() - log.debug(f"Changed files detected via git diff (GitHub): {self.show_files}") + log.debug(f"Changed files detected via git diff (GitHub PR): {self.show_files}") detected = True except Exception as error: - log.debug(f"Failed to get changed files via git diff (GitHub): {error}") + log.debug(f"Failed to get changed files via git diff (GitHub PR): {error}") + # Commits to default branch (push events) + elif github_event_name == 'push': + try: + self.show_files = self.repo.git.show(self.commit, name_only=True, format="%n").splitlines() + log.debug(f"Changed files detected via git show (GitHub push): {self.show_files}") + detected = True + except Exception as error: + log.debug(f"Failed to get changed files via git show (GitHub push): {error}") # GitLab CI Merge Request context if not detected: gitlab_target = os.getenv('CI_MERGE_REQUEST_TARGET_BRANCH_NAME') From 54f9a8066e9069a81a4f77054b52d59e4913daa3 Mon Sep 17 00:00:00 2001 From: Douglas Coburn Date: Mon, 28 Jul 2025 20:45:07 -0700 Subject: [PATCH 3/5] Add fetch of previous commit --- pyproject.toml | 2 +- socketsecurity/__init__.py | 2 +- socketsecurity/core/git_interface.py | 39 +++++++++++++++++++++++----- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 32c31f3..d159096 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "hatchling.build" [project] name = "socketsecurity" -version = "2.1.30" +version = "2.1.31" requires-python = ">= 3.10" license = {"file" = "LICENSE"} dependencies = [ diff --git a/socketsecurity/__init__.py b/socketsecurity/__init__.py index f4461a1..38c366b 100644 --- a/socketsecurity/__init__.py +++ b/socketsecurity/__init__.py @@ -1,2 +1,2 @@ __author__ = 'socket.dev' -__version__ = '2.1.30' +__version__ = '2.1.31' diff --git a/socketsecurity/core/git_interface.py b/socketsecurity/core/git_interface.py index 317386e..691079a 100644 --- a/socketsecurity/core/git_interface.py +++ b/socketsecurity/core/git_interface.py @@ -135,24 +135,49 @@ def __init__(self, path: str): github_base_ref = os.getenv('GITHUB_BASE_REF') github_head_ref = os.getenv('GITHUB_HEAD_REF') github_event_name = os.getenv('GITHUB_EVENT_NAME') + github_before_sha = os.getenv('GITHUB_EVENT_BEFORE') # previous commit for push + github_sha = os.getenv('GITHUB_SHA') # current commit if github_event_name == 'pull_request' and github_base_ref and github_head_ref: try: - self.repo.git.fetch('origin', github_base_ref, github_head_ref) + # Fetch both branches individually + self.repo.git.fetch('origin', github_base_ref) + self.repo.git.fetch('origin', github_head_ref) + # Try remote diff first diff_range = f"origin/{github_base_ref}...origin/{github_head_ref}" - diff_files = self.repo.git.diff('--name-only', diff_range) + try: + diff_files = self.repo.git.diff('--name-only', diff_range) + self.show_files = diff_files.splitlines() + log.debug(f"Changed files detected via git diff (GitHub PR remote): {self.show_files}") + detected = True + except Exception as remote_error: + log.debug(f"Remote diff failed: {remote_error}") + # Try local branch diff + local_diff_range = f"{github_base_ref}...{github_head_ref}" + try: + diff_files = self.repo.git.diff('--name-only', local_diff_range) + self.show_files = diff_files.splitlines() + log.debug(f"Changed files detected via git diff (GitHub PR local): {self.show_files}") + detected = True + except Exception as local_error: + log.debug(f"Local diff failed: {local_error}") + except Exception as error: + log.debug(f"Failed to fetch branches or diff for GitHub PR: {error}") + # Commits to default branch (push events) + elif github_event_name == 'push' and github_before_sha and github_sha: + try: + diff_files = self.repo.git.diff('--name-only', f'{github_before_sha}..{github_sha}') self.show_files = diff_files.splitlines() - log.debug(f"Changed files detected via git diff (GitHub PR): {self.show_files}") + log.debug(f"Changed files detected via git diff (GitHub push): {self.show_files}") detected = True except Exception as error: - log.debug(f"Failed to get changed files via git diff (GitHub PR): {error}") - # Commits to default branch (push events) + log.debug(f"Failed to get changed files via git diff (GitHub push): {error}") elif github_event_name == 'push': try: self.show_files = self.repo.git.show(self.commit, name_only=True, format="%n").splitlines() - log.debug(f"Changed files detected via git show (GitHub push): {self.show_files}") + log.debug(f"Changed files detected via git show (GitHub push fallback): {self.show_files}") detected = True except Exception as error: - log.debug(f"Failed to get changed files via git show (GitHub push): {error}") + log.debug(f"Failed to get changed files via git show (GitHub push fallback): {error}") # GitLab CI Merge Request context if not detected: gitlab_target = os.getenv('CI_MERGE_REQUEST_TARGET_BRANCH_NAME') From 0db590481c7fdba3efeb59c33de60e90efd2ad17 Mon Sep 17 00:00:00 2001 From: Douglas Coburn Date: Mon, 28 Jul 2025 20:51:54 -0700 Subject: [PATCH 4/5] Fix file names for changed files to work with globbing --- pyproject.toml | 2 +- socketsecurity/__init__.py | 2 +- socketsecurity/core/git_interface.py | 11 +++++++++-- workflows/github-actions.yml | 2 +- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index d159096..827f66d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "hatchling.build" [project] name = "socketsecurity" -version = "2.1.31" +version = "2.1.32" requires-python = ">= 3.10" license = {"file" = "LICENSE"} dependencies = [ diff --git a/socketsecurity/__init__.py b/socketsecurity/__init__.py index 38c366b..5b35bb9 100644 --- a/socketsecurity/__init__.py +++ b/socketsecurity/__init__.py @@ -1,2 +1,2 @@ __author__ = 'socket.dev' -__version__ = '2.1.31' +__version__ = '2.1.32' diff --git a/socketsecurity/core/git_interface.py b/socketsecurity/core/git_interface.py index 691079a..93fefb5 100644 --- a/socketsecurity/core/git_interface.py +++ b/socketsecurity/core/git_interface.py @@ -15,6 +15,13 @@ def __init__(self, path: str): self.repo = Repo(path) assert self.repo self.head = self.repo.head + + # Always fetch all remote refs to ensure branches exist for diffing + try: + self.repo.git.fetch('--all') + log.debug("Fetched all remote refs for diffing.") + except Exception as fetch_error: + log.debug(f"Failed to fetch all remote refs: {fetch_error}") # Use CI environment SHA if available, otherwise fall back to current HEAD commit github_sha = os.getenv('GITHUB_SHA') @@ -215,8 +222,8 @@ def __init__(self, path: str): self.changed_files = [] for item in self.show_files: if item != "": - full_path = f"{self.path}/{item}" - self.changed_files.append(full_path) + # Use relative path for glob matching + self.changed_files.append(item) # Determine if this commit is on the default branch # This considers both GitHub Actions detached HEAD and regular branch situations diff --git a/workflows/github-actions.yml b/workflows/github-actions.yml index 8c3d49d..866f654 100644 --- a/workflows/github-actions.yml +++ b/workflows/github-actions.yml @@ -33,7 +33,7 @@ jobs: - uses: actions/checkout@v4 with: # For PRs, fetch one additional commit for proper diff analysis - fetch-depth: ${{ github.event_name == 'pull_request' && 2 || 0 }} + fetch-depth: 0 - name: Run Socket Security Scan env: From fa09bc5c438d28b3a0a605f84aead899da2aa461 Mon Sep 17 00:00:00 2001 From: Douglas Coburn Date: Mon, 28 Jul 2025 21:05:27 -0700 Subject: [PATCH 5/5] Fixed detection for files in the commit files change --- pyproject.toml | 2 +- socketsecurity/__init__.py | 2 +- socketsecurity/core/__init__.py | 15 ++++++++++----- workflows/github-actions.yml | 2 +- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 827f66d..d2f79a4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "hatchling.build" [project] name = "socketsecurity" -version = "2.1.32" +version = "2.1.33" requires-python = ">= 3.10" license = {"file" = "LICENSE"} dependencies = [ diff --git a/socketsecurity/__init__.py b/socketsecurity/__init__.py index 5b35bb9..c03b717 100644 --- a/socketsecurity/__init__.py +++ b/socketsecurity/__init__.py @@ -1,2 +1,2 @@ __author__ = 'socket.dev' -__version__ = '2.1.32' +__version__ = '2.1.33' diff --git a/socketsecurity/core/__init__.py b/socketsecurity/core/__init__.py index ec85d4e..7c43265 100644 --- a/socketsecurity/core/__init__.py +++ b/socketsecurity/core/__init__.py @@ -389,15 +389,20 @@ def has_manifest_files(self, files: list) -> bool: from .utils import socket_globs as fallback_patterns patterns = fallback_patterns + # Normalize all file paths for matching + norm_files = [f.replace('\\', '/').lstrip('./') for f in files] + for ecosystem in patterns: ecosystem_patterns = patterns[ecosystem] for file_name in ecosystem_patterns: pattern_str = ecosystem_patterns[file_name]["pattern"] - for file in files: - if "\\" in file: - file = file.replace("\\", "/") - if PurePath(file).match(pattern_str): - return True + # Expand brace patterns for each manifest pattern + expanded_patterns = Core.expand_brace_pattern(pattern_str) + for exp_pat in expanded_patterns: + for file in norm_files: + # Use PurePath.match for glob-like matching + if PurePath(file).match(exp_pat): + return True return False def check_file_count_limit(self, file_count: int) -> dict: diff --git a/workflows/github-actions.yml b/workflows/github-actions.yml index 866f654..422eb25 100644 --- a/workflows/github-actions.yml +++ b/workflows/github-actions.yml @@ -15,7 +15,7 @@ on: # Prevent concurrent runs for the same commit concurrency: - group: socket-scan-${{ github.ref }}-${{ github.sha }} + group: socket-scan-${{ github.sha }} cancel-in-progress: true jobs: