module
Noir::CLI::ScanCommand
Overview
noir scan [paths...] [flags]
Discovers endpoints across one or more code bases. Positional paths
augment any -b PATH flags so both v0 and v1 invocation styles work:
noir scan ./app # v1 positional noir scan ./api ./worker # v1 multi-path positional noir -b ./app # v0 (router default-routes to scan) noir scan -b ./app --passive # v1 explicit + flags
Defined in:
cli/commands/scan.crConstant Summary
-
PROMPT_OVERRIDE_SETTERS =
{"override_filter_prompt" => ->(v : String) do LLM::PromptOverrides.filter_prompt = v end, "override_analyze_prompt" => ->(v : String) do LLM::PromptOverrides.analyze_prompt = v end, "override_bundle_analyze_prompt" => ->(v : String) do LLM::PromptOverrides.bundle_analyze_prompt = v end, "override_llm_optimize_prompt" => ->(v : String) do LLM::PromptOverrides.llm_optimize_prompt = v end} -
WARNING_COLOR =
Colorize::Color256.new(208) -
ANSI 256-color orange used for the protocol-missing warning. Kept as a named constant so the call site reads as "warning color" rather than a bare magic number.
Class Method Summary
-
.cli_flag_names(argv : Array(String)) : Set(String)
Long-flag tokens present on the command line, with
--flag=valuereduced to--flag. -
.glob_error(pattern : String) : String | Nil
Returns nil for a usable glob, otherwise the reason it is broken.
-
.host_error(host : String | Nil) : String | Nil
Why
-uneeds an authority, not just a scheme: it is the base URL every discovered path is appended to. - .run(argv : Array(String))
-
.scan_exit_code(app : NoirRunner, app_diff : NoirRunner | Nil) : Int32
Exit code for a scan that produced its report.
Class Method Detail
Long-flag tokens present on the command line, with --flag=value
reduced to --flag. The only question asked of it is "did the user
type this flag?", which is why the values are dropped.
Returns nil for a usable glob, otherwise the reason it is broken.
File.match? parses the pattern itself, so character-class errors
come back from Crystal with its own wording. Brace groups it accepts
and then never matches (*.{rb matches nothing at all), so the
{/} balance is checked here — skipping over character classes,
inside which a brace is an ordinary character.
Why -u needs an authority, not just a scheme: it is the base URL
every discovered path is appended to. URI.parse is happy without a
host — -u http:// parses with an empty one — and the concatenation
then promotes the first discovered path segment to the authority, so
/a becomes http://a. With --probe or --status-codes that
fires real HTTP requests at a host the user never named.
Whitespace and control characters are rejected for the same reason
normalize_probe_via! rejects a missing host: -u "not a url" and
-u $'http://a\nb/' are accepted today and baked into every endpoint
of the JSON/OAS/Postman output as an unusable URL.
Returns nil when the host is usable, otherwise the reason (phrased to
slot into the -u/--url <reason> in <url> message).
Exit code for a scan that produced its report.
Exit 2 rather than 1 so a CI gate can tell "scan ran, coverage incomplete" from the usage/validation errors that already exit 1.
degraded used to read !app.analyzer_failures.empty? when that list
held tech-level analyzer failures and nothing else, so --strict — whose
documented contract is "exit 2 if any analyzer failed or skipped a
file" — reported green on a scan that lost a whole subtree to an
unlistable directory, dropped every symlinked package, exported nothing,
or ran zero passive rules. Every one of those now feeds the same list, so
the test is unchanged and finally means what it says.