Handle target list comments and encoding errors

This commit is contained in:
bearsyankees
2026-07-06 23:29:01 -04:00
parent 7783fcac12
commit 2c470c9daa
6 changed files with 41 additions and 9 deletions
+1 -1
View File
@@ -169,7 +169,7 @@ strix --target https://your-app.com --instruction "Perform authenticated testing
# Multi-target testing (source code + deployed app) # Multi-target testing (source code + deployed app)
strix -t https://github.com/org/app -t https://your-app.com strix -t https://github.com/org/app -t https://your-app.com
# Targets from a file, one target per non-empty line # Targets from a file, one target per non-empty, non-comment line
strix --target-list ./targets.txt strix --target-list ./targets.txt
# White-box source-aware scan (local repository) # White-box source-aware scan (local repository)
+1 -1
View File
@@ -63,7 +63,7 @@ strix --target https://your-app.com
# Multiple targets (white-box testing) # Multiple targets (white-box testing)
strix -t https://github.com/org/repo -t https://your-app.com strix -t https://github.com/org/repo -t https://your-app.com
# Targets from a file, one target per non-empty line # Targets from a file, one target per non-empty, non-comment line
strix --target-list ./targets.txt strix --target-list ./targets.txt
``` ```
+1 -1
View File
@@ -16,7 +16,7 @@ strix (--target <target> | --target-list <path> | --mount <path>) [options]
</ParamField> </ParamField>
<ParamField path="--target-list" type="string"> <ParamField path="--target-list" type="string">
Path to a file containing targets, one per non-empty line. Can be specified multiple times and combined with `--target`. Path to a file containing targets, one per non-empty, non-comment line. Lines starting with `#` are ignored. Can be specified multiple times and combined with `--target`.
</ParamField> </ParamField>
<ParamField path="--mount" type="string"> <ParamField path="--mount" type="string">
+3 -3
View File
@@ -345,7 +345,7 @@ Examples:
strix --target https://github.com/user/repo --target https://example.com strix --target https://github.com/user/repo --target https://example.com
strix --target ./my-project --target https://staging.example.com --target https://prod.example.com strix --target ./my-project --target https://staging.example.com --target https://prod.example.com
# Targets from a file, one target per line # Targets from a file, one target per non-empty, non-comment line
strix --target-list ./targets.txt strix --target-list ./targets.txt
# Custom instructions (inline) # Custom instructions (inline)
@@ -378,8 +378,8 @@ Examples:
type=str, type=str,
action="append", action="append",
metavar="PATH", metavar="PATH",
help="Path to a file containing targets, one per non-empty line. Can be specified " help="Path to a file containing targets, one per non-empty, non-comment line. "
"multiple times and combined with --target.", "Can be specified multiple times and combined with --target.",
) )
parser.add_argument( parser.add_argument(
"--mount", "--mount",
+10 -2
View File
@@ -1132,7 +1132,7 @@ def infer_target_type(target: str) -> tuple[str, dict[str, str]]: # noqa: PLR09
def read_target_list_file(path_str: str) -> list[str]: def read_target_list_file(path_str: str) -> list[str]:
"""Read scan targets from a file, one target per non-empty line.""" """Read scan targets from a file, one target per non-empty, non-comment line."""
if not path_str or not path_str.strip(): if not path_str or not path_str.strip():
raise ValueError("--target-list path must not be empty.") raise ValueError("--target-list path must not be empty.")
@@ -1141,7 +1141,15 @@ def read_target_list_file(path_str: str) -> list[str]:
raise ValueError(f"Target list file '{path_str}' is not an existing file.") raise ValueError(f"Target list file '{path_str}' is not an existing file.")
try: try:
targets = [line.strip() for line in path.read_text(encoding="utf-8").splitlines()] targets = [
target
for line in path.read_text(encoding="utf-8").splitlines()
if (target := line.strip()) and not target.startswith("#")
]
except UnicodeDecodeError as e:
raise ValueError(
f"Target list file '{path_str}' must be valid UTF-8 text: {e!s}"
) from e
except OSError as e: except OSError as e:
raise ValueError(f"Failed to read target list file '{path_str}': {e!s}") from e raise ValueError(f"Failed to read target list file '{path_str}': {e!s}") from e
+25 -1
View File
@@ -175,9 +175,25 @@ def test_read_target_list_file_strips_blank_lines(tmp_path: Path) -> None:
] ]
def test_read_target_list_file_ignores_comment_lines(tmp_path: Path) -> None:
target_list = tmp_path / "targets.txt"
target_list.write_text(
"# production targets\n"
"https://test1.com/\n"
" # staging targets\n"
"http://test2.com:5789/\n",
encoding="utf-8",
)
assert read_target_list_file(str(target_list)) == [
"https://test1.com/",
"http://test2.com:5789/",
]
def test_read_target_list_file_rejects_empty_file(tmp_path: Path) -> None: def test_read_target_list_file_rejects_empty_file(tmp_path: Path) -> None:
target_list = tmp_path / "targets.txt" target_list = tmp_path / "targets.txt"
target_list.write_text(" \n\n", encoding="utf-8") target_list.write_text(" \n# no targets yet\n\n", encoding="utf-8")
with pytest.raises(ValueError, match="is empty"): with pytest.raises(ValueError, match="is empty"):
read_target_list_file(str(target_list)) read_target_list_file(str(target_list))
@@ -188,6 +204,14 @@ def test_read_target_list_file_rejects_missing_path(tmp_path: Path) -> None:
read_target_list_file(str(tmp_path / "missing.txt")) read_target_list_file(str(tmp_path / "missing.txt"))
def test_read_target_list_file_rejects_non_utf8_file(tmp_path: Path) -> None:
target_list = tmp_path / "targets.txt"
target_list.write_bytes(b"https://test1.com/\xff\n")
with pytest.raises(ValueError, match="must be valid UTF-8 text"):
read_target_list_file(str(target_list))
@pytest.mark.parametrize("empty", ["", " "]) @pytest.mark.parametrize("empty", ["", " "])
def test_read_target_list_file_rejects_empty_path(empty: str) -> None: def test_read_target_list_file_rejects_empty_path(empty: str) -> None:
with pytest.raises(ValueError, match="must not be empty"): with pytest.raises(ValueError, match="must not be empty"):