Skip to content

fix: correct default branch detection and ensure consistent scanning … #102

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 102 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,45 @@
# Socket Security CLI

The Socket Security CLI was created to enable integrations with other tools like GitHub Actions, Gitlab, BitBucket, local use cases and more. The tool will get the head scan for the provided repo from Socket, create a new one, and then report any new alerts detected. If there are new alerts against the Socket security policy it'll exit with a non-Zero exit code.
The Socket Security CLI was created to enable integrations with other tools like GitHub Actions, GitLab, BitBucket, local use cases and more. The tool will get the head scan for the provided repo from Socket, create a new one, and then report any new alerts detected. If there are new alerts against the Socket security policy it'll exit with a non-Zero exit code.

## Quick Start

The CLI now features automatic detection of git repository information, making it much simpler to use in CI/CD environments. Most parameters are now optional and will be detected automatically from your git repository.

### Minimal Usage Examples

**GitHub Actions:**
```bash
socketcli --target-path $GITHUB_WORKSPACE --scm github --pr-number $PR_NUMBER
```

**GitLab CI:**
```bash
socketcli --target-path $CI_PROJECT_DIR --scm gitlab --pr-number ${CI_MERGE_REQUEST_IID:-0}
```

**Local Development:**
```bash
socketcli --target-path ./my-project
```

The CLI will automatically detect:
- Repository name from git remote
- Branch name from git
- Commit SHA and message from git
- Committer information from git
- Default branch status from git and CI environment
- Changed files from git commit history

## CI/CD Workflow Examples

Pre-configured workflow examples are available in the [`workflows/`](workflows/) directory:

- **[GitHub Actions](workflows/github-actions.yml)** - Complete workflow with concurrency control and automatic PR detection
- **[GitLab CI](workflows/gitlab-ci.yml)** - Pipeline configuration with caching and environment variable handling
- **[Bitbucket Pipelines](workflows/bitbucket-pipelines.yml)** - Basic pipeline setup with optional path filtering

These examples are production-ready and include best practices for each platform.

## Usage

Expand All @@ -25,36 +64,36 @@ If you don't want to provide the Socket API Token every time then you can use th
#### Repository
| Parameter | Required | Default | Description |
|:-----------------|:---------|:--------|:------------------------------------------------------------------------|
| --repo | False | | Repository name in owner/repo format |
| --repo | False | *auto* | Repository name in owner/repo format (auto-detected from git remote) |
| --integration | False | api | Integration type (api, github, gitlab) |
| --owner | False | | Name of the integration owner, defaults to the socket organization slug |
| --branch | False | "" | Branch name |
| --committers | False | | Committer(s) to filter by |
| --branch | False | *auto* | Branch name (auto-detected from git) |
| --committers | False | *auto* | Committer(s) to filter by (auto-detected from git commit) |
| --repo-is-public | False | False | If set, flags a new repository creation as public. Defaults to false. |

#### Pull Request and Commit
| Parameter | Required | Default | Description |
|:-----------------|:---------|:--------|:--------------------|
| --pr-number | False | "0" | Pull request number |
| --commit-message | False | | Commit message |
| --commit-sha | False | "" | Commit SHA |
| Parameter | Required | Default | Description |
|:-----------------|:---------|:--------|:-----------------------------------------------|
| --pr-number | False | "0" | Pull request number |
| --commit-message | False | *auto* | Commit message (auto-detected from git) |
| --commit-sha | False | *auto* | Commit SHA (auto-detected from git) |

#### Path and File
| Parameter | Required | Default | Description |
|:----------------------------|:---------|:----------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| --target-path | False | ./ | Target path for analysis |
| --sbom-file | False | | SBOM file path |
| --files | False | [] | Files to analyze (JSON array string) |
| --files | False | *auto* | Files to analyze (JSON array string). Auto-detected from git commit changes when not specified |
| --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) |
| --license-file-name | False | `license_output.json` | Name of the file to save the license details to if enabled |
| --save-submitted-files-list | False | | Save list of submitted file names to JSON file for debugging purposes |
| --save-manifest-tar | False | | Save all manifest files to a compressed tar.gz archive with original directory structure |

#### Branch and Scan Configuration
| Parameter | Required | Default | Description |
|:-----------------|:---------|:--------|:------------------------------------------------------------|
| --default-branch | False | False | Make this branch the default branch |
| --pending-head | False | False | If true, the new scan will be set as the branch's head scan |
| Parameter | Required | Default | Description |
|:-----------------|:---------|:--------|:------------------------------------------------------------------------------------------------------|
| --default-branch | False | *auto* | Make this branch the default branch (auto-detected from git and CI environment when not specified) |
| --pending-head | False | *auto* | If true, the new scan will be set as the branch's head scan (automatically synced with default-branch) |

#### Output Configuration
| Parameter | Required | Default | Description |
Expand Down Expand Up @@ -114,26 +153,66 @@ Example `SOCKET_SLACK_CONFIG_JSON` value
{"url": "https://REPLACE_ME_WEBHOOK"}
````

## Automatic Git Detection

The CLI now automatically detects repository information from your git environment, significantly simplifying usage in CI/CD pipelines:

### Auto-Detected Information

- **Repository name**: Extracted from git remote origin URL
- **Branch name**: Current git branch or CI environment variables
- **Commit SHA**: Latest commit hash or CI-provided commit SHA
- **Commit message**: Latest commit message
- **Committer information**: Git commit author details
- **Default branch status**: Determined from git repository and CI environment
- **Changed files**: Files modified in the current commit (for differential scanning)

### Default Branch Detection

The CLI uses intelligent default branch detection with the following priority:

1. **Explicit `--default-branch` flag**: Takes highest priority when specified
2. **CI environment detection**: Uses CI platform variables (GitHub Actions, GitLab CI)
3. **Git repository analysis**: Compares current branch with repository's default branch
4. **Fallback**: Defaults to `false` if none of the above methods succeed

Both `--default-branch` and `--pending-head` parameters are automatically synchronized to ensure consistent behavior.

### Scan Behavior

The CLI determines scanning behavior intelligently:

- **Manifest files changed**: Performs differential scan with PR/MR comments when supported
- **No manifest files changed**: Creates full repository scan report without waiting for diff results
- **Force API mode**: When no supported manifest files are detected, automatically enables non-blocking mode

## File Selection Behavior

The CLI determines which files to scan based on the following logic:

1. **Git Commit Files**: By default, the CLI checks files changed in the current git commit first. If any of these files match supported manifest patterns (like package.json, requirements.txt, etc.), a scan is triggered.
1. **Git Commit Files (Default)**: The CLI automatically checks files changed in the current git commit. If any of these files match supported manifest patterns (like package.json, requirements.txt, etc.), a scan is triggered.

2. **`--files` Parameter Override**: When specified, this parameter takes precedence over git commit detection. It accepts a JSON array of file paths to check for manifest files.

3. **`--ignore-commit-files` Flag**: When set, git commit files are ignored completely, and the CLI will scan all manifest files in the target directory regardless of what changed.

2. **`--files` Parameter**: If no git commit exists, or no manifest files are found in the commit changes, the CLI checks files specified via the `--files` parameter. This parameter accepts a JSON array of file paths.
4. **Automatic Fallback**: If no manifest files are found in git commit changes and no `--files` are specified, the CLI automatically switches to "API mode" and performs a full repository scan.

3. **`--ignore-commit-files`**: When this flag is set, git commit files are ignored completely, and only files specified in `--files` are considered. This also forces a scan regardless of whether manifest files are present.
> **Important**: The CLI doesn't scan only the specified files - it uses them to determine whether a scan should be performed and what type of scan to run. When triggered, it searches the entire `--target-path` for all supported manifest files.

4. **No Manifest Files**: If no manifest files are found in either git commit changes or `--files` (and `--ignore-commit-files` is not set), the scan is skipped.
### Scanning Modes

> **Note**: The CLI does not scan only the specified files - it uses them to determine whether a scan should be performed. When a scan is triggered, it searches the entire `--target-path` for all supported manifest files.
- **Differential Mode**: When manifest files are detected in changes, performs a diff scan with PR/MR comment integration
- **API Mode**: When no manifest files are in changes, creates a full scan report without PR comments but still scans the entire repository
- **Force Mode**: With `--ignore-commit-files`, always performs a full scan regardless of changes

### Examples

- **Commit with manifest file**: If your commit includes changes to `package.json`, a scan will be triggered automatically.
- **Commit without manifest files**: If your commit only changes non-manifest files (like `.github/workflows/socket.yaml`), no scan will be performed unless you use `--files` or `--ignore-commit-files`.
- **Using `--files`**: If you specify `--files '["package.json"]'`, the CLI will check if this file exists and is a manifest file before triggering a scan.
- **Using `--ignore-commit-files`**: This forces a scan of all manifest files in the target path, regardless of what's in your commit.
- **Commit with manifest file**: If your commit includes changes to `package.json`, a differential scan will be triggered automatically with PR comment integration.
- **Commit without manifest files**: If your commit only changes non-manifest files (like `.github/workflows/socket.yaml`), the CLI automatically switches to API mode and performs a full repository scan.
- **Using `--files`**: If you specify `--files '["package.json"]'`, the CLI will check if this file exists and is a manifest file before determining scan type.
- **Using `--ignore-commit-files`**: This forces a full scan of all manifest files in the target path, regardless of what's in your commit.
- **Auto-detection**: Most CI/CD scenarios now work with just `socketcli --target-path /path/to/repo --scm github --pr-number $PR_NUM`

## Debugging and Troubleshooting

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ build-backend = "hatchling.build"

[project]
name = "socketsecurity"
version = "2.1.23"
version = "2.1.24"
requires-python = ">= 3.10"
license = {"file" = "LICENSE"}
dependencies = [
Expand Down
2 changes: 1 addition & 1 deletion socketsecurity/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
__author__ = 'socket.dev'
__version__ = '2.1.23'
__version__ = '2.1.24'
41 changes: 13 additions & 28 deletions socketsecurity/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ def create_full_scan_with_report_url(
no_change: bool = False,
save_files_list_path: str = None,
save_manifest_tar_path: str = None
) -> dict:
) -> Diff:
"""Create a new full scan and return with html_report_url.

Args:
Expand All @@ -501,12 +501,13 @@ def create_full_scan_with_report_url(
Dict with full scan data including html_report_url
"""
log.debug(f"starting create_full_scan_with_report_url with no_change: {no_change}")
diff = Diff(
id="NO_SCAN_RAN",
report_url="",
diff_url=""
)
if no_change:
return {
"id": "NO_SCAN_RAN",
"html_report_url": "",
"unmatchedFiles": []
}
return diff

# Find manifest files
files = self.find_files(path)
Expand All @@ -521,11 +522,7 @@ def create_full_scan_with_report_url(

files_for_sending = self.load_files_for_sending(files, path)
if not files:
return {
"id": "NO_SCAN_RAN",
"html_report_url": "",
"unmatchedFiles": []
}
return diff

try:
# Create new scan
Expand All @@ -539,25 +536,13 @@ def create_full_scan_with_report_url(

# Construct report URL
base_socket = "https://socket.dev/dashboard/org"
report_url = f"{base_socket}/{self.config.org_slug}/sbom/{new_full_scan.id}"
if not params.include_license_details:
report_url += "?include_license_details=false"
diff.report_url = f"{base_socket}/{self.config.org_slug}/sbom/{new_full_scan.id}"
diff.diff_url = diff.report_url
diff.id = new_full_scan.id
diff.packages = {}

# Return result in the format expected by the user
return {
"id": new_full_scan.id,
"created_at": new_full_scan.created_at,
"updated_at": new_full_scan.updated_at,
"organization_id": new_full_scan.organization_id,
"repository_id": new_full_scan.repository_id,
"branch": new_full_scan.branch,
"commit_message": new_full_scan.commit_message,
"commit_hash": new_full_scan.commit_hash,
"pull_request": new_full_scan.pull_request,
"committers": new_full_scan.committers,
"html_report_url": report_url,
"unmatchedFiles": getattr(new_full_scan, 'unmatchedFiles', [])
}
return diff

def check_full_scans_status(self, head_full_scan_id: str, new_full_scan_id: str) -> bool:
is_ready = False
Expand Down
Loading
Loading