Skip to content

Commit 8c5d3e9

Browse files
committed
Reject owner/repo in --repo and deprecate --pending-head
--repo was documented as owner/repo, but the value is sent as the repository slug, which the API validates against [a-zA-Z0-9._-]+. Following the help text failed every scan, at repository creation or full-scan creation. Describe the slug in the help text and docs, and exit 1 up front when --repo contains "/", naming the slug to use. --pending-head was parsed and never read: set_as_pending_head follows is_default_branch. Keep accepting it so existing pipelines still parse, but hide it from --help and log a deprecation warning pointing at --default-branch. Also fix the docs examples that taught owner/repo: the GitLab CI example ($CI_PROJECT_PATH -> $CI_PROJECT_NAME) and the Slack repos filter, which is matched against the bare slug. Bump to 2.11.12.
1 parent 911331c commit 8c5d3e9

8 files changed

Lines changed: 89 additions & 23 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,24 @@
11
# Changelog
22

3+
## 2.11.12
4+
5+
### Fixed: `--repo` takes a repository slug, not `owner/repo`
6+
7+
- The help text and docs said `--repo` takes `owner/repo`, but the API only
8+
accepts a repository slug, which can't contain `/`. Following the docs made
9+
every scan fail. The help text and docs now describe the slug, and the CLI
10+
exits `1` up front with the slug to use when `--repo` contains `/`. Use
11+
`--workspace` for the owner.
12+
- The GitLab CI example now passes `$CI_PROJECT_NAME` instead of
13+
`$CI_PROJECT_PATH`, and the Slack `repos` filter example uses slugs.
14+
15+
### Deprecated: `--pending-head`
16+
17+
- `--pending-head` never had any effect: a scan on the default branch becomes
18+
its head scan whether or not the flag is set. It is still accepted so
19+
existing pipelines keep working, but it is hidden from `--help` and logs a
20+
deprecation warning. Use `--default-branch`.
21+
322
## 2.11.11
423

524
### Changed: use lowercase Python CLI User-Agent

‎docs/cli-reference.md‎

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ These are two full-scan uploads, two server-side graphs, and two repository head
154154
**Generate GitLab Security Dashboard report:**
155155
```bash
156156
socketcli --enable-gitlab-security \
157-
--repo owner/repo \
157+
--repo my-repo \
158158
--target-path .
159159
```
160160

@@ -167,7 +167,7 @@ This will:
167167
**Save SARIF report to file (e.g. for GitHub Code Scanning, SonarQube, or VS Code):**
168168
```bash
169169
socketcli --sarif-file results.sarif \
170-
--repo owner/repo \
170+
--repo my-repo \
171171
--target-path .
172172
```
173173

@@ -176,7 +176,7 @@ socketcli --sarif-file results.sarif \
176176
socketcli --enable-json \
177177
--sarif-file results.sarif \
178178
--enable-gitlab-security \
179-
--repo owner/repo
179+
--repo my-repo
180180
```
181181

182182
This will simultaneously generate:
@@ -212,7 +212,7 @@ socketcli [-h] [--api-token API_TOKEN] [--repo REPO] [--workspace WORKSPACE] [--
212212
[--base-scan-id BASE_SCAN_ID | --base-commit-sha BASE_COMMIT_SHA]
213213
[--target-path TARGET_PATH] [--sbom-file SBOM_FILE] [--license-file-name LICENSE_FILE_NAME] [--save-submitted-files-list SAVE_SUBMITTED_FILES_LIST]
214214
[--save-manifest-tar SAVE_MANIFEST_TAR] [--files FILES] [--sub-path SUB_PATH] [--workspace-name WORKSPACE_NAME]
215-
[--excluded-ecosystems EXCLUDED_ECOSYSTEMS] [--exclude-paths EXCLUDE_PATHS] [--include-dirs INCLUDE_DIRS] [--default-branch] [--pending-head] [--generate-license] [--enable-debug]
215+
[--excluded-ecosystems EXCLUDED_ECOSYSTEMS] [--exclude-paths EXCLUDE_PATHS] [--include-dirs INCLUDE_DIRS] [--default-branch] [--generate-license] [--enable-debug]
216216
[--enable-json] [--enable-sarif] [--sarif-file <path>] [--sarif-scope {diff,full}] [--sarif-grouping {instance,alert}] [--sarif-reachability {all,reachable,potentially,reachable-or-potentially}] [--enable-gitlab-security] [--gitlab-security-file <path>]
217217
[--disable-overview] [--exclude-license-details] [--allow-unverified] [--disable-security-issue]
218218
[--ignore-commit-files] [--disable-blocking] [--disable-ignore] [--enable-diff] [--scm SCM] [--timeout TIMEOUT] [--include-module-folders]
@@ -235,7 +235,7 @@ If you don't want to provide the Socket API Token every time then you can use th
235235
#### Repository
236236
| Parameter | Required | Default | Description |
237237
|:-----------------|:---------|:--------|:------------------------------------------------------------------------------------------------------------------|
238-
| `--repo` | False | *auto* | Repository name in owner/repo format (auto-detected from git remote) |
238+
| `--repo` | False | *auto* | Repository slug in Socket, without the owner: `my-repo`, not `my-org/my-repo`. Auto-detected from the git remote. A value containing `/` is rejected; use `--workspace` for the owner. |
239239
| `--workspace` | False | | The Socket workspace to associate the scan with (e.g. `my-org` in `my-org/my-repo`). See note below. |
240240
| `--repo-is-public` | False | False | If set, flags a new repository creation as public. Defaults to false. |
241241
| `--integration` | False | api | Integration type (api, github, gitlab, azure, bitbucket). When omitted, `--scm github` or `--scm gitlab` implies the matching integration. |
@@ -308,7 +308,6 @@ If you don't want to provide the Socket API Token every time then you can use th
308308
| Parameter | Required | Default | Description |
309309
|:-------------------------|:---------|:--------|:------------------------------------------------------------------------------------------------------|
310310
| `--default-branch` | False | *auto* | Make this branch the default branch (auto-detected from git and CI environment when not specified) |
311-
| `--pending-head` | False | *auto* | If true, the new scan will be set as the branch's head scan (automatically synced with default-branch) |
312311
| `--include-module-folders` | False | False | If enabled, re-includes the JS/TS module folders (`node_modules`, `bower_components`, `jspm_packages`) in manifest discovery. For other excluded directories, use `--include-dirs`. |
313312
314313
#### Output Configuration
@@ -551,7 +550,7 @@ export SOCKET_SLACK_BOT_TOKEN="xoxb-your-bot-token-here"
551550
552551
Webhook mode (`url_configs`):
553552
- `reachability_alerts_only` (boolean, default: false): When `--reach` is enabled, only send reachable vulnerabilities from the selected diff alert set (uses reachability facts when available; otherwise falls back to blocking-status behavior)
554-
- `repos` (array): Only send alerts for specific repositories (e.g., `["owner/repo1", "owner/repo2"]`)
553+
- `repos` (array): Only send alerts for specific repositories, matched against the `--repo` slug without the owner (e.g., `["my-repo1", "my-repo2"]`)
555554
- `alert_types` (array): Only send specific alert types (e.g., `["malware", "typosquat"]`)
556555
- `severities` (array): Only send alerts with specific severities (e.g., `["high", "critical"]`)
557556
@@ -683,7 +682,7 @@ The CLI uses intelligent default branch detection with the following priority:
683682
3. **Git repository analysis**: Compares current branch with repository's default branch
684683
4. **Fallback**: Defaults to `false` if none of the above methods succeed
685684
686-
Both `--default-branch` and `--pending-head` parameters are automatically synchronized to ensure consistent behavior.
685+
A scan on the default branch also becomes that branch's head scan. `--pending-head` is deprecated and has no effect: it is still accepted so existing pipelines keep working, but it logs a warning. Use `--default-branch` instead.
687686
688687
## Who can ignore an alert
689688
@@ -763,7 +762,7 @@ Socket CLI can generate reports compatible with GitLab's Security Dashboard, all
763762
To generate a GitLab-compatible security report:
764763
765764
```bash
766-
socketcli --enable-gitlab-security --repo owner/repo
765+
socketcli --enable-gitlab-security --repo my-repo
767766
```
768767
769768
This creates a `gl-dependency-scanning-report.json` file following GitLab's Dependency Scanning report schema.
@@ -782,7 +781,7 @@ socket_security_scan:
782781
script:
783782
- socketcli
784783
--api-token $SOCKET_API_TOKEN
785-
--repo $CI_PROJECT_PATH
784+
--repo $CI_PROJECT_NAME
786785
--branch $CI_COMMIT_REF_NAME
787786
--commit-sha $CI_COMMIT_SHA
788787
--enable-gitlab-security

‎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.11.11"
9+
version = "2.11.12"
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,4 +1,4 @@
11
__author__ = 'socket.dev'
2-
__version__ = '2.11.11'
2+
__version__ = '2.11.12'
33
USER_AGENT_NAME = 'socket-python-cli'
44
USER_AGENT = f'{USER_AGENT_NAME}/{__version__}'

‎socketsecurity/config.py‎

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,22 @@ def from_args(cls, args_list: Optional[List[str]] = None) -> 'CliConfig':
448448
logging.error("--workspace-name requires --sub-path to be specified")
449449
exit(1)
450450

451+
# The API validates the repo as a slug, which can't contain "/", so an
452+
# owner/repo value would otherwise fail later at repository creation.
453+
if args.repo and "/" in args.repo:
454+
suggested = args.repo.rstrip("/").rsplit("/", 1)[-1]
455+
logging.error(
456+
f"--repo takes the repository slug without its owner, but got '{args.repo}'. "
457+
f"Use --repo {suggested}, and --workspace for the owner if your repositories use one."
458+
)
459+
exit(1)
460+
461+
if args.pending_head:
462+
logging.warning(
463+
"--pending-head is deprecated and has no effect. A scan becomes the head scan "
464+
"when it runs on the default branch; use --default-branch to mark it as such."
465+
)
466+
451467
# argparse only enforces the mutually exclusive group for real CLI args;
452468
# this also catches both values arriving via a --config file.
453469
if args.base_scan_id and args.base_commit_sha:
@@ -527,8 +543,11 @@ def create_argument_parser() -> argparse.ArgumentParser:
527543
repo_group = parser.add_argument_group('Repository')
528544
repo_group.add_argument(
529545
"--repo",
530-
metavar="<owner/repo>",
531-
help="Repository name in owner/repo format",
546+
metavar="<repo>",
547+
help=(
548+
"Repository slug in Socket, without the owner (e.g. my-repo, not my-org/my-repo). "
549+
"Defaults to the git remote's repository name. Use --workspace for the owner."
550+
),
532551
required=False
533552
)
534553
repo_group.add_argument(
@@ -743,11 +762,12 @@ def create_argument_parser() -> argparse.ArgumentParser:
743762
action="store_true",
744763
help=argparse.SUPPRESS
745764
)
765+
# Deprecated no-op, still accepted so existing pipelines don't fail to parse.
746766
config_group.add_argument(
747767
"--pending-head",
748768
dest="pending_head",
749769
action="store_true",
750-
help="If true, the new scan will be set as the branch's head scan"
770+
help=argparse.SUPPRESS
751771
)
752772
config_group.add_argument(
753773
"--ignore-authorization",

‎tests/unit/test_config.py‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,34 @@ def test_config_file_json_sets_defaults(self, tmp_path):
168168
assert config.sarif_reachability == "reachable"
169169

170170

171+
class TestRepoAndPendingHeadFlags:
172+
"""--repo takes a bare slug, and --pending-head is a deprecated no-op"""
173+
174+
@pytest.mark.parametrize("repo", ["my-org/my-repo", "group/sub/my-repo", "my-org/my-repo/"])
175+
def test_repo_with_owner_exits_with_suggestion(self, repo, caplog):
176+
with pytest.raises(SystemExit) as exc_info:
177+
CliConfig.from_args(["--api-token", "test-token", "--repo", repo])
178+
assert exc_info.value.code == 1
179+
assert "Use --repo my-repo" in caplog.text
180+
181+
def test_repo_slug_is_accepted(self):
182+
config = CliConfig.from_args(["--api-token", "test-token", "--repo", "my-repo"])
183+
assert config.repo == "my-repo"
184+
185+
@pytest.mark.parametrize("flag", ["--pending-head", "--pending_head"])
186+
def test_pending_head_is_accepted_with_a_deprecation_warning(self, flag, caplog):
187+
config = CliConfig.from_args(["--api-token", "test-token", flag])
188+
assert config.pending_head is True
189+
assert "--pending-head is deprecated" in caplog.text
190+
191+
def test_help_hides_pending_head_and_shows_repo_slug(self, capsys):
192+
with pytest.raises(SystemExit):
193+
CliConfig.from_args(["--help"])
194+
help_text = capsys.readouterr().out
195+
assert "--pending-head" not in help_text
196+
assert "--repo <repo>" in help_text
197+
198+
171199
class TestBaseScanFlags:
172200
"""Tests for the --base-scan-id / --base-commit-sha diff baseline overrides."""
173201

‎tests/unit/test_fossa_compat.py‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def test_fossa_report_payload_vulnerability_shape_is_stable():
6666
config = CliConfig.from_args([
6767
"--api-token", "test",
6868
"--legal-format", "fossa",
69-
"--repo", "owner/repo",
69+
"--repo", "widgets",
7070
"--branch", "refs/heads/main",
7171
])
7272
diff = Diff(id="scan-123", report_url="https://socket.dev/report/123")
@@ -147,14 +147,14 @@ def test_fossa_report_payload_vulnerability_shape_is_stable():
147147
def test_project_metadata_uses_dollar_revision_separator():
148148
"""The composed FOSSA `project.id` is `<projectLocator>$<revision>`."""
149149
from socketsecurity.fossa_compat import _build_project_metadata
150-
config = CliConfig.from_args(["--api-token", "test", "--legal-format", "fossa", "--repo", "acme/widgets", "--branch", "refs/heads/main"])
150+
config = CliConfig.from_args(["--api-token", "test", "--legal-format", "fossa", "--repo", "widgets", "--branch", "refs/heads/main"])
151151
diff = Diff(id="scan-abc123", report_url="https://socket.dev/x")
152152
project = _build_project_metadata(diff, config)
153153
assert project == {
154154
"branch": "refs/heads/main",
155-
"id": "acme/widgets$scan-abc123",
156-
"project": "acme/widgets",
157-
"projectId": "acme/widgets",
155+
"id": "widgets$scan-abc123",
156+
"project": "widgets",
157+
"projectId": "widgets",
158158
"revision": "scan-abc123",
159159
"url": "https://socket.dev/x",
160160
}
@@ -311,10 +311,10 @@ def test_attribution_payload_top_level_is_5_keys():
311311

312312
def test_attribution_project_has_only_name_and_revision():
313313
"""SBOM `project` is the 2-key subset, not the 6-key analyze project."""
314-
config = CliConfig.from_args(["--api-token", "test", "--legal-format", "fossa", "--repo", "acme/widgets"])
314+
config = CliConfig.from_args(["--api-token", "test", "--legal-format", "fossa", "--repo", "widgets"])
315315
diff = Diff(id="rev-x")
316316
payload = build_fossa_attribution_payload(diff, config)
317-
assert payload["project"] == {"name": "acme/widgets", "revision": "rev-x"}
317+
assert payload["project"] == {"name": "widgets", "revision": "rev-x"}
318318

319319

320320
def test_attribution_empty_diff_yields_empty_collections():

‎uv.lock‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)