Skip to content

Commit 0cdac5a

Browse files
authored
Merge branch 'main' into CM-61986-enrich-data-for-guardrails
2 parents 417deaa + d778209 commit 0cdac5a

24 files changed

Lines changed: 915 additions & 199 deletions

README.md

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ This guide walks you through both installation and usage.
3030
4. [Package Vulnerabilities](#package-vulnerabilities-option)
3131
5. [License Compliance](#license-compliance-option)
3232
6. [Lock Restore](#lock-restore-option)
33+
7. [Stop on Error](#stop-on-error-option)
3334
2. [Repository Scan](#repository-scan)
3435
1. [Branch Option](#branch-option)
3536
3. [Path Scan](#path-scan)
@@ -384,12 +385,22 @@ The MCP server provides the following tools that AI systems can use:
384385

385386
| Tool Name | Description |
386387
|----------------------|---------------------------------------------------------------------------------------------|
387-
| `cycode_secret_scan` | Scan files for hardcoded secrets |
388-
| `cycode_sca_scan` | Scan files for Software Composition Analysis (SCA) - vulnerabilities and license issues |
389-
| `cycode_iac_scan` | Scan files for Infrastructure as Code (IaC) misconfigurations |
390-
| `cycode_sast_scan` | Scan files for Static Application Security Testing (SAST) - code quality and security flaws |
388+
| `cycode_secret_scan` | Scan for hardcoded secrets |
389+
| `cycode_sca_scan` | Scan for Software Composition Analysis (SCA) - vulnerabilities and license issues |
390+
| `cycode_iac_scan` | Scan for Infrastructure as Code (IaC) misconfigurations |
391+
| `cycode_sast_scan` | Scan for Static Application Security Testing (SAST) - code quality and security flaws |
391392
| `cycode_status` | Get Cycode CLI version, authentication status, and configuration information |
392393

394+
Each scan tool accepts two mutually exclusive input modes:
395+
396+
- **`paths`** *(preferred)* — one or more file or directory paths that exist on disk. Directories are scanned recursively. The Cycode engine handles file discovery and filtering, just as `cycode scan -t <type> path ./src` does from the CLI.
397+
- **`files`** *(fallback)* — a dictionary mapping file paths to their full content as strings. Use this only when the files are not available on disk (e.g. in-memory edits not yet saved).
398+
399+
> [!TIP]
400+
> Use `paths` whenever possible. Passing large files (like `package-lock.json`) as inline content can exceed token limits and slow down the AI client. With `paths`, the Cycode engine reads files directly from disk.
401+
402+
All scan tools return a JSON object that includes a `"summary"` field with a human-readable violation count (e.g. `"Cycode found 3 violations: 1 CRITICAL, 2 HIGH."`) in addition to the full `"detections"` array.
403+
393404
### Usage Examples
394405

395406
#### Basic Command Examples
@@ -547,6 +558,26 @@ cycode mcp -t streamable-http -H 127.0.0.2 -p 9000 &
547558
> [!NOTE]
548559
> The MCP server requires proper Cycode CLI authentication to function. Make sure you have authenticated using `cycode auth` or configured your credentials before starting the MCP server.
549560

561+
### Pre-authorizing Tools for Subagents (Claude Code)
562+
563+
When Claude Code delegates work to background subagents (e.g. to run scans in parallel), those subagents cannot display interactive permission prompts. If the Cycode tools have not been pre-approved, scans will fail silently in subagent contexts.
564+
565+
To pre-authorize the Cycode MCP tools so they work in all contexts including subagents, add them to the `allowedTools` list in your Claude Code settings (`~/.claude/settings.json`):
566+
567+
```json
568+
{
569+
"allowedTools": [
570+
"mcp__cycode__cycode_secret_scan",
571+
"mcp__cycode__cycode_sca_scan",
572+
"mcp__cycode__cycode_iac_scan",
573+
"mcp__cycode__cycode_sast_scan",
574+
"mcp__cycode__cycode_status"
575+
]
576+
}
577+
```
578+
579+
Once added, Claude Code will not prompt for approval when these tools are called, and they will work correctly inside subagents.
580+
550581
### Troubleshooting MCP
551582

552583
If you encounter issues with the MCP server, you can enable debug logging to get more detailed information about what's happening. There are two ways to enable debug logging:
@@ -590,6 +621,7 @@ The Cycode CLI application offers several types of scans so that you can choose
590621
| `--monitor` | When specified, the scan results will be recorded in Cycode. |
591622
| `--cycode-report` | Display a link to the scan report in the Cycode platform in the console output. |
592623
| `--no-restore` | When specified, Cycode will not run the restore command. This will scan direct dependencies ONLY! |
624+
| `--stop-on-error` | Abort the scan if any file collection or dependency restore failure occurs, instead of skipping the failed file and continuing. |
593625
| `--gradle-all-sub-projects` | Run gradle restore command for all sub projects. This should be run from |
594626
| `--maven-settings-file` | For Maven only, allows using a custom [settings.xml](https://maven.apache.org/settings.html) file when scanning for dependencies |
595627
| `--help` | Show options for given command. |
@@ -696,6 +728,18 @@ If a lockfile already exists alongside the manifest, Cycode reads it directly wi
696728
addSbtPlugin("software.purpledragon" % "sbt-dependency-lock" % "1.5.1")
697729
```
698730

731+
#### Stop on Error Option
732+
733+
By default, Cycode continues scanning even if a file cannot be read (e.g. due to a permission error) or a dependency lockfile cannot be generated during an SCA scan. The failed item is skipped with a warning and the scan proceeds with the remaining files.
734+
735+
Use `--stop-on-error` to change this behaviour: the scan aborts immediately on the first such failure and reports the error.
736+
737+
```bash
738+
cycode scan -t sca --stop-on-error path ~/home/git/codebase
739+
```
740+
741+
This is useful in CI pipelines where a silent failure would produce an incomplete scan result. When `--stop-on-error` is triggered you can either fix the underlying issue or, for SCA restore failures specifically, add `--no-restore` to skip lockfile generation and scan direct dependencies only.
742+
699743
### Repository Scan
700744

701745
A repository scan examines an entire local repository for any exposed secrets or insecure misconfigurations. This more holistic scan type looks at everything: the current state of your repository and its commit history. It will look not only for secrets that are currently exposed within the repository but previously deleted secrets as well.

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

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ def handle_before_read_file(ctx: typer.Context, payload: AIHookPayload, policy:
116116

117117
try:
118118
# Check path-based denylist first
119-
if is_denied_path(file_path, policy):
119+
is_sensitive_path = is_denied_path(file_path, policy)
120+
if is_sensitive_path:
120121
block_reason = BlockReason.SENSITIVE_PATH
121122
if mode == PolicyMode.BLOCK and action == PolicyMode.BLOCK:
122123
outcome = AIHookOutcome.BLOCKED
@@ -125,13 +126,21 @@ def handle_before_read_file(ctx: typer.Context, payload: AIHookPayload, policy:
125126
user_message,
126127
'This file path is classified as sensitive; do not read/send it to the model.',
127128
)
128-
# Warn mode - ask user for permission
129+
# Warn mode - if content scan is enabled, emit a separate event for the
130+
# sensitive path so the finally block can independently track the scan result.
131+
# If content scan is disabled, a single event (from finally) is enough.
129132
outcome = AIHookOutcome.WARNED
130-
user_message = f'Cycode flagged {file_path} as sensitive. Allow reading?'
131-
return response_builder.ask_permission(
132-
user_message,
133-
'This file path is classified as sensitive; proceed with caution.',
134-
)
133+
if get_policy_value(file_read_config, 'scan_content', default=True):
134+
ai_client.create_event(
135+
payload,
136+
AiHookEventType.FILE_READ,
137+
outcome,
138+
block_reason=BlockReason.SENSITIVE_PATH,
139+
file_path=payload.file_path,
140+
)
141+
# Reset for the content scan result tracked by the finally block
142+
block_reason = None
143+
outcome = AIHookOutcome.ALLOWED
135144

136145
# Scan file content if enabled
137146
if get_policy_value(file_read_config, 'scan_content', default=True):
@@ -152,7 +161,14 @@ def handle_before_read_file(ctx: typer.Context, payload: AIHookPayload, policy:
152161
user_message,
153162
'Possible secrets detected; proceed with caution.',
154163
)
155-
return response_builder.allow_permission()
164+
165+
# If path was sensitive but content scan found no secrets (or scan disabled), still warn
166+
if is_sensitive_path:
167+
user_message = f'Cycode flagged {file_path} as sensitive. Allow reading?'
168+
return response_builder.ask_permission(
169+
user_message,
170+
'This file path is classified as sensitive; proceed with caution.',
171+
)
156172

157173
return response_builder.allow_permission()
158174
except Exception as e:
@@ -342,7 +358,7 @@ def _scan_path_for_secrets(ctx: typer.Context, file_path: str, policy: dict) ->
342358
Returns tuple of (violation_summary, scan_id) if secrets found, (None, scan_id) if clean.
343359
Raises exception on error or timeout.
344360
"""
345-
if not file_path or not os.path.exists(file_path):
361+
if not file_path or not os.path.isfile(file_path):
346362
return None, None
347363

348364
max_bytes = get_policy_value(policy, 'secrets', 'max_bytes', default=200000)

0 commit comments

Comments
 (0)