Skip to content

Commit 5adc5c4

Browse files
committed
CM-58022-lint
1 parent bd250a4 commit 5adc5c4

File tree

12 files changed

+58
-81
lines changed

12 files changed

+58
-81
lines changed

cycode/cli/apps/ai_guardrails/command_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def validate_and_parse_ide(ide: str) -> AIIDEType:
3232
f'[red]Error:[/] Invalid IDE "{ide}". Supported IDEs: {valid_ides}',
3333
style='bold red',
3434
)
35-
raise typer.Exit(1)
35+
raise typer.Exit(1) from None
3636

3737

3838
def validate_scope(scope: str, allowed_scopes: tuple[str, ...] = ('user', 'repo')) -> None:

cycode/cli/apps/ai_guardrails/consts.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@
1818

1919
class AIIDEType(str, Enum):
2020
"""Supported AI IDE types."""
21+
2122
CURSOR = 'cursor'
2223

2324

2425
class IDEConfig(NamedTuple):
2526
"""Configuration for an AI IDE."""
27+
2628
name: str
2729
hooks_dir: Path
2830
repo_hooks_subdir: str # Subdirectory in repo for hooks (e.g., '.cursor')
@@ -34,10 +36,10 @@ def _get_cursor_hooks_dir() -> Path:
3436
"""Get Cursor hooks directory based on platform."""
3537
if platform.system() == 'Darwin':
3638
return Path.home() / '.cursor'
37-
elif platform.system() == 'Windows':
39+
if platform.system() == 'Windows':
3840
return Path.home() / 'AppData' / 'Roaming' / 'Cursor'
39-
else: # Linux
40-
return Path.home() / '.config' / 'Cursor'
41+
# Linux
42+
return Path.home() / '.config' / 'Cursor'
4143

4244

4345
# IDE-specific configurations

cycode/cli/apps/ai_guardrails/hooks_manager.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@
1010
from typing import Optional
1111

1212
from cycode.cli.apps.ai_guardrails.consts import (
13-
AIIDEType,
1413
CYCODE_MARKER,
1514
CYCODE_SCAN_PROMPT_COMMAND,
1615
DEFAULT_IDE,
1716
IDE_CONFIGS,
17+
AIIDEType,
1818
get_hooks_config,
1919
)
2020
from cycode.logger import get_logger
@@ -162,9 +162,7 @@ def uninstall_hooks(
162162
return False, f'Failed to update hooks file: {hooks_path}'
163163

164164

165-
def get_hooks_status(
166-
scope: str = 'user', repo_path: Optional[Path] = None, ide: AIIDEType = DEFAULT_IDE
167-
) -> dict:
165+
def get_hooks_status(scope: str = 'user', repo_path: Optional[Path] = None, ide: AIIDEType = DEFAULT_IDE) -> dict:
168166
"""
169167
Get the status of AI guardrails hooks.
170168

cycode/cli/apps/scan/prompt/handlers.py

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,17 @@
77

88
import json
99
import os
10-
from multiprocessing.pool import ThreadPool, TimeoutError as PoolTimeoutError
11-
from typing import Optional
10+
from multiprocessing.pool import ThreadPool
11+
from multiprocessing.pool import TimeoutError as PoolTimeoutError
12+
from typing import Callable, Optional
1213

1314
import typer
1415

1516
from cycode.cli.apps.scan.code_scanner import _get_scan_documents_thread_func
1617
from cycode.cli.apps.scan.prompt.payload import AIHookPayload
1718
from cycode.cli.apps.scan.prompt.policy import get_policy_value
1819
from cycode.cli.apps.scan.prompt.response_builders import get_response_builder
19-
from cycode.cli.apps.scan.prompt.types import AIHookOutcome, AiHookEventType, BlockReason
20+
from cycode.cli.apps.scan.prompt.types import AiHookEventType, AIHookOutcome, BlockReason
2021
from cycode.cli.apps.scan.prompt.utils import (
2122
is_denied_path,
2223
truncate_utf8,
@@ -60,8 +61,11 @@ def handle_before_submit_prompt(ctx: typer.Context, payload: AIHookPayload, poli
6061
try:
6162
violation_summary, scan_id = _scan_text_for_secrets(ctx, clipped, timeout_ms)
6263

63-
if violation_summary and get_policy_value(prompt_config, 'action',
64-
default='block') == 'block' and mode == 'block':
64+
if (
65+
violation_summary
66+
and get_policy_value(prompt_config, 'action', default='block') == 'block'
67+
and mode == 'block'
68+
):
6569
outcome = AIHookOutcome.BLOCKED
6670
block_reason = BlockReason.SECRETS_IN_PROMPT
6771
user_message = f'{violation_summary}. Remove secrets before sending.'
@@ -72,8 +76,9 @@ def handle_before_submit_prompt(ctx: typer.Context, payload: AIHookPayload, poli
7276
response = response_builder.allow_prompt()
7377
return response
7478
except Exception as e:
75-
outcome = AIHookOutcome.ALLOWED if get_policy_value(policy, 'fail_open',
76-
default=True) else AIHookOutcome.BLOCKED
79+
outcome = (
80+
AIHookOutcome.ALLOWED if get_policy_value(policy, 'fail_open', default=True) else AIHookOutcome.BLOCKED
81+
)
7782
block_reason = BlockReason.SCAN_FAILURE if outcome == AIHookOutcome.BLOCKED else None
7883
raise e
7984
finally:
@@ -133,15 +138,15 @@ def handle_before_read_file(ctx: typer.Context, payload: AIHookPayload, policy:
133138
user_message,
134139
'Secrets detected; do not send this file to the model.',
135140
)
136-
else:
137-
if violation_summary:
138-
outcome = AIHookOutcome.WARNED
139-
return response_builder.allow_permission()
141+
if violation_summary:
142+
outcome = AIHookOutcome.WARNED
143+
return response_builder.allow_permission()
140144

141145
return response_builder.allow_permission()
142146
except Exception as e:
143-
outcome = AIHookOutcome.ALLOWED if get_policy_value(policy, 'fail_open',
144-
default=True) else AIHookOutcome.BLOCKED
147+
outcome = (
148+
AIHookOutcome.ALLOWED if get_policy_value(policy, 'fail_open', default=True) else AIHookOutcome.BLOCKED
149+
)
145150
block_reason = BlockReason.SCAN_FAILURE if outcome == AIHookOutcome.BLOCKED else None
146151
raise e
147152
finally:
@@ -197,17 +202,17 @@ def handle_before_mcp_execution(ctx: typer.Context, payload: AIHookPayload, poli
197202
user_message,
198203
'Do not pass secrets to tools. Use secret references (name/id) instead.',
199204
)
200-
else:
201-
outcome = AIHookOutcome.WARNED
202-
return response_builder.ask_permission(
203-
f'{violation_summary} in MCP tool call "{tool}". Allow execution?',
204-
'Possible secrets detected in tool arguments; proceed with caution.',
205-
)
205+
outcome = AIHookOutcome.WARNED
206+
return response_builder.ask_permission(
207+
f'{violation_summary} in MCP tool call "{tool}". Allow execution?',
208+
'Possible secrets detected in tool arguments; proceed with caution.',
209+
)
206210

207211
return response_builder.allow_permission()
208212
except Exception as e:
209-
outcome = AIHookOutcome.ALLOWED if get_policy_value(policy, 'fail_open',
210-
default=True) else AIHookOutcome.BLOCKED
213+
outcome = (
214+
AIHookOutcome.ALLOWED if get_policy_value(policy, 'fail_open', default=True) else AIHookOutcome.BLOCKED
215+
)
211216
block_reason = BlockReason.SCAN_FAILURE if outcome == AIHookOutcome.BLOCKED else None
212217
raise e
213218
finally:
@@ -220,7 +225,7 @@ def handle_before_mcp_execution(ctx: typer.Context, payload: AIHookPayload, poli
220225
)
221226

222227

223-
def get_handler_for_event(event_type: str):
228+
def get_handler_for_event(event_type: str) -> Optional[Callable[[typer.Context, AIHookPayload, dict], dict]]:
224229
"""Get the appropriate handler function for a canonical event type.
225230
226231
Args:
@@ -274,8 +279,8 @@ def _perform_scan(
274279
try:
275280
scan_id, error, local_scan_result = result.get(timeout=timeout_seconds)
276281
except PoolTimeoutError:
277-
logger.debug(f'Scan timed out after {timeout_seconds} seconds')
278-
raise RuntimeError(f'Scan timed out after {timeout_seconds} seconds')
282+
logger.debug('Scan timed out after %s seconds', timeout_seconds)
283+
raise RuntimeError(f'Scan timed out after {timeout_seconds} seconds') from None
279284

280285
# Check if scan failed - raise exception to trigger fail_open policy
281286
if error:
@@ -294,9 +299,7 @@ def _perform_scan(
294299
return None, scan_id
295300

296301

297-
def _scan_text_for_secrets(
298-
ctx: typer.Context, text: str, timeout_ms: int
299-
) -> tuple[Optional[str], Optional[str]]:
302+
def _scan_text_for_secrets(ctx: typer.Context, text: str, timeout_ms: int) -> tuple[Optional[str], Optional[str]]:
300303
"""
301304
Scan text content for secrets using Cycode CLI.
302305
@@ -322,7 +325,7 @@ def _scan_path_for_secrets(ctx: typer.Context, file_path: str, policy: dict) ->
322325
if not file_path or not os.path.exists(file_path):
323326
return None, None
324327

325-
with open(file_path, 'r', encoding='utf-8', errors='replace') as f:
328+
with open(file_path, encoding='utf-8', errors='replace') as f:
326329
content = f.read()
327330

328331
# Truncate content based on policy max_bytes

cycode/cli/apps/scan/prompt/payload.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,5 +67,4 @@ def from_payload(cls, payload: dict, tool: str = 'cursor') -> 'AIHookPayload':
6767
"""
6868
if tool == 'cursor':
6969
return cls.from_cursor_payload(payload)
70-
else:
71-
raise ValueError(f'Unsupported IDE/tool: {tool}.')
70+
raise ValueError(f'Unsupported IDE/tool: {tool}.')

cycode/cli/apps/scan/prompt/prompt_command.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,9 @@ def prompt_command(
105105
# Fail closed
106106
if event_name == AiHookEventType.PROMPT:
107107
output_json(
108-
response_builder.deny_prompt('Cycode guardrails error - blocking due to fail-closed policy'))
108+
response_builder.deny_prompt('Cycode guardrails error - blocking due to fail-closed policy')
109+
)
109110
else:
110-
output_json(response_builder.deny_permission(
111-
'Cycode guardrails error',
112-
'Blocking due to fail-closed policy'
113-
))
111+
output_json(
112+
response_builder.deny_permission('Cycode guardrails error', 'Blocking due to fail-closed policy')
113+
)

cycode/cli/apps/scan/prompt/response_builders.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,22 @@ class IDEResponseBuilder(ABC):
1414
@abstractmethod
1515
def allow_permission(self) -> dict:
1616
"""Build response to allow file read or MCP execution."""
17-
pass
1817

1918
@abstractmethod
2019
def deny_permission(self, user_message: str, agent_message: str) -> dict:
2120
"""Build response to deny file read or MCP execution."""
22-
pass
2321

2422
@abstractmethod
2523
def ask_permission(self, user_message: str, agent_message: str) -> dict:
2624
"""Build response to ask user for permission (warn mode)."""
27-
pass
2825

2926
@abstractmethod
3027
def allow_prompt(self) -> dict:
3128
"""Build response to allow prompt submission."""
32-
pass
3329

3430
@abstractmethod
3531
def deny_prompt(self, user_message: str) -> dict:
3632
"""Build response to deny prompt submission."""
37-
pass
3833

3934

4035
class CursorResponseBuilder(IDEResponseBuilder):

cycode/cli/apps/scan/prompt/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,4 @@ def is_denied_path(file_path: str, policy: dict) -> bool:
6969

7070
def output_json(obj: dict) -> None:
7171
"""Write JSON response to stdout (for IDE to read)."""
72-
print(json.dumps(obj), end='')
72+
print(json.dumps(obj), end='') # noqa: T201

cycode/cyclient/ai_security_manager_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
if TYPE_CHECKING:
99
from cycode.cli.apps.scan.prompt.payload import AIHookPayload
10-
from cycode.cli.apps.scan.prompt.types import AIHookOutcome, AiHookEventType, BlockReason
10+
from cycode.cli.apps.scan.prompt.types import AiHookEventType, AIHookOutcome, BlockReason
1111
from cycode.cyclient.ai_security_manager_service_config import AISecurityManagerServiceConfigBase
1212

1313

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ inline-quotes = "single"
141141
ban-relative-imports = "all"
142142

143143
[tool.ruff.lint.per-file-ignores]
144-
"tests/*.py" = ["S101", "S105"]
144+
"tests/**/*.py" = ["S101", "S105", "ANN"]
145145
"cycode/*.py" = ["BLE001"]
146146

147147
[tool.ruff.format]

0 commit comments

Comments
 (0)