From f02c0ca0f4a7fbdcb67585e3a1f91563078eef3b Mon Sep 17 00:00:00 2001 From: Colin Brown Date: Tue, 10 Feb 2026 09:19:28 +0000 Subject: [PATCH 1/2] Update README badges and enhance ruff linting configuration --- README.md | 7 +++++++ pyproject.toml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1ce69e9..ee44ccb 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,12 @@ # logpilot 🪵 + +![Python Version](https://img.shields.io/badge/python-3.9%2B-blue) +![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg) +![Code style: ruff](https://img.shields.io/badge/code%20style-ruff-d7ff64.svg) +![Security: ruff](https://img.shields.io/badge/security-ruff%20S-orange) + + A Python CLI tool for analyzing logs using the GitHub Copilot SDK. ## Features diff --git a/pyproject.toml b/pyproject.toml index f70ad43..3fe4e55 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ indent-width = 1 exclude = [".git", "__pycache__", ".venv", "venv", "env", "build", "dist"] [tool.ruff.lint] -select = ["E", "F", "W", "I"] +select = ["E", "F", "W", "I", "S"] ignore = [] [tool.ruff.format] From aa743a69a804eec4ce9c63b2e0eb1b09ac8fba0c Mon Sep 17 00:00:00 2001 From: Colin Brown Date: Tue, 10 Feb 2026 09:48:30 +0000 Subject: [PATCH 2/2] Enhance error handling in version detection and update CLI test commands for improved security --- logpilot/cli.py | 4 ++-- pyproject.toml | 3 +++ tests/test_cli.py | 22 +++++++++++++++------- tests/test_llm_client.py | 3 ++- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/logpilot/cli.py b/logpilot/cli.py index 9e6cc04..4d528cf 100644 --- a/logpilot/cli.py +++ b/logpilot/cli.py @@ -27,8 +27,8 @@ def get_version() -> str: version = data.get("project", {}).get("version") if version: return version - except Exception: - pass + except Exception: # noqa: S110 + pass # Intentionally silent - version detection is optional return "unknown" diff --git a/pyproject.toml b/pyproject.toml index 3fe4e55..d20e465 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,9 @@ exclude = [".git", "__pycache__", ".venv", "venv", "env", "build", "dist"] select = ["E", "F", "W", "I", "S"] ignore = [] +[tool.ruff.lint.per-file-ignores] +"tests/**/*.py" = ["S101", "S603"] # Allow assert and subprocess in tests + [tool.ruff.format] indent-style = "tab" diff --git a/tests/test_cli.py b/tests/test_cli.py index aed7f95..3edfb51 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -14,11 +14,16 @@ def run_cli(args, env=None): env = dict(os.environ) if env is None else env env["LOGPILOT_MOCK_LLM"] = "1" + # Construct command with trusted values only + cmd = [sys.executable, "-m", "logpilot.cli"] + # Arguments are safe without quoting when shell=False + cmd.extend(args) return subprocess.run( - [sys.executable, "-m", "logpilot.cli"] + args, + cmd, capture_output=True, text=True, env=env, + shell=False, ) @@ -225,11 +230,14 @@ def test_cli_analyze_basic(tmp_path, monkeypatch): # Run the CLI analyze command with mock LLM enabled env = dict(os.environ) env["LOGPILOT_MOCK_LLM"] = "1" + # Construct command with trusted values only + cmd = [sys.executable, "-m", "logpilot.cli", "analyze", str(log_file)] result = subprocess.run( - [sys.executable, "-m", "logpilot.cli", "analyze", str(log_file)], + cmd, capture_output=True, text=True, env=env, + shell=False, ) assert result.returncode == 0, f"stdout: {result.stdout}\nstderr: {result.stderr}" assert "Something failed" in result.stdout or "critical" in result.stdout.lower() @@ -334,7 +342,7 @@ def test_analyze_stdin_rejected(self): runner = typer.testing.CliRunner() result = runner.invoke(app, ["analyze", "-"]) assert result.exit_code != 0 - output = (result.stdout or "") + (result.stderr or "") + output = result.output assert "Error: stdin is not supported" in output def test_analyze_with_max_tokens(self, tmp_path): @@ -387,7 +395,7 @@ def test_cli_help_command(): """Test CLI help command.""" result = run_cli_direct(["--help"]) assert result.exit_code == 0 - output = (result.stdout or "") + (result.stderr or "") + output = result.stdout assert "Logpilot CLI" in output or "Usage" in output @@ -396,7 +404,7 @@ def test_cli_analyze_help(tmp_path): """Test analyze subcommand help.""" result = run_cli_direct(["analyze", "--help"]) assert result.exit_code == 0 - output = (result.stdout or "") + (result.stderr or "") + output = result.stdout assert "Analyze logs" in output or "analyze" in output.lower() @@ -736,14 +744,14 @@ def test_analyze_empty_log_file(self, tmp_path): result = run_cli_direct(["analyze", str(log_file)]) assert result.exit_code != 0 - output = (result.stdout or "") + (result.stderr or "") + output = result.output assert "No log entries" in output or "Error" in output def test_analyze_stdin_not_supported(self): """Test that stdin input is rejected.""" result = run_cli_direct(["analyze", "-"]) assert result.exit_code != 0 - output = (result.stdout or "") + (result.stderr or "") + output = result.output assert "stdin is not supported" in output def test_analyze_with_all_options(self, tmp_path): diff --git a/tests/test_llm_client.py b/tests/test_llm_client.py index 6c48ce6..7e1aee6 100644 --- a/tests/test_llm_client.py +++ b/tests/test_llm_client.py @@ -6,6 +6,7 @@ import pytest +# noqa: S603, S607 - Suppress bandit warnings for test code with hardcoded strings from logpilot.llm_client import LLMClient # ============================================================================ @@ -102,7 +103,7 @@ def test_llm_client_via_subprocess(): """ env = dict(os.environ) env["LOGPILOT_MOCK_LLM"] = "1" - result = subprocess.run( + result = subprocess.run( # noqa: S603 [sys.executable, "-c", code], capture_output=True, text=True,