Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 1 addition & 8 deletions SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -336,13 +336,6 @@ CodeLens v8.0+ adds 7 major capability pillars over v7.x:
5. **Cross-File Dataflow Engine** (`dataflow` v2) — Workspace-wide call graph with import resolution (`from/import`, `require` destructuring) and bidirectional taint propagation.
6. **OWASP Top 10 + Compliance Mapping** — 89 rules total (A01-A10 + PCI-DSS requirements 1-12 + HIPAA 45 CFR § 164.312).
7. **CI/CD Quality Gate** (`check` command) — Exits non-zero on failure, SARIF output for GitHub Advanced Security / VS Code.
8. **Diff-Scoped Analysis** (`--diff-base REF` flag, issue #157) — Global flag that restricts any analysis command to only report findings from files changed relative to a git ref (branch/tag/SHA/`HEAD~1`). Empty diff → early exit with clear message. Invalid ref → clear error + non-zero exit. Useful for CI PR checks where only NEW findings introduced by the PR should fail the gate.

```bash
# CI PR check — only findings from files changed vs main
codelens check . --diff-base origin/main --format sarif > codelens.sarif
codelens taint . --diff-base origin/main
codelens secrets . --diff-base HEAD~1
```
8. **Gitleaks-Backed Secrets Scanner** (`secrets` command, issue #159) — When [gitleaks](https://github.com/gitleaks/gitleaks) is installed, `codelens secrets` uses it as the primary backend for 600+ maintained rules and entropy scoring. Falls back to the built-in regex scanner when gitleaks is unavailable (opt-in upgrade, never a hard dependency). Use `--no-gitleaks` to force the regex backend. Install: `brew install gitleaks` / `go install github.com/gitleaks/gitleaks/v8@latest` / [GitHub releases](https://github.com/gitleaks/gitleaks/releases).

v8.1 follows up with F1 benchmark improvements (avg F1 0.803 → 0.872), circular engine depth fixes (F1 0.667 → 1.000), dead-code engine fixes (F1 0.800 → 0.952), and AST taint depth enhancements (return-value propagation, scope-hierarchical TaintState, branch condition refinement).
73 changes: 71 additions & 2 deletions scripts/commands/secrets.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
"""Secrets command — Detect hardcoded secrets and API keys."""
"""Secrets command — Detect hardcoded secrets and API keys.

Issue #159: When gitleaks is installed, use it as the primary backend
(600+ maintained rules, entropy scoring). Fall back to the built-in
regex scanner when gitleaks is unavailable or ``--no-gitleaks`` is set.
"""

import sys

from secrets_engine import detect_secrets
from commands import register_command
Expand All @@ -11,10 +18,72 @@ def add_args(parser):
help="Filter by severity")
parser.add_argument("--max-files", type=int, default=5000,
help="Maximum number of files to scan (default: 5000)")
# Issue #159: force regex backend even if gitleaks is available.
# Useful for testing, offline environments, or when gitleaks produces
# unexpected results.
parser.add_argument("--no-gitleaks", action="store_true", default=False,
help="Force the built-in regex scanner even if "
"gitleaks is available (issue #159)")


def execute(args, workspace):
return detect_secrets(workspace, severity=args.severity, max_files=args.max_files)
"""Run the secrets scan, preferring gitleaks when available.

@FLOW: SECRETS_SCAN
@CALLS: gitleaks_backend.scan_with_gitleaks() -> result | None
@CALLS: secrets_engine.detect_secrets() -> result (fallback)
@MUTATES: none (read-only scan; gitleaks writes only to temp file)
"""
# Issue #159: try gitleaks first unless --no-gitleaks
use_gitleaks = not getattr(args, "no_gitleaks", False)
if use_gitleaks:
try:
from gitleaks_backend import scan_with_gitleaks, _gitleaks_available
except ImportError:
# gitleaks_backend module unavailable — fall through to regex
use_gitleaks = False
else:
if _gitleaks_available():
try:
result = scan_with_gitleaks(
workspace,
severity=args.severity,
)
except Exception as exc:
# Gitleaks failed — fall back to regex with a warning.
# Never crash the command; gitleaks is opt-in.
print(
f"[CodeLens] gitleaks backend failed: {exc}. "
f"Falling back to regex scanner.",
file=sys.stderr,
)
result = None
if result is not None:
return result
# result is None → gitleaks not available, fall through
# else: gitleaks not installed, fall through to regex

# Regex backend (existing behavior)
result = detect_secrets(
workspace,
severity=args.severity,
max_files=args.max_files,
)
# Tag the backend so consumers can tell which scanner ran
if isinstance(result, dict):
result["backend"] = "regex"
if use_gitleaks:
# We tried gitleaks but it wasn't available — surface install hint
result["gitleaks_hint"] = (
"gitleaks not found — using built-in regex scanner (lower "
"accuracy). Install gitleaks for 600+ maintained rules and "
"entropy scoring: https://github.com/gitleaks/gitleaks"
)
# Surface in stats too so compact/ai formatters pick it up
stats = result.get("stats")
if isinstance(stats, dict):
stats["backend"] = "regex"
return result


register_command("secrets", "Detect hardcoded secrets and API keys", add_args, execute)
Loading
Loading