Skip to content

Improve documentation for requisite API token permissions - #353

Open
lelia wants to merge 9 commits into
mainfrom
lelia/api-scope-docs-audit
Open

lelia wants to merge 9 commits into
mainfrom
lelia/api-scope-docs-audit

Conversation

@lelia

@lelia lelia commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

Why

Before this PR, the repo said one thing about token permissions: a troubleshooting note on the diff-scans comparison. That note described the APIAccessDenied fallback as PR/MR-only, when it applies to every run that compares scans. It also told readers to grant full-scans:list, which the fallback path already proves the token has. It never listed the baseline set of scopes, so a token couldn't be provisioned from the docs.

The setup guide's scope list doesn't match this CLI

The CI/CD token setup guide lists nine scopes. It leaves out diff-scans:create and diff-scans:list. Every diff-producing run calls the diff-scans endpoints first, so a token set up exactly as the guide says gets APIAccessDenied there and falls back to the streaming comparison. The only sign is a warning in the log. Following the documented setup is enough to cause this, so every CLI user who did that is affected.

The converse also holds. socketcli never uses four of the guide's scopes: repo:update, security-policy:read, triage:alerts-list and triage:alerts-update. That includes repo:update: POST full-scans checks only full-scans:create, even when it sets the repository head.

This PR documents the gap for CLI users. SocketDev/docs#195 fixes the guide itself.

What changed

docs/troubleshooting.md carries the substance:

  • The least-privilege scope set, and what each scope is used for.
  • Each API call by run type (every run, diff-producing runs, per flag), with the scope that endpoint checks.
  • The APIAccessDenied fallback, which runs compare, and how to tell which scope is missing.
  • Three results that look like failures but aren't: the temporary empty baseline on a first scan, reachability scan IDs, and exit 2 when the token can't create the repository.

Supporting changes:

  • Permissions pointers in README.md, docs/cli-reference.md and docs/ci-cd.md.
  • All four accepted token environment variables, in priority order.
  • The GitLab requirements section named $SOCKET_API_TOKEN. It now says SOCKET_SECURITY_API_TOKEN.

How the mapping was verified

Each endpoint-to-scope mapping is the scope the API itself checks. For public endpoints that's the security block in the API reference. For the three hidden ones (upload-manifest-files, tier1-reachability-scan/finalize, and the telemetry post), it's each route's requiredScopes. The draft of this PR inferred mappings from scope names, and checking them against the API changed three of them:

  • repo:update: unused (see above).
  • --sbom-file makes no API call. The CycloneDX export it was mapped to has no caller, and the license-metadata and full-scan metadata reads are reached only from tests.
  • GET organizations, GET report/supported and the ignore-comment telemetry post check no scope at all, which resolves the draft's open question.

The call surface was re-audited against 2.12.0 after rebasing: SDK calls, the sys.exit(2) sites, the diff/full-scan flow decision, the empty-baseline path, and the log strings the docs quote.

Notes for the reviewer

  • README.md's exit code table now notes that exit 2 also covers repository lookup and creation failures, and that neither exit-code flag remaps it. That behavior is a bug, tracked separately. This PR only documents it.
  • This bumps to 2.12.1 even though it's docs-only, because check_version is a required, unfiltered check that wants a version ahead of PyPI. If another PR claims 2.12.1 first, this one rides it.

Related PRs

The same scope audit for the other two Python repos, and the docs-site fix. Each links to this PR's troubleshooting section, so merge this one first.

Fixes: CE-461
Refs: CE-384, CE-460, CE-481

@lelia lelia changed the title Document the API token permissions a run actually needs Improve documentation for requisite API token permissions Sep 11, 2026
@lelia

lelia commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

@lelia
lelia force-pushed the lelia/api-scope-docs-audit branch from 72c2f29 to 69f8871 Compare September 23, 2026 21:51
@lelia
lelia temporarily deployed to socket-firewall September 23, 2026 21:53 — with GitHub Actions Inactive
lelia and others added 6 commits November 13, 2026 20:47
The only scope guidance in the repo covered the diff-scans comparison path,
described it as PR/MR-only, and listed `full-scans:list` alongside the two
`diff-scans:*` scopes. The comparison also runs on plain pushes, and the
streaming fallback is itself a full-scans read, so a reader hitting the
`APIAccessDenied` warning was pointed at the wrong permission and told the
condition did not apply to them.

Replace it with the full picture: what every run calls, what diff-producing
runs add, and what each flag adds. Scope names are only published for the
diff-scans path, so the rest are described by endpoint rather than guessed at.

Also document three outcomes that look like failures and are not: the
temporary empty baseline on a first scan, the reachability scan ID being a
`tier1ReachabilityScanId` rather than a full scan ID, and a repository
permission gap exiting 2 — a code the exit table documents as a keyboard
interrupt, and which bypasses `--disable-blocking` and
`--exit-code-on-api-error`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The permission tables described endpoints but deferred on scope names, since
nothing in this repo or the SDK publishes them. The public CI/CD token setup
guide does: nine scopes, which the docs now name and map to the calls they
cover.

That guide omits `diff-scans:create` and `diff-scans:list`. Every
diff-producing run tries the diff-scans endpoints first, so a token
provisioned exactly as documented always fails that call and falls back to the
legacy streaming comparison, with a warning as the only signal. Anyone
following the documented setup hits this.

The converse is also worth stating: `socketcli` makes no triage or
security-policy calls, so three of the nine scopes the guide lists are not
exercised by this CLI.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
now sends only a "diff" event type to create_new_diff and everything else,
default-branch pushes included, to create_full_scan_with_report_url.

The permission docs asserted the opposite -- that plain pushes also reach the
diff-scans path -- which was true when they were written against 2.8.1 and is
not true now. Replace the claim with a table of which runs compare, and keep
the old behavior as a note, since the warning still shows up in logs from
pre-2.9.0 runs with no pull request in sight.

Re-verified the rest against 2.9.7: SDK call surface, the four sys.exit(2)
sites, the temporary empty baseline, and the reachability scan ID are all
unchanged.
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.
@lelia
lelia force-pushed the lelia/api-scope-docs-audit branch from c7b9938 to a1c1ae4 Compare November 14, 2026 01:53
@lelia
lelia deployed to socket-firewall November 14, 2026 01:53 — with GitHub Actions Active
@lelia
lelia marked this pull request as ready for review November 14, 2026 02:39
@lelia
lelia requested a review from a team as a code owner November 14, 2026 02:39
@lelia
lelia deployed to socket-firewall November 14, 2026 02:39 — with GitHub Actions Active
@lelia

lelia commented Nov 14, 2026

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor

cursor Bot commented Nov 14, 2026 •

Copy link
Copy Markdown

PR Summary

Low Risk
Docs and version bump only; no runtime behavior changes beyond publishing 2.12.1 metadata.

Overview
This release (2.12.1) is documentation-only: it expands how operators should provision Socket API tokens for socketcli and links that guidance across the repo.

The main addition is docs/troubleshooting.md#api-token-permissions, which documents the least-privilege scope set, maps API calls to scopes by run type and flags, calls out that the external CI/CD token guide omits diff-scans:create and diff-scans:list, and explains silent fallbacks (APIAccessDenied on comparisons) versus hard failures (exit 2 when the token cannot look up or create a repository). It also clarifies confusing outcomes: temporary empty baselines, reachability scan IDs vs full-scan IDs.

README.md, docs/cli-reference.md, and docs/ci-cd.md now point at that guide, document the four accepted token environment variables in priority order, and update the exit-code table so 2 covers repository lookup/creation failures and is not remapped by --disable-blocking or --exit-code-on-api-error.

Reviewed by Cursor Bugbot for commit 5fc3b67. Configure here.

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread CHANGELOG.md Resolved
@lelia
lelia deployed to socket-firewall November 14, 2026 03:31 — with GitHub Actions Active
Only a diff-producing run that takes its baseline from the repository's
head scan looks the repository up, and so only that run can create it
or exit 2. A full-scan run uploads straight to full-scans, which creates
a missing repository for an organization-wide token. A failed streaming
fallback also only points at full-scans:list when it fails with
Insufficient permissions.
@lelia
lelia deployed to socket-firewall November 14, 2026 03:43 — with GitHub Actions Active
A failed GET report/supported raises from the SDK and stops the run; the
bundled pattern list only covers a non-error response with no body. An
empty baseline is created when the repository has no head scan, not on
every new branch, since a branch compares against the repository's head
scan.
@lelia
lelia deployed to socket-firewall November 14, 2026 03:52 — with GitHub Actions Active
@lelia

lelia commented Nov 14, 2026

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 5fc3b67. Configure here.

This branch was successfully deployed

1 active deployment
socket-firewall — 5fc3b67f Deployed Nov 14, 2026 by lelia via python-sfw-smoke-enterprise #603
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant