Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,20 @@ Current section mappings:
- `compute`: `vms`
- `core`: `inventory`

## Help

AzureFox supports generic and scoped help:

```bash
azurefox help
azurefox help identity
azurefox help permissions
azurefox -h identity
azurefox -h permissions
```

Command help includes ATT&CK cloud leads as investigative context so users can map the output to likely tactics and techniques without treating the help text as proof that a technique occurred.

## Fixture Mode

Set `AZUREFOX_FIXTURE_DIR` to run against local fixture files rather than Azure APIs.
Expand Down
24 changes: 24 additions & 0 deletions src/azurefox/cli.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
from __future__ import annotations

import sys
from pathlib import Path

import typer

from azurefox.collectors.provider import get_provider
from azurefox.config import GlobalOptions
from azurefox.errors import AzureFoxError
from azurefox.help import render_help
from azurefox.models.common import OutputMode
from azurefox.models.run import AllChecksSummary, RunCommandResult
from azurefox.output.style import emit_artifact_paths, emit_command_status, emit_context_banner
Expand Down Expand Up @@ -163,6 +165,15 @@ def all_checks(
raise typer.Exit(code=1)


@app.command("help")
def help_command(topic: str | None = typer.Argument(None)) -> None:
try:
typer.echo(render_help(topic))
except ValueError as exc:
typer.echo(str(exc), err=True)
raise typer.Exit(code=2) from exc


def _run_single(ctx: typer.Context, command: str) -> None:
options: GlobalOptions = ctx.obj
try:
Expand All @@ -185,6 +196,7 @@ def _run_single(ctx: typer.Context, command: str) -> None:


def main() -> None:
sys.argv = _normalize_argv(sys.argv)
app()


Expand All @@ -195,3 +207,15 @@ def _build_metadata(command: str, options: GlobalOptions) -> dict[str, str | Non
"subscription_id": options.subscription,
"token_source": None,
}


def _normalize_argv(argv: list[str]) -> list[str]:
if len(argv) < 2:
return argv

if argv[1] in {"-h", "--help"}:
if len(argv) == 2:
return [argv[0], "help"]
return [argv[0], "help", argv[2]]

return argv
Loading
Loading