fix(cli): validate required args before running --diagnostic#741
fix(cli): validate required args before running --diagnostic#741
Conversation
- Add early `zip` preflight in diagnostic collection script (with install hints) - Hard-error on Windows when `--diagnostic` is used (exit code 2) - Clarify `--diagnostic` help text as Linux/macOS-only - Add unit test to ensure Windows gating avoids running subprocess
Handle --diagnostic inside main() after Typer/Click parsing so missing required options (-d/-t) fail normally. Run the diagnostic script via run_diagnostic() and exit with its return code; hard-error on Windows.
Add targeted `type: ignore[unreachable]` on assertions after calling run_diagnostic (annotated NoReturn) inside pytest.raises blocks, so the pre-commit mypy hook passes.
Introduce base_argv/base_argv_with_spaces fixtures and tighten reconstruct tests to assert shlex round-trips exactly. Reuse base_argv in TestRunDiagnostic to avoid ad-hoc argv construction.
Create the diagnostic zip from the parent directory so the archive contains only the diagnostic folder (no full /var/... path prefixes).
Require the nac-test command to be passed as a single quoted argument ($1) and fail fast otherwise. Also clarify the log message that nac-test output is not shown on screen and is written to 100_nac_test_execution.txt.
Compute Robot Framework output file list once from $OUTPUT_DIR/robot_results and reuse it for both logging and copying, avoiding duplicate filesystem scans.
aitestino
left a comment
There was a problem hiding this comment.
Hey @oboehmer, thank you for the PR -- this is a well-motivated fix that addresses a real usability gap. Moving --diagnostic out of the eager Typer callback and into main() so required args get validated first is exactly the right architectural call, and it eliminates ~35 lines of hand-rolled argument parsing (_extract_output_dir) that was duplicating what Typer already does. The $1 enforcement in the shell script, the zip preflight check, the relative archive paths, and the PIPESTATUS[0] bug fix are all genuine improvements. Clean PR overall.
I did a couple of reviews on this, and I think we need some small changes before merge. The core design is sound -- these are all polish items.
Things that need adjustment:
-
ctx.command_pathvssys.argv[0]in the argv reconstruction --run_diagnostic(output, argv=[ctx.command_path, *sys.argv[1:]])uses the bare namenac-testrather than the full path thatsys.argv[0]would provide (e.g.,/home/user/.venv/bin/nac-test). The diagnostic script re-executes viabash -c, which relies on PATH resolution. In CI environments, Docker containers, or improperly exported virtualenvs, the bare name may not resolve. Since_reconstruct_commandalready strips--diagnosticfrom whatever argv it receives, passingsys.argvdirectly would work and be more robust. That said,ctx.command_pathis arguably more portable for the general case -- I'd like to hear your reasoning on this one. -
Subprocess call argument assertions dropped from tests -- The previous
test_true_with_output_dir_runs_scriptverifiedcall_args[0] == "bash"and"nac-test-diagnostic.sh" in call_args[1]. The newtest_propagates_script_exit_codeonly checksmock_run.assert_called_once()without inspecting what it was called with. A regression that changes the argument order, drops-o, or passesoutput_diras aPathobject instead of a string would go undetected. Worth restoring those assertions. -
Missing return type annotations on new test methods -- The existing test methods in this file consistently annotate
-> None. The newTestRunDiagnosticmethods drop them:def test_windows_errors_without_running_script(self, base_argv): # missing -> None def test_propagates_script_exit_code(self, mock_run, base_argv): # missing -> None + MagicMock type
-
run_diagnosticdocstring has a multi-line opening sentence -- The summary line wraps across two lines. The convention elsewhere in the file is a single-line summary followed by a blank line:"""Run the diagnostic collection shell script. Wraps nac-test execution with pre/post environment capture and log collection.
-
_reconstruct_commanddocstring stripped -- The full docstring with Args/Returns sections was replaced with a bare one-liner. Looking at_find_diagnostic_scriptright above it, which has the full treatment, restoring at least Args and Returns would keep it consistent. -
Missing class docstring on
TestRunDiagnostic--TestReconstructCommandandTestFindDiagnosticScriptboth have class docstrings. Adding"""Tests for run_diagnostic function."""would keep it consistent.
I'd consider items 1-3 as things to address before merge -- they're all quick fixes. Items 4-6 are docstring polish and could be follow-ups if you'd rather not hold this up further.
What do you think?
P.S. -- This comment was drafted using voice-to-text via Claude Code. If the tone comes across as overly direct or terse, please know that's just how it tends to phrase things. No offense or criticism is intended -- this is purely an objective technical review of the PR. Thanks for understanding!
Use sys.argv directly instead of [ctx.command_path, *sys.argv[1:]] so the diagnostic script receives the full invocation path (e.g. /home/user/.venv/bin/nac-test) rather than the bare command name. This is more robust for bash -c re-execution in virtualenvs and CI environments.
Verify that subprocess.run receives the correct argument structure: bash, script path, -o flag, and output directory. Prevents regressions that change argument order or drop required flags from going undetected.
Reformat the opening sentence to a single-line summary followed by a blank line and extended description, matching the file's convention (see _find_diagnostic_script).
Add Args and Returns sections to match the docstring style of _find_diagnostic_script and other functions in the module.
Consistent with TestReconstructCommand and TestFindDiagnosticScript which both have class-level docstrings.
|
Thanks for the thorough review! Addressed in individual commits: 1. 2. Subprocess call assertions — Restored assertions verifying 3. Missing 4. Multi-line docstring opening — Fixed to single-line summary + blank line + details, matching the file's convention. → d1d32cb 5. 6. |
Description
This PR improves
--diagnosticbehavior and the bundled diagnostic collection script to make diagnostics safer, more accurate, and easier to consume.CLI
--diagnosticbehavior (Fixes #740)--diagnostichandling out of the Typer callback and intonac_test/cli/main.pyso required args are validated by Typer/Click before diagnostics run.run_diagnostic(...)(annotatedNoReturn) that runs the diagnostic script and exits with the script’s return code.--diagnostic.Diagnostic script improvements (Fixes #664 + follow-ups)
zipcommand is missing (observed on WSL2 environment)PIPESTATUSusage)./var/...prefixes in the archive contents).pyats version checkinstead ofpyats.__version__for reliable version capture.$1) and enforce the contract.$OUTPUT_DIR/robot_results, and collect robot outputs via a singlefindpass.Tests
tests/unit/cli/test_diagnostic.pyto match the newrun_diagnosticentrypoint._reconstruct_commandcoverage with strictshlex.join/shlex.splitround-trip assertions.NoReturninpytest.raises.Closes
Type of Change
Test Framework Affected
NaC Architecture Affected
Platform Tested
Key Changes
--diagnosticno longer bypasses missing options).Testing Done
pytest/pre-commit run -a)Test Commands Used
Additional Notes
shlex.join), and the script enforces that it receives exactly one command argument.$OUTPUT_DIR/robot_results.