Skip to content

Commit 5a2fa6a

Browse files
committed
document baseline overrides, merge-base workflow, Buildlkite-specific guidance
Signed-off-by: lelia <2418071+lelia@users.noreply.github.com>
1 parent 78a713a commit 5a2fa6a

3 files changed

Lines changed: 106 additions & 2 deletions

File tree

README.md

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,26 @@ socketcli --target-path .
4242
socketcli --enable-gitlab-security --gitlab-security-file gl-dependency-scanning-report.json
4343
```
4444

45+
### PR scan diffed against the merge base
46+
47+
By default, PR scans are diffed against the repository's latest head scan. To diff against
48+
the exact commit your PR branched from instead, pass the merge base as the baseline:
49+
50+
```bash
51+
BASE_SHA=$(git merge-base origin/main HEAD)
52+
socketcli --pr-number 123 --base-commit-sha "$BASE_SHA"
53+
```
54+
55+
> **Requirement:** `--base-commit-sha` only works if Socket already has a full scan for that
56+
> exact commit. In practice this means your CI must run `socketcli` on **every commit that
57+
> lands on your default branch** — not just some of them. If merges can land without a scan
58+
> (skipped/canceled builds, `[skip ci]`, path-filtered pipelines), the PR scan will fail with
59+
> exit code 3 rather than silently diff against the wrong baseline. See
60+
> [`docs/cli-reference.md`](https://github.com/SocketDev/socket-python-cli/blob/main/docs/cli-reference.md)
61+
> for the full requirements and a backfill pattern that makes PR jobs self-sufficient.
62+
63+
A specific full scan ID also works: `--base-scan-id <id>`.
64+
4565
## SARIF use cases
4666

4767
### Full-scope reachable SARIF (grouped alerts)
@@ -204,8 +224,10 @@ Minimal pattern:
204224
| `3` | Infrastructure or API error (timeout, network failure, unexpected error) |
205225

206226
`--exit-code-on-api-error <N>` remaps the infrastructure-error code (`3`) to any
207-
value — e.g. a Buildkite `soft_fail` code, or `0` to swallow infra errors. Exit
208-
`3` is a Socket convention, not an industry standard.
227+
value — e.g. a Buildkite
228+
[`soft_fail`](https://buildkite.com/docs/pipelines/configure/step-types/command-step)
229+
code, or `0` to swallow infra errors. Exit `3` is a Socket convention, not an
230+
industry standard.
209231

210232
### How these options interact
211233

docs/ci-cd.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,54 @@ steps:
8181
SOCKET_SECURITY_API_TOKEN: "${SOCKET_SECURITY_API_TOKEN}"
8282
```
8383
84+
#### Merge-base baselines in Buildkite (dynamic pipelines)
85+
86+
Notes for using `--base-commit-sha` (see the
87+
[merge-base note in the CLI reference](cli-reference.md#pull-request-and-commit))
88+
when your steps are emitted by a
89+
[dynamic pipeline](https://buildkite.com/docs/pipelines/configure/dynamic-pipelines)
90+
generator rather than a static YAML file:
91+
92+
- **Compute the merge base at generation time, not step time.** The generator runs
93+
with a full checkout; step agents may have shallow or fresh clones where
94+
`git merge-base` fails or needs an extra fetch. Resolve it once in the generator and
95+
bake it into the emitted step's `env`. Diff against the PR's *target* branch, which
96+
isn't always the default branch (see Buildkite's
97+
[environment variables](https://buildkite.com/docs/pipelines/configure/environment-variables)):
98+
99+
```shell
100+
TARGET="${BUILDKITE_PULL_REQUEST_BASE_BRANCH:-$BUILDKITE_PIPELINE_DEFAULT_BRANCH}"
101+
BASE_SHA=$(git merge-base "origin/${TARGET}" HEAD)
102+
```
103+
104+
- **Emit the backfill step conditionally from the generator.** The generator is the
105+
natural place for the "does a baseline scan exist?" check
106+
(`GET /orgs/{org}/full-scans?repo=<repo>&commit_hash=$BASE_SHA&per_page=1`): only
107+
emit the baseline-scan step when it returns nothing. The emitted pipeline then shows
108+
in the UI whether a backfill will run.
109+
110+
- **Keep the backfill inside one command step.** The checkout-base → scan →
111+
checkout-PR sequence must not be split across steps — steps can land on different
112+
agents with different checkouts. Prefer
113+
[`git worktree`](https://git-scm.com/docs/git-worktree) over mutating the step's
114+
checkout: `git worktree add /tmp/socket-base "$BASE_SHA"` then
115+
`socketcli --target-path /tmp/socket-base --branch "$TARGET" --disable-blocking`.
116+
117+
- **Soft-fail infra errors, not findings.** A missing baseline (or any API error)
118+
exits with code 3 (`--exit-code-on-api-error` to change it); real findings exit 1.
119+
[`soft_fail: [{exit_status: 3}]`](https://buildkite.com/docs/pipelines/configure/step-types/command-step)
120+
on the PR scan step keeps infra errors from blocking merges while security findings
121+
still do.
122+
123+
- **["Cancel intermediate builds"](https://buildkite.com/docs/pipelines/configure/canceling-builds#cancel-running-intermediate-builds)
124+
on the default branch is the main source of baseline gaps.** Canceled builds never
125+
scan their commit, so merge-base lookups for PRs based on those commits fail. The
126+
conditional backfill step above is the remedy; there is no per-step exemption from
127+
build cancellation in Buildkite. If you need strict scan-once semantics for
128+
concurrent backfills of the same merge base, serialize the backfill step with a
129+
[concurrency group](https://buildkite.com/docs/pipelines/configure/workflows/controlling-concurrency)
130+
keyed on the merge-base SHA.
131+
84132
### GitLab CI
85133

86134
```yaml

docs/cli-reference.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ This will simultaneously generate:
146146
socketcli [-h] [--api-token API_TOKEN] [--repo REPO] [--workspace WORKSPACE] [--repo-is-public] [--branch BRANCH] [--integration {api,github,gitlab,azure,bitbucket}]
147147
[--config <path>]
148148
[--owner OWNER] [--pr-number PR_NUMBER] [--commit-message COMMIT_MESSAGE] [--commit-sha COMMIT_SHA] [--committers [COMMITTERS ...]]
149+
[--base-scan-id BASE_SCAN_ID | --base-commit-sha BASE_COMMIT_SHA]
149150
[--target-path TARGET_PATH] [--sbom-file SBOM_FILE] [--license-file-name LICENSE_FILE_NAME] [--save-submitted-files-list SAVE_SUBMITTED_FILES_LIST]
150151
[--save-manifest-tar SAVE_MANIFEST_TAR] [--files FILES] [--sub-path SUB_PATH] [--workspace-name WORKSPACE_NAME]
151152
[--excluded-ecosystems EXCLUDED_ECOSYSTEMS] [--exclude-paths EXCLUDE_PATHS] [--include-dirs INCLUDE_DIRS] [--default-branch] [--pending-head] [--generate-license] [--enable-debug]
@@ -191,6 +192,39 @@ If you don't want to provide the Socket API Token every time then you can use th
191192
| `--pr-number` | False | "0" | Pull request number |
192193
| `--commit-message` | False | *auto* | Commit message (auto-detected from git) |
193194
| `--commit-sha` | False | *auto* | Commit SHA (auto-detected from git) |
195+
| `--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` |
196+
| `--base-commit-sha`| False | | Commit SHA to diff against, overriding the repository's head scan as the baseline. The most recent full scan for that commit is used; the CLI errors (exit code 3, or `--exit-code-on-api-error`) if no scan exists for it. Mutually exclusive with `--base-scan-id` |
197+
198+
> **Diffing against the merge base** — by default, PR scans are diffed against the repository's *latest* head scan, which may include newer default-branch commits than your PR branched from. To diff against the exact commit your PR is based on, compute the merge base and pass it as the baseline:
199+
>
200+
> ```shell
201+
> BASE_SHA=$(git merge-base origin/main HEAD)
202+
> socketcli --pr-number 123 --base-commit-sha "$BASE_SHA"
203+
> ```
204+
>
205+
> **Requirement: a full scan must already exist for the merge-base commit.** `--base-commit-sha` does not create a scan of that commit; it looks up an existing one. That lookup only succeeds if your CI runs `socketcli` on **every commit that lands on your default branch** — every merge and direct push, not just periodic or latest-only scans. Common ways commits slip through without a scan:
206+
>
207+
> - CI settings that cancel or skip intermediate builds when newer commits land (e.g. Buildkite's ["cancel intermediate builds"](https://buildkite.com/docs/pipelines/configure/canceling-builds#cancel-running-intermediate-builds))
208+
> - `[skip ci]` commits, path-filtered pipelines, or failed/canceled scan steps
209+
> - merge-base commits that predate your Socket rollout
210+
>
211+
> If no scan exists for the commit, 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 head scan — a wrong baseline would misreport which alerts the PR introduces. Don't adopt this flag without default-branch scan coverage in place; you'll fail PR builds on lookup misses.
212+
>
213+
> **Backfill pattern** — if your default-branch coverage has gaps, the PR job can create the missing baseline itself before scanning:
214+
>
215+
> ```shell
216+
> BASE_SHA=$(git merge-base origin/main HEAD)
217+
> # Create the baseline only if Socket doesn't have one for this commit yet
218+
> # (check: GET /orgs/{org}/full-scans?repo=<repo>&commit_hash=$BASE_SHA&per_page=1)
219+
> git checkout "$BASE_SHA"
220+
> socketcli --branch main --disable-blocking
221+
> git checkout -
222+
> socketcli --pr-number 123 --base-commit-sha "$BASE_SHA"
223+
> ```
224+
>
225+
> Run the baseline step with `--disable-blocking` (findings on the default branch must not fail the PR job) and an explicit `--branch`, since branch auto-detection is unreliable at a detached HEAD.
226+
>
227+
> Buildkite users with dynamically generated pipelines: see [Merge-base baselines in Buildkite](ci-cd.md#merge-base-baselines-in-buildkite-dynamic-pipelines) for generation-time vs. step-time guidance.
194228
195229
#### Path and File
196230
| Parameter | Required | Default | Description |

0 commit comments

Comments
 (0)