Skip to content

Commit 7dca26c

Browse files
committed
chore: adding disable ignore flag
1 parent 064fb7d commit 7dca26c

File tree

8 files changed

+176
-14
lines changed

8 files changed

+176
-14
lines changed

docs/cli-reference.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ socketcli [-h] [--api-token API_TOKEN] [--repo REPO] [--workspace WORKSPACE] [--
151151
[--excluded-ecosystems EXCLUDED_ECOSYSTEMS] [--default-branch] [--pending-head] [--generate-license] [--enable-debug]
152152
[--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>]
153153
[--disable-overview] [--exclude-license-details] [--allow-unverified] [--disable-security-issue]
154-
[--ignore-commit-files] [--disable-blocking] [--enable-diff] [--scm SCM] [--timeout TIMEOUT] [--include-module-folders]
154+
[--ignore-commit-files] [--disable-blocking] [--disable-ignore] [--enable-diff] [--scm SCM] [--timeout TIMEOUT] [--include-module-folders]
155155
[--reach] [--reach-version REACH_VERSION] [--reach-timeout REACH_ANALYSIS_TIMEOUT]
156156
[--reach-memory-limit REACH_ANALYSIS_MEMORY_LIMIT] [--reach-ecosystems REACH_ECOSYSTEMS] [--reach-exclude-paths REACH_EXCLUDE_PATHS]
157157
[--reach-min-severity {low,medium,high,critical}] [--reach-skip-cache] [--reach-disable-analytics] [--reach-output-file REACH_OUTPUT_FILE]
@@ -306,6 +306,7 @@ The CLI will automatically install `@coana-tech/cli` if not present. Use `--reac
306306
|:-------------------------|:---------|:--------|:----------------------------------------------------------------------|
307307
| `--ignore-commit-files` | False | False | Ignore commit files |
308308
| `--disable-blocking` | False | False | Disable blocking mode |
309+
| `--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. |
309310
| `--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. |
310311
| `--enable-diff` | False | False | Enable diff mode even when using `--integration api` (forces diff mode without SCM integration) |
311312
| `--scm` | False | api | Source control management type |

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.2.80"
9+
version = "2.2.81"
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,3 +1,3 @@
11
__author__ = 'socket.dev'
2-
__version__ = '2.2.80'
2+
__version__ = '2.2.81'
33
USER_AGENT = f'SocketPythonCLI/{__version__}'

socketsecurity/config.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ class CliConfig:
9191
files: str = None
9292
ignore_commit_files: bool = False
9393
disable_blocking: bool = False
94+
disable_ignore: bool = False
9495
strict_blocking: bool = False
9596
integration_type: IntegrationType = "api"
9697
integration_org_slug: Optional[str] = None
@@ -201,6 +202,7 @@ def from_args(cls, args_list: Optional[List[str]] = None) -> 'CliConfig':
201202
'files': args.files,
202203
'ignore_commit_files': args.ignore_commit_files,
203204
'disable_blocking': args.disable_blocking,
205+
'disable_ignore': args.disable_ignore,
204206
'strict_blocking': args.strict_blocking,
205207
'integration_type': args.integration,
206208
'pending_head': args.pending_head,
@@ -693,6 +695,19 @@ def create_argument_parser() -> argparse.ArgumentParser:
693695
action="store_true",
694696
help=argparse.SUPPRESS
695697
)
698+
advanced_group.add_argument(
699+
"--disable-ignore",
700+
dest="disable_ignore",
701+
action="store_true",
702+
help="Disable support for @SocketSecurity ignore commands in PR comments. "
703+
"Alerts cannot be suppressed via comments when this flag is set."
704+
)
705+
advanced_group.add_argument(
706+
"--disable_ignore",
707+
dest="disable_ignore",
708+
action="store_true",
709+
help=argparse.SUPPRESS
710+
)
696711
advanced_group.add_argument(
697712
"--strict-blocking",
698713
dest="strict_blocking",

socketsecurity/core/messages.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,8 @@ def security_comment_template(diff: Diff, config=None) -> str:
816816
<tbody>
817817
"""
818818

819+
show_ignore = not (config and getattr(config, 'disable_ignore', False))
820+
819821
# Loop through security alerts (non-license), dynamically generating rows
820822
for alert in security_alerts:
821823
severity_icon = Messages.get_severity_icon(alert.severity)
@@ -842,10 +844,10 @@ def security_comment_template(diff: Diff, config=None) -> str:
842844
<a href="https://socket.dev/alerts/malware">What is known malware?</a></p>
843845
<blockquote>
844846
<p><em>Suggestion:</em> {alert.suggestion}</p>
845-
<p><em>Mark as acceptable risk:</em> To ignore this alert only in this pull request, reply with:<br/>
847+
{f"""<p><em>Mark as acceptable risk:</em> To ignore this alert only in this pull request, reply with:<br/>
846848
<code>@SocketSecurity ignore {alert.pkg_name}@{alert.pkg_version}</code><br/>
847849
Or ignore all future alerts with:<br/>
848-
<code>@SocketSecurity ignore-all</code></p>
850+
<code>@SocketSecurity ignore-all</code></p>""" if show_ignore else ""}
849851
</blockquote>
850852
</details>
851853
</td>
@@ -890,7 +892,7 @@ def security_comment_template(diff: Diff, config=None) -> str:
890892
<blockquote>
891893
<p><em>Next steps:</em> Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at <strong>support@socket.dev</strong>.</p>
892894
<p><em>Suggestion:</em> Find a package that does not violate your license policy or adjust your policy to allow this package's license.</p>
893-
<p><em>Mark the package as acceptable risk:</em> To ignore this alert only in this pull request, reply with the comment <code>@SocketSecurity ignore {first_alert.pkg_name}@{first_alert.pkg_version}</code>. You can also ignore all packages with <code>@SocketSecurity ignore-all</code>. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.</p>
895+
{f'<p><em>Mark the package as acceptable risk:</em> To ignore this alert only in this pull request, reply with the comment <code>@SocketSecurity ignore {first_alert.pkg_name}@{first_alert.pkg_version}</code>. You can also ignore all packages with <code>@SocketSecurity ignore-all</code>. To ignore an alert for all future pull requests, use Socket\'s Dashboard to change the triage state of this alert.</p>' if show_ignore else ""}
894896
</blockquote>
895897
</details>
896898
</td>

socketsecurity/socketcli.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -486,21 +486,27 @@ def main_code():
486486
# 3. Updates the comment to remove ignored alerts
487487
# This is completely separate from the main scanning functionality
488488
log.info("Comment initiated flow")
489-
490-
comments = scm.get_comments_for_pr()
491-
log.debug("Removing comment alerts")
492-
scm.remove_comment_alerts(comments)
489+
490+
if not config.disable_ignore:
491+
comments = scm.get_comments_for_pr()
492+
log.debug("Removing comment alerts")
493+
scm.remove_comment_alerts(comments)
494+
else:
495+
log.info("Ignore commands disabled (--disable-ignore), skipping comment processing")
493496

494497
elif scm is not None and scm.check_event_type() != "comment" and not force_api_mode:
495498
log.info("Push initiated flow")
496499
if scm.check_event_type() == "diff":
497500
log.info("Starting comment logic for PR/MR event")
498501
diff = core.create_new_diff(scan_paths, params, no_change=should_skip_scan, save_files_list_path=config.save_submitted_files_list, save_manifest_tar_path=config.save_manifest_tar, base_paths=base_paths, explicit_files=sbom_files_to_submit)
499502
comments = scm.get_comments_for_pr()
500-
log.debug("Removing comment alerts")
501-
503+
502504
# FIXME: this overwrites diff.new_alerts, which was previously populated by Core.create_issue_alerts
503-
diff.new_alerts = Comments.remove_alerts(comments, diff.new_alerts)
505+
if not config.disable_ignore:
506+
log.debug("Removing comment alerts")
507+
diff.new_alerts = Comments.remove_alerts(comments, diff.new_alerts)
508+
else:
509+
log.info("Ignore commands disabled (--disable-ignore), all alerts will be reported")
504510
log.debug("Creating Dependency Overview Comment")
505511

506512
overview_comment = Messages.dependency_overview_template(diff)

tests/unit/test_disable_ignore.py

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
"""Tests for the --disable-ignore flag."""
2+
3+
import pytest
4+
from dataclasses import dataclass
5+
6+
from socketsecurity.config import CliConfig
7+
from socketsecurity.core.classes import Comment, Diff, Issue
8+
from socketsecurity.core.messages import Messages
9+
from socketsecurity.core.scm_comments import Comments
10+
11+
12+
# --- CLI flag parsing tests ---
13+
14+
class TestDisableIgnoreFlag:
15+
def test_flag_defaults_to_false(self):
16+
config = CliConfig.from_args(["--api-token", "test"])
17+
assert config.disable_ignore is False
18+
19+
def test_flag_parsed_with_dashes(self):
20+
config = CliConfig.from_args(["--api-token", "test", "--disable-ignore"])
21+
assert config.disable_ignore is True
22+
23+
def test_flag_parsed_with_underscores(self):
24+
config = CliConfig.from_args(["--api-token", "test", "--disable_ignore"])
25+
assert config.disable_ignore is True
26+
27+
def test_flag_independent_of_disable_blocking(self):
28+
config = CliConfig.from_args([
29+
"--api-token", "test",
30+
"--disable-ignore",
31+
"--disable-blocking",
32+
])
33+
assert config.disable_ignore is True
34+
assert config.disable_blocking is True
35+
36+
37+
# --- Alert suppression tests ---
38+
39+
def _make_alert(**overrides) -> Issue:
40+
defaults = dict(
41+
pkg_name="lodash",
42+
pkg_version="4.17.21",
43+
pkg_type="npm",
44+
severity="high",
45+
title="Known Malware",
46+
description="Test description",
47+
type="malware",
48+
url="https://socket.dev/test",
49+
manifests="package.json",
50+
props={},
51+
key="test-key",
52+
purl="pkg:npm/lodash@4.17.21",
53+
error=True,
54+
warn=False,
55+
ignore=False,
56+
monitor=False,
57+
suggestion="Remove this package",
58+
next_step_title="Next steps",
59+
emoji="🚨",
60+
)
61+
defaults.update(overrides)
62+
return Issue(**defaults)
63+
64+
65+
def _make_comment(body: str, comment_id: int = 1) -> Comment:
66+
return Comment(
67+
id=comment_id,
68+
body=body,
69+
body_list=body.split("\n"),
70+
reactions={"+1": 0},
71+
user={"login": "test-user", "id": 123},
72+
)
73+
74+
75+
class TestRemoveAlertsRespectedByFlag:
76+
"""Verify that Comments.remove_alerts behaves correctly so the
77+
disable_ignore conditional in socketcli.py has the right effect."""
78+
79+
def test_remove_alerts_suppresses_matching_alert(self):
80+
"""Without --disable-ignore, matching alerts are removed."""
81+
alert = _make_alert()
82+
ignore_comment = _make_comment("SocketSecurity ignore npm/lodash@4.17.21")
83+
comments = Comments.check_for_socket_comments({ignore_comment.id: ignore_comment})
84+
result = Comments.remove_alerts(comments, [alert])
85+
assert len(result) == 0
86+
87+
def test_alerts_preserved_when_no_ignore_comments(self):
88+
"""With --disable-ignore the caller skips remove_alerts entirely,
89+
which is equivalent to passing empty comments."""
90+
alert = _make_alert()
91+
result = Comments.remove_alerts({}, [alert])
92+
assert len(result) == 1
93+
assert result[0].pkg_name == "lodash"
94+
95+
def test_ignore_all_suppresses_all_alerts(self):
96+
alert1 = _make_alert()
97+
alert2 = _make_alert(pkg_name="express", pkg_version="4.18.2",
98+
purl="pkg:npm/express@4.18.2")
99+
ignore_comment = _make_comment("SocketSecurity ignore-all")
100+
comments = Comments.check_for_socket_comments({ignore_comment.id: ignore_comment})
101+
result = Comments.remove_alerts(comments, [alert1, alert2])
102+
assert len(result) == 0
103+
104+
105+
# --- Comment output tests ---
106+
107+
@dataclass
108+
class _FakeConfig:
109+
disable_ignore: bool = False
110+
scm: str = "github"
111+
112+
113+
class TestSecurityCommentIgnoreInstructions:
114+
def _make_diff_with_alert(self) -> Diff:
115+
diff = Diff()
116+
diff.id = "test-scan-id"
117+
diff.diff_url = "https://socket.dev/test"
118+
diff.new_alerts = [_make_alert()]
119+
return diff
120+
121+
def test_ignore_instructions_shown_by_default(self):
122+
diff = self._make_diff_with_alert()
123+
config = _FakeConfig(disable_ignore=False)
124+
comment = Messages.security_comment_template(diff, config)
125+
assert "@SocketSecurity ignore" in comment
126+
assert "Mark as acceptable risk" in comment
127+
128+
def test_ignore_instructions_hidden_when_disabled(self):
129+
diff = self._make_diff_with_alert()
130+
config = _FakeConfig(disable_ignore=True)
131+
comment = Messages.security_comment_template(diff, config)
132+
assert "@SocketSecurity ignore" not in comment
133+
assert "Mark as acceptable risk" not in comment
134+
135+
def test_ignore_instructions_shown_when_config_is_none(self):
136+
diff = self._make_diff_with_alert()
137+
comment = Messages.security_comment_template(diff, config=None)
138+
assert "@SocketSecurity ignore" in comment

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)