Skip to content
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
950694b
feat(output): show patched versions in security findings
lelia Aug 13, 2026
7c1ec81
feat(ci): preserve pull request context in scan metadata
lelia Aug 13, 2026
7cf8682
chore(release): bump version to 2.9.0
lelia Sep 2, 2026
fa6ec9a
refactor: share one git remote parser between Buildkite consumers
lelia Sep 2, 2026
0bdac6c
fix(ci): apply the pull request link to an already-compared scan pair
lelia Sep 2, 2026
54e4b2f
fix(comments): make per-alert ignores round trip
lelia Sep 3, 2026
90462b7
fix(comments): preserve dependency change types
lelia Sep 3, 2026
004cae4
fix(ci): use full scans outside pull requests
lelia Sep 3, 2026
167554f
docs: update release notes for comment fixes
lelia Sep 3, 2026
95483f3
fix(ci): restrict SCM diffs to pull requests
lelia Sep 3, 2026
8f9e402
fix(scans): keep the package list on full scans
lelia Sep 4, 2026
9e9bc58
fix(ci): keep branch pipelines out of pull request handling
lelia Sep 4, 2026
39403c7
fix(comments): stop reading an npm scope as an ecosystem
lelia Sep 4, 2026
78199e2
fix(comments): keep the diff badge where artwork exists
lelia Sep 4, 2026
f869a52
refactor(config): scope the config-file defaults dict to its block
lelia Sep 4, 2026
fc36c76
docs: correct the release notes for branch pipeline scans
lelia Sep 4, 2026
63e938d
fix(comments): stop legacy comment updates crashing on scoped names
lelia Sep 11, 2026
977a8fb
fix(comments): require write access to ignore an alert
lelia Sep 11, 2026
f16525f
fix(ci): validate CI-supplied server URLs before building a link
lelia Sep 11, 2026
d7b01b0
docs: correct the add_purl_capabilities docstring
lelia Sep 11, 2026
bd2a3c3
docs: record the review fixes in the 2.9.0 release notes
lelia Sep 11, 2026
239c85f
docs: rewrite branch comments for the reader, not the author
lelia Sep 11, 2026
7a986c8
fix(comments): parse legacy alert rows defensively
lelia Sep 11, 2026
adb56c6
feat(comments): add --ignore-authorization
lelia Sep 12, 2026
b8502bb
fix(comments): escape repository-derived values when rendering comments
lelia Sep 12, 2026
a320008
fix(gitlab): make the authentication fallback actually run
lelia Sep 12, 2026
87a631b
fix(review): address authorization and full-scan findings
lelia Sep 12, 2026
dd02c76
Merge remote-tracking branch 'origin/main' into lelia/patched-version…
lelia Sep 15, 2026
6ce6d48
fix(comments): close ignore authorization gaps
lelia Sep 15, 2026
726258b
Merge remote-tracking branch 'origin/main' into lelia/patched-version…
lelia Sep 15, 2026
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
83 changes: 83 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,88 @@
# Changelog

## 2.9.0

### Added: patched versions in human-readable security output

- The native console alert table now includes a `Patched Version` column,
populated from `props.firstPatchedVersionIdentifier` when the API provides it.
- GitHub pull request and GitLab merge request security comments now show the
patched version in each applicable alert's details.

### Fixed: CLI scans retain pull request context in the Socket Dashboard

- Pull request numbers are detected from standard GitHub Actions, GitLab CI,
and Azure Pipelines environments when `--pr-number` is not supplied. An
explicitly supplied value, including `0`, remains authoritative.
- The Buildkite workflow and CI/CD guide now forward `BUILDKITE_PULL_REQUEST`
explicitly and document provider selection for Dashboard PR association. With
`--integration github` or `--integration gitlab`, the repository slug and host
for the link are read from `BUILDKITE_REPO`, covering self-hosted installations.
- `--scm github` and `--scm gitlab` now imply the matching scan integration
unless `--integration` is explicitly supplied.
- Diff scans include the detected pull request or merge request URL as their
external link, allowing Dashboard reports to retain their CI change context.
Re-running a comparison over an already-compared scan pair now applies the
link to the existing diff scan instead of leaving that report unassociated.
- A `--pr-number` value that is not a positive integer is now normalized to `0`
before the GitHub adapter reads it, so Buildkite's `false` on a branch build no
longer makes that build look like a pull request event.

### Changed: GitHub and GitLab branch pipelines create full scans

- With `--scm github` or `--scm gitlab`, only pull request and merge request
events create diff scans. Every other pipeline, including default-branch
pushes, creates a full scan. The detected event type is authoritative:
`--enable-diff` and `--ignore-commit-files` no longer opt an SCM branch run
into comparison mode.
- Those runs no longer set a blocking exit code. A full scan has no baseline, so
it cannot distinguish newly introduced alerts from pre-existing ones; the CLI
now behaves as if `--disable-blocking` was supplied, matching how it already
treats a run with no supported manifest files. Pull request and merge request
pipelines are unaffected and still block.
- `--generate-license` and `--legal-format fossa` fetch the package list on this
path, so attribution files generated from a branch pipeline are complete rather
than empty.

### Changed: `@SocketSecurity ignore` requires write access

- An ignore command suppresses a security alert, but the CLI honored one from any
commenter, including a drive-by comment from someone with no access to the
repository. Commands are now accepted only from an author with write access.
- On GitHub this is read from the `author_association` GitHub already returns with
each comment, so it costs no extra request: `OWNER`, `MEMBER` and `COLLABORATOR`
are honored, and `CONTRIBUTOR`, `FIRST_TIME_CONTRIBUTOR`, `MANNEQUIN` and `NONE`
are not.
- GitLab notes carry no equivalent field, so project membership is read once per
run (only when an ignore command is present) and Developer or above is required.
If that lookup cannot be answered — a `CI_JOB_TOKEN` generally cannot read the
members API — the command is still honored and a warning names the author, so
enabling this does not silently break pipelines that relied on ignore commands.
Use a `GITLAB_TOKEN` with API read access to get enforcement.
- A rejected command is logged and is also absent from the ignore telemetry, which
records what was acted on.

### Fixed: pull request and merge request comment accuracy

- Per-alert ignore instructions now use ecosystem-qualified package names and
accept scoped packages while remaining compatible with older bare-name replies.
A leading npm scope is no longer mistaken for an ecosystem, so
`ignore @types/node@*` no longer also ignores the package named `node`.
- Dependency overviews preserve added, updated, removed, and replaced package
classifications instead of presenting updates as new dependencies. Added and
updated rows keep their diff badge; removed and replaced, which have no
published badge, use a text label.
- Shared security comment copy no longer describes GitLab merge request output
as Socket for GitHub.
- Updating a security comment in the legacy table format no longer raises on a
scoped package name. That path split the package cell on every `@`, so a name
carrying its own `@` unpacked into three values; it now splits from the right,
matching the current comment format. Ignore commands for a scoped package are
accepted there in both the ecosystem-qualified and bare forms.
- Server URLs read from `GITHUB_SERVER_URL` and `CI_SERVER_URL` are validated as
http(s) URLs before being composed into a diff scan's external link, matching
the check already applied to the other repository URLs read from CI.

## 2.8.1

### Changed: bump pinned @coana-tech/cli to 15.10.40
Expand Down
147 changes: 139 additions & 8 deletions docs/ci-cd.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

Use this guide for pipeline-focused CLI usage across platforms.

The shell commands in the recommended patterns are CI-provider neutral. Buildkite
pipeline equivalents and provider-specific considerations are called out alongside
the relevant guidance below.

## Recommended patterns

### Dashboard-style reachable SARIF
Expand All @@ -27,6 +31,27 @@ socketcli \
--strict-blocking
```

### Buildkite: retain SARIF as a build artifact

Either recommended pattern can run directly in a Buildkite command step. When the
scan writes SARIF, add
[`artifact_paths`](https://buildkite.com/docs/pipelines/configure/artifacts#upload-artifacts-with-a-command-step)
so developers can download the report from the build after the command finishes:

```yaml
steps:
- label: ":socket: Socket reachable diff"
command: |
socketcli \
--reach \
--sarif-file results.sarif \
--sarif-scope diff \
--sarif-reachability reachable \
--strict-blocking
artifact_paths:
- "results.sarif"
```

## Config file usage in CI

Use `--config .socketcli.toml` or `--config .socketcli.json` to keep pipeline commands small.
Expand Down Expand Up @@ -60,6 +85,9 @@ Equivalent JSON:
}
```

The Buildkite examples below use the same checked-in `.socketcli.toml` file; no
Buildkite-specific config-file format is required.

## Platform examples

### GitHub Actions
Expand Down Expand Up @@ -306,26 +334,46 @@ initial timeout signal or 137 if `SIGKILL` is involved.

### Buildkite

This example assumes a GitHub-hosted repository. Change
`SOCKET_SCM_INTEGRATION` to `gitlab` for a GitLab-hosted repository, or `api`
when provider association is not wanted. The doubled dollar signs defer
Buildkite variable expansion until the command runs on an agent.

```yaml
env:
SOCKET_SCM_INTEGRATION: "github"

steps:
- label: "Socket scan"
command: "socketcli --config .socketcli.toml --target-path ."
env:
SOCKET_SECURITY_API_TOKEN: "${SOCKET_SECURITY_API_TOKEN}"
command: |
socketcli \
--config .socketcli.toml \
--target-path . \
--integration "$${SOCKET_SCM_INTEGRATION:-api}" \
--pr-number "$${BUILDKITE_PULL_REQUEST:-0}"
secrets:
- SOCKET_SECURITY_API_TOKEN
```

The `secrets` block expects a
[Buildkite secret](https://buildkite.com/docs/pipelines/security/secrets/buildkite-secrets)
named `SOCKET_SECURITY_API_TOKEN`. If your organization uses an external secrets
plugin or an agent hook instead, remove that block and inject the same environment
variable through your existing mechanism. Do not store the token in pipeline YAML.

The CLI reads Buildkite's native `BUILDKITE_COMMIT`, `BUILDKITE_BRANCH`,
`BUILDKITE_PULL_REQUEST`, and `BUILDKITE_PULL_REQUEST_BASE_BRANCH` variables.
For pull-request builds, ensure the checkout contains the base branch and the
checked-out head commit. The CLI uses those local refs first and performs a
targeted fetch only when a required ref or its comparison history is missing;
it does not fetch every remote ref and tag during startup.

When `--scm github` is used from Buildkite, the CLI also derives GitHub comment
context from `BUILDKITE_REPO`, `BUILDKITE_BUILD_CHECKOUT_PATH`, and the variables
above. Set `GH_API_TOKEN` to a GitHub token with the required repository access.
GitHub Enterprise users should also set `GITHUB_API_URL`; GitHub.com defaults to
`https://api.github.com`.
When `--scm github` is used from Buildkite, the CLI also posts GitHub PR comments.
It identifies the repository from `BUILDKITE_REPO` and takes the rest of the build
context from `BUILDKITE_BUILD_CHECKOUT_PATH` and the variables above — see
[Buildkite PR context](#buildkite-pr-context). Set `GH_API_TOKEN` to a GitHub token
with the required repository access. GitHub Enterprise users should also set
`GITHUB_API_URL`; GitHub.com defaults to `https://api.github.com`.

#### Merge-base baselines in Buildkite (dynamic pipelines)

Expand Down Expand Up @@ -385,6 +433,18 @@ socket_scan:
SOCKET_SECURITY_API_TOKEN: $SOCKET_SECURITY_API_TOKEN
```

### Azure Pipelines

```yaml
- script: |
socketcli \
--integration azure \
--enable-diff \
--target-path "$(Build.SourcesDirectory)"
env:
SOCKET_SECURITY_API_TOKEN: $(SOCKET_SECURITY_API_TOKEN)
```

### Bitbucket Pipelines

```yaml
Expand All @@ -395,6 +455,69 @@ pipelines:
- socketcli --config .socketcli.toml --target-path .
```

## Scan type by pipeline

With `--scm github` or `--scm gitlab`, the detected event decides the scan type:

| Event | Scan | Blocks the build |
|:------|:-----|:-----------------|
| Pull request / merge request | Diff scan against the repository's baseline | Yes, on newly introduced alerts |
| Any other pipeline, including default-branch pushes | Full scan | No |

A full scan has no baseline, so it cannot tell a newly introduced alert from one
that was already there. Rather than block on a number that would mean something
different depending on which output format was enabled, those runs behave as if
`--disable-blocking` was supplied and report through the Dashboard instead. This
matches how the CLI already treats a run with no supported manifest files.

The event type is authoritative once `--scm` is set: `--enable-diff` and
`--ignore-commit-files` do not turn a branch pipeline into a comparison. To diff
a branch build, drop `--scm` and use `--enable-diff` with `--integration`, which
runs the comparison without the PR comment adapter.

`--generate-license` and `--legal-format fossa` work on both paths; a full scan
fetches the package list for them.

## Pull request and Dashboard association

The CLI sends the resolved pull request number with each full scan and attaches
the pull request URL to diff scans so the Socket Dashboard can associate the
report with its originating change. If `--pr-number` is supplied, it wins;
passing `--pr-number 0` explicitly disables automatic association. Any value that
is not a positive integer, including Buildkite's `false`, means no pull request.

Without an explicit value, the CLI recognizes:

- GitHub Actions: `PR_NUMBER`, then the PR number in `GITHUB_REF`.
- GitLab CI: `CI_MERGE_REQUEST_IID`.
- Azure Pipelines: `SYSTEM_PULLREQUEST_PULLREQUESTNUMBER` for GitHub-hosted
repositories, otherwise `SYSTEM_PULLREQUEST_PULLREQUESTID` for Azure Repos.

### Buildkite PR context

Buildkite is SCM-provider neutral, so the CLI does not infer a provider or consume
its PR variable automatically. Pass Buildkite's
[`BUILDKITE_PULL_REQUEST`](https://buildkite.com/docs/pipelines/configure/environment-variables#BUILDKITE_PULL_REQUEST)
value to
`--pr-number` and identify the repository host with `--integration`, as shown in
the Buildkite platform example above. Buildkite sets `BUILDKITE_PULL_REQUEST` to
`false` outside PR builds; the CLI treats that value as no PR.

Use `--integration github` for GitHub-hosted repositories and `--integration gitlab`
for GitLab-hosted ones. The CLI identifies the repository from
[`BUILDKITE_REPO`](https://buildkite.com/docs/pipelines/configure/environment-variables#BUILDKITE_REPO),
taking both the slug and the host from it, so github.com, GitLab.com, and self-hosted
installations all build a correct pull request or merge request link without extra
configuration. That same value identifies the repository for GitHub PR comments when
`--scm github` is set. `CI_PROJECT_URL` still overrides the derived GitLab project URL.
Keep `--scm api` unless you also intend to configure an existing GitHub or GitLab
comment adapter and its provider token.

`--scm github` and `--scm gitlab` also imply the matching scan integration for
Dashboard metadata unless `--integration` was explicitly supplied. PR comments
remain limited to the existing GitHub and GitLab SCM adapters; Azure receives
console output and Dashboard association but does not post a PR comment.

## Workflow templates

Prebuilt examples in this repo:
Expand All @@ -411,3 +534,11 @@ Prebuilt examples in this repo:
- `--sarif-grouping alert` currently applies to `--sarif-scope full`.
- Diff-based SARIF can validly be empty when there are no matching net-new alerts.
- Keep API tokens in secret stores (`SOCKET_SECURITY_API_TOKEN`), not in config files.
- In Buildkite pipeline YAML, follow its
[runtime interpolation](https://buildkite.com/docs/pipelines/configure/environment-variables#runtime-variable-interpolation)
guidance and use `$$` for variables that must expand when the command runs rather
than when the pipeline is uploaded.
- Security findings with `props.firstPatchedVersionIdentifier` show that value in
the console table, including native Buildkite job logs, and in GitHub/GitLab
security comments when that SCM adapter is configured. Findings without a known
patched release leave the console cell blank and omit the comment field.
25 changes: 22 additions & 3 deletions docs/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ If you don't want to provide the Socket API Token every time then you can use th
| `--repo` | False | *auto* | Repository name in owner/repo format (auto-detected from git remote) |
| `--workspace` | False | | The Socket workspace to associate the scan with (e.g. `my-org` in `my-org/my-repo`). See note below. |
| `--repo-is-public` | False | False | If set, flags a new repository creation as public. Defaults to false. |
| `--integration` | False | api | Integration type (api, github, gitlab, azure, bitbucket) |
| `--integration` | False | api | Integration type (api, github, gitlab, azure, bitbucket). When omitted, `--scm github` or `--scm gitlab` implies the matching integration. |
| `--owner` | False | | Name of the integration owner, defaults to the socket organization slug |
| `--branch` | False | *auto* | Branch name (auto-detected from git) |
| `--committers` | False | *auto* | Committer(s) to filter by (auto-detected from git commit) |
Expand All @@ -252,7 +252,7 @@ If you don't want to provide the Socket API Token every time then you can use th
#### Pull Request and Commit
| Parameter | Required | Default | Description |
|:-----------------|:---------|:--------|:-----------------------------------------------|
| `--pr-number` | False | "0" | Pull request number |
| `--pr-number` | False | *auto* | Pull request number. Auto-detected in GitHub Actions, GitLab CI, and Azure Pipelines; explicitly passing `0` disables detection. |
| `--commit-message` | False | *auto* | Commit message (auto-detected from git) |
| `--commit-sha` | False | *auto* | Commit SHA (auto-detected from git) |
| `--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` |
Expand Down Expand Up @@ -431,7 +431,7 @@ The launcher can be tuned via the `SOCKET_CLI_COANA_LAUNCHER` environment variab
|:-------------------------|:---------|:--------|:----------------------------------------------------------------------|
| `--ignore-commit-files` | False | False | Ignore commit files |
| `--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`. |
| `--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. |
| `--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). |
| `--strict-blocking` | False | False | Fail on ANY security policy violations (blocking severity), not just new ones. Only works in diff mode. See [Strict Blocking Mode](#strict-blocking-mode) for details. |
| `--enable-diff` | False | False | Enable diff mode even when using `--integration api` (forces diff mode without SCM integration) |
| `--scm` | False | api | Source control management type |
Expand Down Expand Up @@ -690,6 +690,25 @@ The CLI uses intelligent default branch detection with the following priority:

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

## Who can ignore an alert

`@SocketSecurity ignore <ecosystem>/<package>@<version>` and
`@SocketSecurity ignore-all` suppress security findings, so the CLI honors them
only from a commenter with write access to the repository. A command from anyone
else is skipped, logged with the author's name, and the alerts it named stay
reported. `--disable-ignore` turns the feature off entirely.

| Provider | How access is determined | If it cannot be determined |
|:---------|:-------------------------|:---------------------------|
| GitHub | The `author_association` returned with each comment. `OWNER`, `MEMBER` and `COLLABORATOR` are honored. | Treated as unauthorized. |
| GitLab | Project membership, read once per run when an ignore command is present. Developer (30) or above is honored. | The command is honored and a warning is logged. |

GitLab notes carry no permission field, so the check needs a `GITLAB_TOKEN` that
can read `GET /projects/:id/members/all`. A `CI_JOB_TOKEN` generally cannot, and
in that case the CLI logs a warning and still honors the command rather than
breaking a pipeline that was already relying on it. Use a personal or group access
token with API read access to get enforcement.

## GitLab Token Configuration

GitLab token/auth behavior and CI examples are documented in [`ci-cd.md`](ci-cd.md).
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.8.1"
version = "2.9.0"
requires-python = ">= 3.11"
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,3 +1,3 @@
__author__ = 'socket.dev'
__version__ = '2.8.1'
__version__ = '2.9.0'
USER_AGENT = f'SocketPythonCLI/{__version__}'
Loading