Skip to content

feat(cli): align --output parent-dir handling and add behavior --sbom (#233) - #242

Open
nikhilpatidar wants to merge 2 commits into
NuGuardAI:developfrom
nikhilpatidar:feat/cli-flag-alignment
Open

feat(cli): align --output parent-dir handling and add behavior --sbom (#233)#242
nikhilpatidar wants to merge 2 commits into
NuGuardAI:developfrom
nikhilpatidar:feat/cli-flag-alignment

Conversation

@nikhilpatidar

@nikhilpatidar nikhilpatidar commented Aug 10, 2026

Copy link
Copy Markdown

PR Type

  • Bug fix
  • Feature

Fixes #233.

Three CLI commands (nuguard analyze, nuguard redteam, nuguard behavior) needed --output to create its parent directory automatically when it didn't exist, and behavior was missing an --sbom flag consistent with the other commands.

Changes

  • nuguard/cli/commands/analyze.py — create parent dir before writing output
  • nuguard/cli/commands/redteam.py — create parent dir before writing output
  • nuguard/cli/commands/behavior.py — add --sbom flag, create parent dir before writing output

Tests

  • tests/cli/test_output_parent_dir.py — 5 tests covering each command's parent-dir handling and the behavior --sbom flag

Closes #233

…behavior --sbom

Analyze and redteam previously crashed with FileNotFoundError when the
parent directory of --output did not exist, while behavior silently
auto-created it. Normalize all three commands to behavior's contract.

Also add a --sbom flag to behavior so the SBOM can be supplied on the
CLI, matching the analyze / redteam subcommands. CLI --sbom overrides
sbom: in nuguard.yaml.
@nikhilpatidar
nikhilpatidar force-pushed the feat/cli-flag-alignment branch from 15b038c to 6b56d7e Compare August 10, 2026 15:33

@KanishkThamman KanishkThamman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The --output parent-dir fix (analyze/redteam) is correct and safe. Holding off approval because the headline feature, behavior --sbom, doesn't actually work yet — see inline comments. The two new tests for it pass anyway because their assertions are vacuous (or-chained / exit-code-only), so this shipped silently broken.

config: Optional[Path] = typer.Option(
None, "--config", "-c", help="Path to nuguard.yaml"
),
sbom: Optional[str] = typer.Option(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This flag is never forwarded to _run_behavior() — the call site's kwargs don't include it, so the CLI value is discarded.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in d96b39a. Threaded into _run_behavior() via a dedicated sbom_override: Optional[str] parameter and passed from the call site; the orchestrator now uses sbom_override or cfg.sbom_path so the CLI value wins over the config fallback.

Comment thread nuguard/cli/commands/behavior.py Outdated
sbom = None
sbom_path_obj: Path | None = None
raw_sbom_path = cfg.sbom_path
raw_sbom_path = sbom or cfg.sbom_path

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sbom here refers to the local sbom = None two lines above (the parsed SBOM doc), not the new CLI flag — this always evaluates to cfg.sbom_path. Needs a dedicated param (e.g. sbom_override) threaded through _run_behavior()'s signature and the call site.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in d96b39a. Renamed the local parsed-SBOM variable's shadowing behavior away from the path: the new sbom_override parameter on _run_behavior() is used in raw_sbom_path = sbom_override or cfg.sbom_path. The two --sbom tests now assert the literal 'Loaded SBOM: ' log line and the resolved path, so they fail (not vacuously pass) if the wiring breaks again.

The --sbom flag on 'nuguard behavior' was declared on the CLI but
its value was never forwarded to _run_behavior(): the call site
kwargs omitted it, and the orchestrator's local `sbom = None` (the
parsed SBOM doc) shadowed the intended value, so `raw_sbom_path =
sbom or cfg.sbom_path` always fell back to the config path. The
two new tests that were meant to cover the flag passed anyway
because their assertions were vacuous (or-chained / exit-code-only).

Fix:
- Add a dedicated `sbom_override: Optional[str]` parameter to
  _run_behavior() and pass it from the CLI entrypoint.
- Use `sbom_override or cfg.sbom_path` so the CLI override wins
  over the config-file fallback.
- Strengthen the two --sbom tests to assert the literal 'Loaded SBOM:'
  log line and the resolved path, so they fail — not vacuously pass —
  if the flag is dropped again. Whitespace is normalized because Rich
  soft-wraps long paths and may insert a space inside the path.
- Drop a pre-existing unused `import json` left over from the
  previous commit on this branch so ruff stays clean in CI.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants