Skip to content

Commit 184dc0d

Browse files
authored
Detect manifest changes across the whole pull request range, and fix full-scan reporting (#371)
* Detect changed files across the whole base..HEAD range Changed-file detection reads a full comparison range only when it recognizes the CI environment: a GitHub pull request, a GitLab merge request, a Bitbucket pull request, or a Buildkite pull request. Every other run falls through to `git show HEAD`, which sees the tip commit alone. That makes dependency gating depend on commit ordering. A pull request whose manifest changed in an earlier commit, followed by a source-only commit, looks like a source-only change: the supported-manifest check fails, the comparison is abandoned for a full scan, and blocking is suppressed, so the run reports no new issues and exits 0. A caller that supplies a base commit has stated the range outright, so honor it ahead of any inference from the environment, reusing the same range detection the recognized providers already use. An unresolvable base commit warns rather than degrading quietly, because the fallback silently narrows the comparison to one commit. * Report full-scan findings as repository findings, not new ones A run with no baseline creates a full scan and suppresses blocking, because there is nothing to compare against and so nothing can be attributed to the change. When an alert-bearing output format is enabled the scan still carries every finding in the repository, and the console summary labeled those `NEW` and their link `Diff Url`. Both are wrong for a full scan, and the first contradicts the exit code: the summary reported blocking issues while the run exited 0, which reads as gating that silently failed rather than gating that correctly did not apply. Label the counts and the link by what the run produced, and say why the counts do not gate. The alert list itself is left alone, since SARIF and JSON output read it and renaming their fields would break consumers. * Stop doubling the namespace in a removed package's purl update_package_values already prefixes a namespaced package's purl with its namespace, so prefixing it again while collecting removed artifacts produced `com.example/widget@1.0.0com.example/com.example/widget@1.0.0`. The purl reaches the dependency overview comment verbatim, so every removed or replaced row for a namespaced package rendered with an unreadable name. The loop collecting added artifacts calls the same function and never did this. * Describe --ignore-commit-files by what it does, and release 2.10.0 The CLI reference described `--ignore-commit-files` as forcing a full scan in four places, and `--help` said only "Ignore commit files". The flag forces a comparison. The confusion is that "full scan" carries two meanings here: the set of files scanned, where the documentation was right, and the scan mode, where it stated the opposite of the behavior. Anyone looking for a way to run a comparison when the changed-file check would skip one would rule out the only flag that does it. Also documents the range that changed-file detection reads, and that supplying a base commit widens it. * Handle explicit base ranges in shallow clones
1 parent 325d551 commit 184dc0d

13 files changed

Lines changed: 371 additions & 61 deletions

‎CHANGELOG.md‎

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,32 @@
11
# Changelog
22

3-
## 2.9.8
3+
## 2.10.0
44

5-
### Fixed: oversized commit messages no longer fail the scan
5+
### Fixed
6+
7+
- `--base-commit-sha` now sets the range changed-file detection reads, so a manifest
8+
changed anywhere between that commit and HEAD triggers a comparison. Previously only
9+
a recognized GitHub, GitLab, Bitbucket, or Buildkite pull request read a full range,
10+
and every other run saw the current commit alone.
11+
- A base commit that cannot be resolved in the checkout now warns instead of narrowing
12+
the comparison to a single commit.
13+
- A full scan reports its findings as repository findings rather than new ones, and
14+
labels its link `Report Url`. The summary states why the counts do not affect the
15+
exit code.
16+
- Removed and replaced packages with a namespace no longer render a duplicated purl in
17+
the dependency overview comment.
618

719
- The 200-character cap on the commit message now applies to the value read from the
820
repository, not only to `--commit-message`. A truncated message ends in `...` and the
921
truncation is reported at INFO.
1022
- A full scan refused for its size (HTTP 413, 414 or 431) now distinguishes possible
1123
upload-size and request-metadata causes and reports what to shorten.
1224

25+
### Changed
26+
27+
- `--ignore-commit-files` is documented as forcing a comparison, which is what it does.
28+
The CLI reference and `--help` described it as forcing a full scan.
29+
1330
## 2.9.7
1431

1532
### Changed: bump pinned @coana-tech/cli to 15.10.51

‎docs/cli-reference.md‎

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ If you don't want to provide the Socket API Token every time then you can use th
256256
| `--commit-message` | False | *auto* | Commit message (auto-detected from git) |
257257
| `--commit-sha` | False | *auto* | Commit SHA (auto-detected from git) |
258258
| `--base-scan-id` | False | | Full scan ID to diff against, overriding the repository's head scan as the baseline. Mutually exclusive with `--base-commit-sha` |
259-
| `--base-commit-sha`| False | | Commit SHA to prefer as the diff baseline, overriding the repository's head scan. The CLI uses its most recent matching full scan or the nearest scanned first-parent ancestor within 100 local commits. It errors (exit code 3, or `--exit-code-on-api-error`) if no scanned ancestor is reachable. Mutually exclusive with `--base-scan-id` |
259+
| `--base-commit-sha`| False | | Commit SHA to prefer as the diff baseline, overriding the repository's head scan. The CLI uses its most recent matching full scan or the nearest scanned first-parent ancestor within 100 local commits. It errors (exit code 3, or `--exit-code-on-api-error`) if no scanned ancestor is reachable. Also sets the range changed-file detection reads, so a manifest changed anywhere between this commit and HEAD is seen. Mutually exclusive with `--base-scan-id` |
260260

261261
> **Diffing against the merge base** — by default, PR scans are diffed against the repository's latest matching head scan, which may include newer default-branch commits than your PR branched from. To prefer the commit your PR is based on, compute the merge base and pass it as the baseline:
262262
>
@@ -267,6 +267,8 @@ If you don't want to provide the Socket API Token every time then you can use th
267267
>
268268
> `--base-commit-sha` does not create a scan of that commit. The CLI first looks for the newest non-temporary scan matching the repository, workspace, scan type, and exact commit. If the exact commit was not scanned, it walks up to 100 first-parent commits from that SHA in the local checkout and uses the nearest matching scanned ancestor. It logs a warning with the selected commit and distance because this produces a wider diff than the merge base.
269269
>
270+
> Supplying `--base-commit-sha` also widens the range the CLI reads when deciding whether any manifest changed. Without it, and outside a recognized CI pull request or merge request, the CLI sees only the current commit, so a pull request whose manifest changed in an earlier commit is treated as a source-only change and the comparison is skipped. If the base commit cannot be resolved in the local checkout, the CLI warns and falls back to the current commit alone; deepen the clone or fetch the base commit to compare the full range.
271+
>
270272
> Run `socketcli` regularly on the default branch so recent ancestors have scans. PR checkouts must also retain the merge base and enough first-parent history; shallow clones can shorten the search. Gaps are expected when CI cancels intermediate builds, commits use `[skip ci]`, pipelines are path-filtered, or the merge base predates your Socket rollout.
271273
>
272274
> If no scanned ancestor is reachable within the local 100-commit walk, the CLI **fails** (exit code 3, or your `--exit-code-on-api-error` value; exit 0 with `--disable-blocking`) instead of silently falling back to the repository head. API or permission failures also fail rather than being treated as a missing exact scan.
@@ -427,7 +429,7 @@ The launcher can be tuned via the `SOCKET_CLI_COANA_LAUNCHER` environment variab
427429
#### Advanced Configuration
428430
| Parameter | Required | Default | Description |
429431
|:-------------------------|:---------|:--------|:----------------------------------------------------------------------|
430-
| `--ignore-commit-files` | False | False | Ignore commit files |
432+
| `--ignore-commit-files` | False | False | Compare regardless of which files changed, scanning every manifest |
431433
| `--disable-blocking` | False | False | Non-blocking CI mode: the CLI always exits **0**, even when blocking alerts are present (including with `--strict-blocking`). Also exits 0 on uncaught runtime errors and Socket API failures, so the job is treated as successful while findings and errors are still logged. Takes precedence over `--strict-blocking`. |
432434
| `--disable-ignore` | False | False | Disable support for `@SocketSecurity ignore` commands in PR comments. When set, alerts cannot be suppressed via comments and ignore instructions are hidden from comment output. See [Who can ignore an alert](#who-can-ignore-an-alert). |
433435
| `--ignore-authorization` | False | enforce | Who may suppress alerts with `@SocketSecurity ignore`. `enforce` requires write access and honors the command with a warning when the provider cannot report it; `strict` rejects it in that case; `off` honors any commenter. See [Who can ignore an alert](#who-can-ignore-an-alert). |
@@ -674,10 +676,10 @@ The CLI now automatically detects repository information from your git environme
674676
- **Commit message**: Latest commit message
675677
- **Committer information**: Git commit author details
676678
- **Default branch status**: Determined from git repository and CI environment
677-
- **Changed files**: Files modified in the current commit (for differential scanning)
679+
- **Changed files**: Files modified in the current commit, or across the whole `--base-commit-sha`..HEAD range when a base commit is supplied (for differential scanning)
678680
> **Note on merge commits**:
679681
> Standard merges (two parents) are supported.
680-
> For *octopus merges* (three or more parents), Git only reports changes relative to the first parent. This can lead to incomplete or empty file lists if changes only exist relative to other parents. In these cases, differential scanning may be skipped. To ensure coverage, use `--ignore-commit-files` to force a full scan or specify files explicitly with `--files`.
682+
> For *octopus merges* (three or more parents), Git only reports changes relative to the first parent. This can lead to incomplete or empty file lists if changes only exist relative to other parents. In these cases, differential scanning may be skipped. To ensure coverage, use `--ignore-commit-files` to compare regardless of the detected changes, or specify files explicitly with `--files`.
681683
### Default Branch Detection
682684
683685
The CLI uses intelligent default branch detection with the following priority:
@@ -728,11 +730,11 @@ GitLab token/auth behavior and CI examples are documented in [`ci-cd.md`](ci-cd.
728730
729731
The CLI determines which files to scan based on the following logic:
730732
731-
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.
733+
1. **Git Commit Files (Default)**: The CLI automatically checks which files changed. In a recognized CI pull request or merge request, and whenever `--base-commit-sha` is supplied, that is every file changed across the range; otherwise it is the current commit alone. If any of them match supported manifest patterns (like package.json, requirements.txt, etc.), a comparison is run.
732734
733735
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.
734736
735-
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.
737+
3. **`--ignore-commit-files` Flag**: When set, the changed-file check is skipped entirely. The CLI runs the comparison regardless of what changed, and scans every manifest file in the target directory.
736738
737739
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.
738740
@@ -742,15 +744,15 @@ The CLI determines which files to scan based on the following logic:
742744
743745
- **Differential Mode**: When manifest files are detected in changes, performs a diff scan with PR/MR comment integration
744746
- **API Mode**: When no manifest files are in changes, creates a full scan report without PR comments but still scans the entire repository
745-
- **Force Mode**: With `--ignore-commit-files`, always performs a full scan regardless of changes
747+
- **Force Mode**: With `--ignore-commit-files`, always runs a comparison regardless of which files changed, over every manifest in the target path
746748
- **Forced Diff Mode**: With `--enable-diff`, forces differential mode even when using `--integration api` (without SCM integration)
747749
748750
### Examples
749751
750752
- **Commit with manifest file**: If your commit includes changes to `package.json`, a differential scan will be triggered automatically with PR comment integration.
751753
- **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.
752754
- **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.
753-
- **Using `--ignore-commit-files`**: This forces a full scan of all manifest files in the target path, regardless of what's in your commit.
755+
- **Using `--ignore-commit-files`**: This runs the comparison regardless of what's in your commit, over all manifest files in the target path. Use it when the changed-file check would otherwise skip a comparison you need.
754756
- **Using `--enable-diff`**: Forces diff mode without SCM integration - useful when you want differential scanning but are using `--integration api`. For example: `socketcli --integration api --enable-diff --target-path /path/to/repo`
755757
- **Auto-detection**: Most CI/CD scenarios now work with just `socketcli --target-path /path/to/repo --scm github --pr-number $PR_NUM`
756758

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
66

77
[project]
88
name = "socketsecurity"
9-
version = "2.9.8"
9+
version = "2.10.0"
1010
requires-python = ">= 3.11"
1111
license = {"file" = "LICENSE"}
1212
dependencies = [

‎socketsecurity/__init__.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
__author__ = 'socket.dev'
2-
__version__ = '2.9.8'
2+
__version__ = '2.10.0'
33
USER_AGENT = f'SocketPythonCLI/{__version__}'

‎socketsecurity/config.py‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,9 @@ def create_argument_parser() -> argparse.ArgumentParser:
631631
help="Commit SHA to diff the new scan against, overriding the repository's head "
632632
"scan as the baseline. The CLI uses the most recent matching full scan, or "
633633
"the nearest scanned first-parent ancestor within 100 local commits when "
634-
"the commit itself was not scanned. Mutually exclusive with --base-scan-id."
634+
"the commit itself was not scanned. Also sets the range changed-file "
635+
"detection reads, so a manifest changed anywhere between this commit and "
636+
"HEAD is seen. Mutually exclusive with --base-scan-id."
635637
)
636638

637639
# Path and File options
@@ -932,7 +934,7 @@ def create_argument_parser() -> argparse.ArgumentParser:
932934
"--ignore-commit-files",
933935
dest="ignore_commit_files",
934936
action="store_true",
935-
help="Ignore commit files"
937+
help="Compare against the baseline regardless of which files changed, scanning every manifest in the target path"
936938
)
937939
advanced_group.add_argument(
938940
"--ignore_commit_files",

‎socketsecurity/core/__init__.py‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2290,8 +2290,6 @@ def get_added_and_removed_packages(
22902290
try:
22912291
pkg = Package.from_diff_artifact(asdict(artifact))
22922292
pkg = Core.update_package_values(pkg)
2293-
if pkg.namespace:
2294-
pkg.purl += f"{pkg.namespace}/{pkg.purl}"
22952293
removed_packages[artifact.id] = pkg
22962294
except KeyError:
22972295
log.error(f"KeyError: Could not create package from removed artifact {artifact.id}")

0 commit comments

Comments
 (0)