Skip to content

Commit db69ae4

Browse files
committed
Map each API call to the scope the API checks
The scope tables were inferred from scope names. The API reference publishes the scope each endpoint checks, so the tables now use those and the open question about unpublished scopes is resolved: GET organizations, GET report/supported and the ignore-comment telemetry post check none. Rechecking the call surface against 2.12.0 also changed the guidance: - repo:update is never exercised. POST full-scans checks only full-scans:create, including when it sets the repository head. - --sbom-file makes no API call; the CycloneDX export it was mapped to has no caller. License-metadata and full-scan metadata reads are likewise unreached outside tests. - diff-scans/from-ids checks full-scans:list as well as diff-scans:create. - --reach's manifest upload and tier-1 finalize check full-scans:create, as do the Coana CLI's reachability calls. - The exit-2 section now quotes the repo:create hint the CLI logs on a 403.
1 parent 6cc80a6 commit db69ae4

2 files changed

Lines changed: 80 additions & 67 deletions

File tree

‎docs/cli-reference.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,9 @@ The token is read from the first of these that is set, then from `--api-token`:
239239
3. `SOCKET_API_KEY`
240240
4. `SOCKET_API_TOKEN`
241241
242-
`SOCKET_SECURITY_API_TOKEN` is the documented name; the others are accepted for
243-
compatibility. Prefer the documented name in new pipelines.
242+
This repository's examples use `SOCKET_SECURITY_API_TOKEN`, and the CI/CD guides on
243+
docs.socket.dev use `SOCKET_SECURITY_API_KEY`. Either works. If both are set,
244+
`SOCKET_SECURITY_API_KEY` wins.
244245

245246
> **Token permissions:** the CLI needs more than scan-creation access, and several
246247
> paths degrade with only a warning when a permission is missing rather than failing.

‎docs/troubleshooting.md‎

Lines changed: 77 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2,82 +2,86 @@
22

33
## API token permissions
44

5-
The CLI authenticates with a single Socket organization API token. Every run needs
6-
more than "create a scan" access, and a token that is missing a permission usually
7-
does **not** fail loudly — several paths degrade or fall back with only a warning.
5+
The CLI authenticates with a single Socket organization API token. A token missing a
6+
permission usually does **not** fail the run. Several paths fall back or skip work and
7+
leave only a warning in the log.
88

9-
### What every run calls
9+
### Scopes to grant
1010

11-
These are exercised on any invocation, regardless of flags:
11+
For a least-privilege CI token, grant these:
1212

13-
| API call | Purpose |
13+
| Scope | Needed for |
1414
|:---|:---|
15-
| `GET organizations` | Resolve the org ID and slug from the token |
16-
| `GET report/supported` | Fetch supported manifest patterns (falls back to a bundled list on failure) |
17-
| `GET orgs/{org}/repos/{repo}` | Look up the repository |
18-
| `POST orgs/{org}/repos` | Create the repository — **only attempted if the lookup above fails** |
19-
| `POST orgs/{org}/full-scans` | Create the new scan |
20-
21-
### What diff-producing runs add
22-
23-
| API call | Purpose |
24-
|:---|:---|
25-
| `POST orgs/{org}/diff-scans/from-ids` | Create the comparison (preferred path) |
26-
| `GET orgs/{org}/diff-scans` | Resolve an existing comparison on a 409 |
27-
| `GET orgs/{org}/diff-scans/{id}?cached=true` | Poll for the computed comparison |
28-
| `GET orgs/{org}/full-scans/diff` | Legacy streaming comparison (fallback path) |
29-
| `GET orgs/{org}/full-scans/{id}` | Resolve a baseline for `--base-scan-id` / `--base-commit-sha` |
30-
31-
### Which scopes to grant
15+
| `repo:list` | Looking up the repository and its head scan, on every run |
16+
| `repo:create` | Creating the repository on its first scan. Without it, a scan of a repository Socket has not seen yet exits `2`; see [below](#a-missing-repository-permission-can-exit-2) |
17+
| `full-scans:create` | Creating the scan, on every run. `--reach` also uploads manifests and finalizes the reachability scan under this scope |
18+
| `full-scans:list` | Every comparison, the `--base-commit-sha` lookup, and fetching scan contents for `--enable-json`, `--enable-sarif`, `--enable-gitlab-security` and `--generate-license` on a full scan |
19+
| `diff-scans:create` | Creating the comparison on a diff-producing run |
20+
| `diff-scans:list` | Polling for the comparison, and finding an existing one |
21+
| `packages:list` | `--generate-license` only |
22+
23+
The scopes each endpoint checks are listed in the
24+
[API reference](https://docs.socket.dev/reference). A few calls check no scope and work
25+
with any valid token for the organization: `GET organizations`, `GET report/supported`,
26+
and the telemetry event posted when someone replies to a Socket comment with an ignore
27+
command.
28+
29+
### The CI/CD setup guide's list is incomplete for this CLI
3230

3331
The [CI/CD token setup guide](https://docs.socket.dev/docs/create-socket-api-key-for-cicd)
34-
tells you to select nine scopes:
32+
lists nine scopes:
3533

3634
`repo:list`, `repo:create`, `repo:update`, `security-policy:read`,
3735
`triage:alerts-list`, `triage:alerts-update`, `full-scans:list`, `full-scans:create`,
3836
`packages:list`
3937

40-
**That list is not sufficient for this CLI.** It does not include `diff-scans:create`
41-
or `diff-scans:list`, which every diff-producing run needs. A token provisioned exactly
42-
as that guide describes will always fall back to the legacy comparison path — see the
43-
next section. Grant those two in addition.
38+
**It does not include `diff-scans:create` or `diff-scans:list`**, and every
39+
diff-producing run needs both. A token set up exactly as that guide describes always
40+
falls back to the older comparison path; see
41+
[the next section](#apiaccessdenied-on-the-scan-comparison). Add the two scopes.
4442

45-
Going the other way, `socketcli` makes no triage or security-policy API calls at all,
46-
so `security-policy:read`, `triage:alerts-list` and `triage:alerts-update` are not
47-
exercised by this CLI. They are on the guide's list for other Socket tooling.
43+
The guide's list also includes four scopes this CLI never uses: `repo:update`,
44+
`security-policy:read`, `triage:alerts-list` and `triage:alerts-update`. Other Socket
45+
tooling uses them, so leave them on a shared token. A token used only by `socketcli`
46+
can drop them.
4847

49-
Mapping the remaining scopes to the calls above (inferred from the names; the setup
50-
guide does not publish a per-endpoint mapping):
48+
### API calls by run type
5149

52-
| Scope | Covers |
53-
|:---|:---|
54-
| `repo:list` | Repository lookup |
55-
| `repo:create` | Repository creation on lookup failure |
56-
| `repo:update` | Setting the scan as repository head / default branch |
57-
| `full-scans:create` | Creating the new scan |
58-
| `full-scans:list` | Reading scans, metadata, streams, and the legacy `full-scans/diff` comparison |
59-
| `diff-scans:create` | Creating the comparison |
60-
| `diff-scans:list` | Resolving and polling the comparison |
61-
| `packages:list` | `POST purl` for license text |
62-
63-
`GET organizations` and `GET report/supported` are not covered by any scope on the
64-
guide's list and appear to be available to any valid org token. If you are provisioning
65-
a least-privilege token and one of these fails, ask Socket support — the scope
66-
identifiers for them are not published.
67-
68-
### What individual flags add
69-
70-
| Flag | Additional API calls |
71-
|:---|:---|
72-
| `--reach` | Manifest upload, `GET organizations` (plan check), full-scan tier-1 finalize |
73-
| `--generate-license` | `POST purl` |
74-
| `--enable-json` / `--enable-sarif` / `--enable-gitlab-security` on a full scan | `GET orgs/{org}/full-scans/{id}` (metadata), full-scan stream, and `POST license-metadata` for every package that carries a license |
75-
| `--sbom-file` | `GET orgs/{org}/export/cdx/{id}` |
50+
Every run:
51+
52+
| API call | Scope | Purpose |
53+
|:---|:---|:---|
54+
| `GET organizations` | none | Resolve the org ID and slug from the token |
55+
| `GET report/supported` | none | Fetch supported manifest patterns. On failure the CLI uses a bundled list that covers fewer ecosystems |
56+
| `GET orgs/{org}/repos/{repo}` | `repo:list` | Look up the repository and its head scan |
57+
| `POST orgs/{org}/repos` | `repo:create` | Create the repository, **only attempted if the lookup above fails** |
58+
| `POST orgs/{org}/full-scans` | `full-scans:create` | Create the new scan, and the temporary empty baseline on a first scan |
59+
60+
Diff-producing runs (see [which runs compare](#apiaccessdenied-on-the-scan-comparison)) add:
61+
62+
| API call | Scope | Purpose |
63+
|:---|:---|:---|
64+
| `POST orgs/{org}/diff-scans/from-ids` | `diff-scans:create` and `full-scans:list` | Create the comparison (preferred path) |
65+
| `GET orgs/{org}/diff-scans` | `diff-scans:list` | Find the existing comparison when creation returns 409 |
66+
| `GET orgs/{org}/diff-scans/{id}` | `diff-scans:list` | Poll for the computed comparison |
67+
| `GET orgs/{org}/full-scans/diff` | `full-scans:list` | Streaming comparison (fallback path) |
68+
69+
Flags add:
70+
71+
| Flag | API calls | Scope |
72+
|:---|:---|:---|
73+
| `--reach` | `GET organizations` (plan check), `POST orgs/{org}/upload-manifest-files`, `POST tier1-reachability-scan/finalize` | none, `full-scans:create`, `full-scans:create` |
74+
| `--base-commit-sha` | `GET orgs/{org}/full-scans` (find the scan for that commit or a scanned ancestor) | `full-scans:list` |
75+
| `--generate-license` | `POST orgs/{org}/purl` | `packages:list` |
76+
| `--enable-json`, `--enable-sarif`, `--enable-gitlab-security` or `--generate-license` on a full scan | `GET orgs/{org}/full-scans/{id}` (scan contents) | `full-scans:list` |
77+
78+
`--reach` also runs the Coana CLI with the same token, and its reachability calls
79+
check `full-scans:create`.
7680

7781
## `APIAccessDenied` on the scan comparison
7882

7983
Any run that produces a diff first tries the diff-scans endpoints. A token without the
80-
`diff-scans:*` permissions logs a warning and silently continues on the older path:
84+
`diff-scans:*` scopes logs a warning and continues on the older path:
8185

8286
```
8387
Diff scan comparison failed with APIAccessDenied(Insufficient permissions), falling back to the streaming scan comparison
@@ -98,10 +102,10 @@ Before 2.9.0 an SCM-integrated branch push also compared, so a pipeline scanning
98102
pushes (`--pr-number 0 --default-branch`) hit this too. If you are diagnosing an older
99103
run, that is why the warning can appear in a log with no pull request in sight.
100104

101-
**Which permission is missing.** The fallback path is `GET orgs/{org}/full-scans/diff`,
102-
a full-scans read. If you see the fallback produce results, your token already has
103-
full-scans read, and the missing grants are the two `diff-scans:*` permissions — not
104-
`full-scans:list`. If the fallback *also* fails, the gap is broader.
105+
**Which scope is missing.** The fallback calls `GET orgs/{org}/full-scans/diff`, which
106+
checks `full-scans:list`. If the fallback produces results, the token already has
107+
`full-scans:list`, so the missing grant is `diff-scans:create`, `diff-scans:list`, or
108+
both. If the fallback also fails, `full-scans:list` is missing too.
105109

106110
**Why the diff-scans path is preferred.** It polls with short, bounded requests rather
107111
than holding one connection open while the backend computes, which is what lets large
@@ -124,9 +128,16 @@ interrupt. That exit also bypasses `--disable-blocking` and `--exit-code-on-api-
124128
so it fails the pipeline even when you have asked for infrastructure errors to be
125129
non-blocking.
126130

127-
If a job dies with exit 2 and `Failed to create repository` or `API failure while
128-
creating repository` in the log, check the token's repository permissions before
129-
looking anywhere else.
131+
This usually happens on the first scan of a repository Socket has not seen, when the
132+
token lacks `repo:create`. A token without `repo:list` can end up here even for
133+
a repository that exists, because its lookup fails and the CLI then tries to create it. The log shows `API failure while creating repository`, and on a
134+
403 adds:
135+
136+
```
137+
A 403 here usually means the API token is missing the repo:create scope.
138+
```
139+
140+
Grant `repo:create`, or create the repository in Socket before the first pipeline run.
130141

131142
## Baseline scans that do not appear in the dashboard
132143

@@ -135,6 +146,7 @@ the CLI creates a **temporary empty baseline** and compares to that:
135146

136147
```
137148
No previous scan found - creating empty baseline scan
149+
Baseline selected: source=empty scan_id="<baseline>"
138150
Comparing scans - Head scan ID: <baseline>, New scan ID: <real scan>
139151
```
140152

0 commit comments

Comments
 (0)