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
5 changes: 5 additions & 0 deletions node/src/commands/agent/scan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,11 @@ async function scanDiffFiles(
scanPath?: string,
suppressions: Suppression[] = [],
): Promise<void> {
// git would parse a leading "-" as one of its own options, not a ref.
if (ref.startsWith("-")) {
console.error(`Error: invalid ref "${ref}" (a git ref cannot start with "-")`);
process.exit(2);
}
await runGitAddedLineScan(
["diff", "-U0", "--no-color", "--diff-filter=ACM", ref],
opts,
Expand Down
12 changes: 12 additions & 0 deletions node/tests/secret-scanning-e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,18 @@ describe("E2E: git --diff scanning", () => {
expect(parsed.results[0].matches[0].pattern.name).toBe("AWS Access Key ID");
});

it("rejects a --diff ref that git would parse as an option", () => {
const target = path.join(tmpDir, "untouched.txt");
fs.writeFileSync(target, "keep\n");

const r = rafter(
["scan", "local", tmpDir, "--diff", `--output=${target}`, "--engine", "patterns", "--quiet"],
{ cwd: tmpDir },
);
expect(r.exitCode).toBe(2);
expect(fs.readFileSync(target, "utf-8")).toBe("keep\n");
});

it("exits 0 when changed files are clean", () => {
const initialCommit = git("rev-parse HEAD");

Expand Down
8 changes: 8 additions & 0 deletions python/rafter_cli/commands/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -1736,6 +1736,13 @@ def _output_empty_diff_scan(
)


def _reject_option_like_ref(ref: str) -> None:
"""git would parse a leading "-" as one of its own options, not a ref."""
if ref.startswith("-"):
print(f'Error: invalid ref "{ref}" (a git ref cannot start with "-")', file=sys.stderr)
raise typer.Exit(code=2)


def _run_git_added_line_scan(
git_args: list[str],
git_cwd: str | None,
Expand Down Expand Up @@ -2176,6 +2183,7 @@ def scan(

# --diff
if diff:
_reject_option_like_ref(diff)
_run_git_added_line_scan(
["diff", "-U0", "--no-color", "--diff-filter=ACM", diff],
git_cwd,
Expand Down
2 changes: 2 additions & 0 deletions python/rafter_cli/commands/scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ def scan_local(
_apply_exclude_paths,
_load_baseline_entries,
_run_git_added_line_scan,
_reject_option_like_ref,
)
from ..core.config_manager import ConfigManager
from ..core.custom_patterns import load_suppressions, policy_ignore_to_suppressions
Expand Down Expand Up @@ -146,6 +147,7 @@ def scan_local(

# --diff
if diff:
_reject_option_like_ref(diff)
_run_git_added_line_scan(
["diff", "-U0", "--no-color", "--diff-filter=ACM", diff],
git_cwd,
Expand Down
14 changes: 14 additions & 0 deletions python/tests/test_secret_scanning_e2e.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import json
import os
import subprocess
import sys
from pathlib import Path

import pytest
Expand Down Expand Up @@ -391,6 +392,19 @@ def test_detects_secrets_in_changed_files(self, tmp_path):
assert len(results) == 1
assert results[0].matches[0].pattern.name == "AWS Access Key ID"

def test_rejects_a_diff_ref_that_git_would_parse_as_an_option(self, tmp_path):
target = tmp_path / "untouched.txt"
target.write_text("keep\n")

result = subprocess.run(
[sys.executable, "-m", "rafter_cli", "secrets", self.repo,
"--diff", f"--output={target}", "--engine", "patterns", "--quiet"],
capture_output=True, text=True, cwd=self.repo, timeout=60,
env={**os.environ, "HOME": str(tmp_path)},
)
assert result.returncode == 2
assert target.read_text() == "keep\n"

def test_clean_changed_files_produce_no_results(self, tmp_path):
initial = _git("rev-parse HEAD", self.repo)

Expand Down
Loading