From f93649b1952d14a64db2403b9ce9c669f2d5242c Mon Sep 17 00:00:00 2001
From: "qodo-merge-etso[bot]"
<241087977+qodo-merge-etso[bot]@users.noreply.github.com>
Date: Tue, 17 Mar 2026 16:30:12 +0000
Subject: [PATCH] Generated best practices file
---
best_practices.md | 173 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 173 insertions(+)
create mode 100644 best_practices.md
diff --git a/best_practices.md b/best_practices.md
new file mode 100644
index 0000000..e079c96
--- /dev/null
+++ b/best_practices.md
@@ -0,0 +1,173 @@
+
+Pattern 1: When validating CLI input or required environment variables, raise a dedicated, user-facing exception that is caught at the top-level to print a clean error message and exit without a full traceback.
+
+
+Example code before:
+```
+def parse_args(argv):
+ if "--token" in argv and os.getenv("SNYK_TOKEN") is None:
+ raise ValueError("SNYK_TOKEN environment variable not set")
+```
+
+Example code after:
+```
+class ValidationError(Exception):
+ """User-facing CLI validation error (no traceback)."""
+
+def parse_args(argv):
+ if "--token" in argv and os.getenv("SNYK_TOKEN") is None:
+ raise ValidationError("To use Agent Scan, set the SNYK_TOKEN environment variable.")
+
+def main():
+ try:
+ args = parse_args(sys.argv)
+ run(args)
+ except ValidationError as e:
+ print(str(e), file=sys.stderr)
+ raise SystemExit(2)
+```
+
+Examples for relevant past discussions:
+
+- https://github.com/snyk/agent-scan/pull/214#discussion_r2926186215
+- https://github.com/snyk/agent-scan/pull/199#discussion_r2878421031
+
+
+
+___
+
+Pattern 2: Add targeted unit tests whenever introducing or changing parsing/validation logic, especially for edge cases like unknown flags, missing values, or special-case classification rules.
+
+
+Example code before:
+```
+def parse_block(block):
+ # new parsing logic added, but no tests covering unknown flags/missing values
+ ...
+```
+
+Example code after:
+```
+def test_parse_block_unknown_flag_does_not_hang():
+ argv = ["--control-server", "https://x", "--verbose", "--control-identifier", "id"]
+ assert parse_control_servers(argv)[0].identifier == "id"
+
+def test_parse_block_missing_value_is_handled():
+ argv = ["--control-server", "https://x", "--control-identifier", "--next-flag"]
+ with pytest.raises(ValidationError):
+ parse_control_servers(argv)
+```
+
+Examples for relevant past discussions:
+
+- https://github.com/snyk/agent-scan/pull/214#discussion_r2926285319
+- https://github.com/snyk/agent-scan/pull/210#discussion_r2926142652
+- https://github.com/snyk/agent-scan/pull/149#discussion_r2627380691
+
+
+
+___
+
+Pattern 3: When the same logic appears in multiple places (e.g., defaulting/expanding scan paths, expanding ~ paths, or repeated file existence checks), extract it into a shared helper to prevent drift and simplify future changes.
+
+
+Example code before:
+```
+if not args.files:
+ args.files = WELL_KNOWN_PATHS
+if args.scan_all_users:
+ args.files = expand_paths_all_home_directories(args.files)
+
+# ...later, repeated again in another command path...
+if not args.files:
+ args.files = WELL_KNOWN_PATHS
+if args.scan_all_users:
+ args.files = expand_paths_all_home_directories(args.files)
+```
+
+Example code after:
+```
+def normalize_scan_paths(files, scan_all_users: bool) -> list[str]:
+ files = files or WELL_KNOWN_PATHS
+ return expand_paths_all_home_directories(files) if scan_all_users else files
+
+args.files = normalize_scan_paths(getattr(args, "files", None), getattr(args, "scan_all_users", False))
+```
+
+Examples for relevant past discussions:
+
+- https://github.com/snyk/agent-scan/pull/203#discussion_r2896086754
+- https://github.com/snyk/agent-scan/pull/203#discussion_r2896099448
+- https://github.com/snyk/agent-scan/pull/141#discussion_r2580395659
+
+
+
+___
+
+Pattern 4: Whenever CLI behavior depends on non-obvious grouping/ordering rules or changes user-facing semantics, document it in either argparse --help text and/or an explicit code comment, and keep README/docs examples in sync with the behavior.
+
+
+Example code before:
+```
+def parse_control_servers(argv):
+ """Parse control server arguments from sys.argv."""
+ # grouping/ordering expectations are implicit and undocumented
+ ...
+```
+
+Example code after:
+```
+def parse_control_servers(argv):
+ """
+ Parse repeated control-server blocks.
+
+ Expected structure (repeatable):
+ --control-server URL [--control-server-H HEADER ...] --control-identifier IDENTIFIER
+ """
+ ...
+```
+
+Examples for relevant past discussions:
+
+- https://github.com/snyk/agent-scan/pull/214#discussion_r2926207197
+- https://github.com/snyk/agent-scan/pull/207#discussion_r2905560074
+- https://github.com/snyk/agent-scan/pull/106#discussion_r2409593073
+
+
+
+___
+
+Pattern 5: Prefer cross-platform filesystem handling (pathlib, expanduser, Windows-safe temp files) and avoid assumptions about Unix-only paths; add Windows-specific handling when working with "~", temporary files, or path existence checks.
+
+
+Example code before:
+```
+def inspect_dir(path: str):
+ # may fail on Windows due to "~" or path semantics
+ entries = os.listdir(path)
+ return [os.path.join(path, e) for e in entries]
+```
+
+Example code after:
+```
+from pathlib import Path
+
+def inspect_dir(path: str):
+ p = Path(path).expanduser()
+ return [str(child) for child in p.iterdir()]
+
+# For temporary files used across OSes:
+with tempfile.NamedTemporaryFile(delete=False) as tmp:
+ tmp.write(data)
+ tmp_path = tmp.name
+```
+
+Examples for relevant past discussions:
+
+- https://github.com/snyk/agent-scan/pull/167#discussion_r2765466883
+- https://github.com/snyk/agent-scan/pull/106#discussion_r2409610302
+- https://github.com/snyk/agent-scan/pull/203#discussion_r2896099448
+
+
+
+___