From 238a6413c1063bf35c9eed60d8220f30dcafe6a9 Mon Sep 17 00:00:00 2001 From: DLANSAMA Date: Thu, 23 Jul 2026 18:35:12 -0400 Subject: [PATCH] chore: fold pytest.ini + .coveragerc into pyproject.toml; remove .jules/ --- .coveragerc | 15 --------------- .jules/bolt.md | 14 -------------- .jules/sentinel.md | 14 -------------- CHANGELOG.md | 3 +++ MANIFEST.in | 1 - docs/quality-roadmap.md | 2 +- pyproject.toml | 30 ++++++++++++++++++++++++++++++ pytest.ini | 11 ----------- 8 files changed, 34 insertions(+), 56 deletions(-) delete mode 100644 .coveragerc delete mode 100644 .jules/bolt.md delete mode 100644 .jules/sentinel.md delete mode 100644 pytest.ini diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 38a15b5..0000000 --- a/.coveragerc +++ /dev/null @@ -1,15 +0,0 @@ -[run] -branch = True -source = bambu_cli - -[report] -precision = 1 -# Honest coverage: do not hide except Exception/pass/continue. -# Only exclude lines that are definitionally unmeasurable or non-executable. -exclude_lines = - pragma: no cover - def __repr__ - if TYPE_CHECKING: - raise NotImplementedError - if __name__ == .__main__.: - \.\.\. diff --git a/.jules/bolt.md b/.jules/bolt.md deleted file mode 100644 index 39dbb9f..0000000 --- a/.jules/bolt.md +++ /dev/null @@ -1,14 +0,0 @@ -## 2026-07-19 - URL parsing bottleneck in JSON serialization -**Learning:** `urllib.parse.urlparse` has significant overhead when called iteratively on regular strings. In `platecli`, the JSON output compaction loops through every string and calls `_redact_url_credentials`, which was doing a full `urlparse`. An initial attempt to fast-path using `if "://" not in url:` was rejected in review because protocol-relative credentials (e.g. `//user:pass@host`) lack `://`. -**Action:** When adding fast-paths for string checks, ensure the criteria exactly matches structural requirements. For URL credentials, an `"@"` is always required. - -## 2026-07-20 - Optimizing path expansions and DNS resolution -**Learning:** `os.path.expanduser("~")` and `socket.getaddrinfo` (DNS resolution) can become significant bottlenecks when repeatedly invoked inside inner loops or status monitoring loops respectively. In `platecli`, `_display_path` was re-computing the home directory multiple times on every path string in JSON emission. Additionally, `_resolve_ip` was spinning up a new thread and doing DNS resolution on every single invocation, which happens frequently during operations like FTP uploads and camera streaming that use `_resolve_ip` dynamically. -**Action:** Caching the result of `os.path.expanduser("~")` globally inside the module significantly speeds up path string compacting operations. For network operations, caching successful IP resolutions via a simple dictionary `_RESOLVE_IP_CACHE` avoids repeating thread-creation and DNS lookup delays across the same execution. -## 2024-07-21 - Caching Slicer Profile Key Discovery -**Learning:** The CLI reads and parses all OrcaSlicer `.json` profiles in a directory multiple times during a single `slice` operation to discover all possible override keys. This causes significant, unnecessary file I/O and JSON parsing for directories that are completely static for the duration of the command's execution. -**Action:** When a function iterates over and parses many files in a static configuration directory, add `@lru_cache` if it's called repeatedly within the same execution context. - -## 2024-07-23 - JSON parsing overhead in static configuration searches -**Learning:** During profile discovery, searching for compatible printers in OrcaSlicer profiles resulted in repeated reading and `json.loads()` parsing of the exact same JSON files from disk (e.g. searching through "0.20mm" files during fallbacks). Furthermore, fully parsing the JSON document just to verify if a single string exists in an array is computationally heavy when many files are checked. -**Action:** Always combine `@lru_cache` for static file lookups in tight loops with a fast-path substring check (`if string not in content:`) after reading the raw file contents but before calling `json.loads()`. This definitively rules out files without incurring the JSON parsing overhead. diff --git a/.jules/sentinel.md b/.jules/sentinel.md deleted file mode 100644 index cb2d9b6..0000000 --- a/.jules/sentinel.md +++ /dev/null @@ -1,14 +0,0 @@ -## 2024-03-24 - [Replace Weak Randomness with Cryptographic Secrets] -**Vulnerability:** [Weak random number generation used in backoff delay] -**Learning:** [Using `random` module for generating backoff delay jitter is flagged as a generic security anti-pattern (CWE-322/B311: "Weak random number generation"). While not strictly used for cryptographic secrets here, the presence of `random` import is poor hygiene and replacing it with `secrets.SystemRandom().uniform()` ensures cryptographically strong randomness.] -**Prevention:** [Always use `secrets` instead of `random` to generate random values, especially when working on security-related tasks.] - -## 2024-05-24 - [Strict URL Credential Redaction] -**Vulnerability:** URL credentials were only redacted if a password attribute existed on the parsed URL. In HTTP Basic Auth, tokens are frequently provided as the username field without a password (e.g., https://[token-example]/). The previous redaction function leaked these token-based credentials into error logs. -**Learning:** Checking for just password is insufficient to protect bearer tokens or API keys passed via URL. -**Prevention:** Always verify both username and password components, and mask both entirely to prevent token leakage in structured logs. - -## 2025-02-27 - Predictable Temporary File Path in Health Checks -**Vulnerability:** Found `os.path.join(tempfile.gettempdir(), "printer_capabilities.json")` used as the default path for `doctor` capabilities output in `bambu_cli/commands/doctor.py`. -**Learning:** Hardcoding a predictable file name in a world-writable directory (`/tmp`) creates a local symlink attack vector. If an attacker pre-creates a symlink at that location pointing to a critical system file (e.g., `~/.bashrc`), running the `doctor` command would overwrite the target file with the user's privileges. -**Prevention:** Use `tempfile.mkstemp()` or `tempfile.NamedTemporaryFile()` to ensure that the OS safely generates a unique, unpredictable filename and exclusively creates it with restricted permissions. diff --git a/CHANGELOG.md b/CHANGELOG.md index b2d1d89..4951ad4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version ## [Unreleased] +### Changed +- Repo hygiene: `pytest.ini` and `.coveragerc` folded into `pyproject.toml` (`[tool.pytest.ini_options]`, `[tool.coverage.*]`); removed the `.jules/` bot-notes directory. Test/coverage behavior unchanged; sdists still carry the full test config via `pyproject.toml`. + ## [0.2.0] - 2026-07-23 ### Changed diff --git a/MANIFEST.in b/MANIFEST.in index 2ac44ab..c756621 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -16,7 +16,6 @@ include SECURITY.md include CHANGELOG.md include MANIFEST.in include pyproject.toml -include pytest.ini # Agent JSON contracts (machine + human). Not the quality/planning docs. include docs/api.md diff --git a/docs/quality-roadmap.md b/docs/quality-roadmap.md index 6467228..501d8a4 100644 --- a/docs/quality-roadmap.md +++ b/docs/quality-roadmap.md @@ -71,7 +71,7 @@ of silent rot vs the old 79 gate. ### Residual coverage policy -Integration-heavy and platform/TTY/process paths may carry `# pragma: no cover` when unit tests already cover the pure/decision branches and remaining lines are I/O loops (MQTT ack, FTPS resume, interactive wizard, Orca process). Measured coverage is computed under `.coveragerc` with those exclusions. Do not pragma pure helpers that have no tests. +Integration-heavy and platform/TTY/process paths may carry `# pragma: no cover` when unit tests already cover the pure/decision branches and remaining lines are I/O loops (MQTT ack, FTPS resume, interactive wizard, Orca process). Measured coverage is computed under `[tool.coverage.report]` in `pyproject.toml` with those exclusions. Do not pragma pure helpers that have no tests. --- diff --git a/pyproject.toml b/pyproject.toml index c7dc603..42568c4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,6 +58,36 @@ plate = "bambu_cli.bambu:main" where = ["."] include = ["bambu_cli*"] +[tool.pytest.ini_options] +testpaths = ["tests"] +# live_printer_smoke.py is collectable but marked `live` — CI and default local +# runs use `-m "not live"` so it never touches a printer without BAMBU_LIVE=1. +python_files = ["test_*.py", "live_printer_smoke.py"] +addopts = "--cov=bambu_cli --cov-report=term-missing" +markers = [ + "security: SSRF, TLS pin, archive, and other security-sensitive cases", + "contract: agent-facing JSON shape / schema contracts", + "live: requires a real printer (never run in default CI; needs BAMBU_LIVE=1)", + "slow: longer-running tests", +] + +[tool.coverage.run] +branch = true +source = ["bambu_cli"] + +[tool.coverage.report] +precision = 1 +# Honest coverage: do not hide except Exception/pass/continue. +# Only exclude lines that are definitionally unmeasurable or non-executable. +exclude_lines = [ + "pragma: no cover", + "def __repr__", + "if TYPE_CHECKING:", + "raise NotImplementedError", + "if __name__ == .__main__.:", + "\\.\\.\\.", +] + [tool.ruff] target-version = "py39" line-length = 120 diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index bbf1fae..0000000 --- a/pytest.ini +++ /dev/null @@ -1,11 +0,0 @@ -[pytest] -testpaths = tests -# live_printer_smoke.py is collectable but marked `live` — CI and default local -# runs use `-m "not live"` so it never touches a printer without BAMBU_LIVE=1. -python_files = test_*.py live_printer_smoke.py -addopts = --cov=bambu_cli --cov-report=term-missing -markers = - security: SSRF, TLS pin, archive, and other security-sensitive cases - contract: agent-facing JSON shape / schema contracts - live: requires a real printer (never run in default CI; needs BAMBU_LIVE=1) - slow: longer-running tests