nboot audit --output should reject existing directories
Problem
nboot audit --output PATH accepts any path that Click's
click.Path(path_type=Path) will resolve, including an existing
directory. When the user passes a directory, the resulting
output.write_text(...) call raises IsADirectoryError with a raw
Python traceback, instead of a clean Click error explaining the
issue.
Real-world hit: writing the SARIF report into the audit's working
directory (e.g. --output reports/) silently fails after the
audit has already done all its work.
Repro
mkdir -p /tmp/some-dir
nboot audit --spec nboot-spec.json --pack base --target . \
--format sarif --output /tmp/some-dir
# Traceback (most recent call last):
# ...
# IsADirectoryError: [Errno 21] Is a directory: '/tmp/some-dir'
Proposed fix
Tighten the Click option to:
type=click.Path(dir_okay=False, file_okay=True, path_type=Path)
…in audit_cmd in src/navi_bootstrap/cli.py. Click will then emit
a clean usage-style error:
Error: Invalid value for '--output': Path '/tmp/some-dir' is a directory.
before the audit pipeline runs.
Acceptance criteria
Effort
~5 minutes — one option flag + one test.
Source
Bot review on PR #51 (Copilot, cli.py:405).
nboot audit --outputshould reject existing directoriesProblem
nboot audit --output PATHaccepts any path that Click'sclick.Path(path_type=Path)will resolve, including an existingdirectory. When the user passes a directory, the resulting
output.write_text(...)call raisesIsADirectoryErrorwith a rawPython traceback, instead of a clean Click error explaining the
issue.
Real-world hit: writing the SARIF report into the audit's working
directory (e.g.
--output reports/) silently fails after theaudit has already done all its work.
Repro
Proposed fix
Tighten the Click option to:
…in
audit_cmdinsrc/navi_bootstrap/cli.py. Click will then emita clean usage-style error:
before the audit pipeline runs.
Acceptance criteria
nboot audit --output <existing-dir>exits with a non-zeroClick usage error and never starts the audit pipeline (i.e.
run_audit()is not called; the rejection happens at Clickargument-parse time, before the spec/pack are loaded).
nboot audit --output <new-file>continues to work.nboot audit --output <existing-file>continues to work(overwrites — current behaviour).
tests/test_audit.pycovering the--output <dir>case (asserts the Click error and thatrun_auditwas not invoked, e.g. via mock).Effort
~5 minutes — one option flag + one test.
Source
Bot review on PR #51 (Copilot,
cli.py:405).