Report-related CLI controls are documented and partially parsed, but do not produce the advertised behavior. Audit ignores the output destination, check parses format and output controls but does not render a report, and the documented dependency-skip alias is missing.
Evidence
README.md:53 to README.md:55 documents JSON and Markdown output files plus a dependency-skip flag.
README.md:63 to README.md:68 says check forces machine-friendly output and supports fail conditions.
cmd/license-tool/commands.go:73 to cmd/license-tool/commands.go:80 stores format, output, dependency, resolver, and fail-on flags.
cmd/license-tool/commands.go:98 to cmd/license-tool/commands.go:107 always renders audit to stdout.
cmd/license-tool/commands.go:120 to cmd/license-tool/commands.go:142 calls report.Check and exits without rendering.
cmd/license-tool/commands.go:151 to cmd/license-tool/commands.go:157 binds only a positive dependency boolean, not the documented dependency-skip alias.
Reproduction
Run audit with JSON format and an output path.
Observe that JSON is printed to stdout and the output file is not created.
Run check with JSON format on a passing tree.
Observe no report output.
Run audit with the documented dependency-skip alias.
Observe a usage failure.
Why It Matters
Report-file workflows, CI artifacts, and machine-readable check output are part of the public CLI contract. Scripts depending on those options cannot currently use the tool as documented.
Suggested Fix
Centralize report rendering for audit and check. Honor output destinations, add the documented dependency-skip alias or remove it from docs, and add command tests for each advertised output path.
## Finding
Report-related CLI controls are documented and partially parsed, but do not produce the advertised behavior. Audit ignores the output destination, check parses format and output controls but does not render a report, and the documented dependency-skip alias is missing.
## Evidence
- `README.md:53` to `README.md:55` documents JSON and Markdown output files plus a dependency-skip flag.
- `README.md:63` to `README.md:68` says `check` forces machine-friendly output and supports fail conditions.
- `cmd/license-tool/commands.go:73` to `cmd/license-tool/commands.go:80` stores format, output, dependency, resolver, and fail-on flags.
- `cmd/license-tool/commands.go:98` to `cmd/license-tool/commands.go:107` always renders audit to stdout.
- `cmd/license-tool/commands.go:120` to `cmd/license-tool/commands.go:142` calls `report.Check` and exits without rendering.
- `cmd/license-tool/commands.go:151` to `cmd/license-tool/commands.go:157` binds only a positive dependency boolean, not the documented dependency-skip alias.
## Reproduction
1. Run audit with JSON format and an output path.
2. Observe that JSON is printed to stdout and the output file is not created.
3. Run check with JSON format on a passing tree.
4. Observe no report output.
5. Run audit with the documented dependency-skip alias.
6. Observe a usage failure.
## Why It Matters
Report-file workflows, CI artifacts, and machine-readable check output are part of the public CLI contract. Scripts depending on those options cannot currently use the tool as documented.
## Suggested Fix
Centralize report rendering for audit and check. Honor output destinations, add the documented dependency-skip alias or remove it from docs, and add command tests for each advertised output path.
Status: confirmed — all three sub-claims reproduce against the current tree (built dev, SPDX list 3dfd9aa): --output is silently ignored, check renders no report, and --no-deps is unbound.
Severity: high (matches the bug label, raised within bug's range). This is a broken-public-contract defect, not a crash: three documented CLI behaviors are non-functional and one (--no-deps) is a hard usage error (exit 2). No data loss, so not critical — but CI artifact and machine-readable-check workflows are unusable as documented.
Verified root cause (exact locations):
--output ignored (audit):cmd/license-tool/commands.go:bindAuditFlags:154 binds &f.output, but f.output is read nowhere — newAuditCmd's RunE at commands.go:107 hardcodes report.Render(cmd.OutOrStdout(), r, format). grep confirms line 154 is the only reference to f.output in the package.
check renders nothing:report.Check (internal/report/report.go:Check:377-386) returns only (exitCode int, err error) and never renders. The checkRunE (commands.go:newCheckCmd:130-142) consumes only code, calls os.Exit(code) on non-zero, and returns — so --format/--output for check are parsed and discarded. Reproduced: check --format json emitted 0 bytes.
--no-deps missing:bindAuditFlags:155 binds only --deps (BoolVar, default true). There is no negative alias. Reproduced: audit --no-deps exits 2 (unknown flag).
audit --format json --output audit.json . → exit 0, audit.json NOT created, JSON printed to stdout.
check --format json . → 0 bytes of report output.
audit --no-deps . → exit 2.
Suggested fix:
Centralize a writer-selection helper shared by audit and check: when f.output != "", open the file (os.Create) and render to it (close/error-handle); else cmd.OutOrStdout(). Apply at commands.go:107 (audit) and add an equivalent render step in check after the policy decision.
Make check actually render. report.Check currently throws away the model.Report. Cleanest path: have check call report.Audit for the report, render it (honoring --format/--output), then derive the exit code (extract the pass/fail logic from report.Check:382-385 into an exported predicate, or change Check to return (model.Report, int, error)). Keep the os.Exit(1) gate on failure.
--no-deps: prefer adding the alias over editing docs, since both README.md:55 and docs/license-tool-design.md:25 advertise --deps|--no-deps. cobra's BoolVar does not auto-generate a --no- form; register an explicit --no-deps (or use the --deps/--no-deps pair pattern) and reconcile it with the existing --deps default-true so the two cannot contradict.
Like the v0.2.1 universal-shebang fix touched both the render INSERT path and the detect boundary, this fix must touch both command paths (newAuditCmd and newCheckCmd) consistently — fixing only audit would leave check still silent. (No filetype table is involved here; that caveat applies to header-boundary bugs, not these CLI-wiring defects.)
100% gate: add command-level tests in cmd/license-tool (or extend internal/report tests) covering: --output writes a file and stdout stays empty; check --format json emits a report on both pass and fail; --no-deps parses and disables dep resolution. The new file-open and writer-selection branches and the check render branch must each be exercised to keep .testcoverage.yml green.
Corrections to the issue: minor only.
The body calls --no-deps a "dependency-skip alias." It is documented as the negative half of the --deps|--no-deps pair (README:55, design doc:25), not strictly an "alias" — functionally equivalent, but the fix is "add the negative flag," not "alias an existing one."
The reproduction frames check's gap as "no report output" on a passing tree; the missing-render defect is unconditional (it never renders on pass or fail). My passing-config repro actually exited 1 due to policy, yet still produced 0 bytes — confirming the render gap is independent of pass/fail, slightly broader than the body implies.
Otherwise all line references (commands.go:73-80, 98-107, 120-142, 151-157) and the README references are accurate.
Open questions (maintainer must decide):
For check, should the rendered report always print, or only when --output/non-default --format is given? Today check is silent-by-design as a pure gate; rendering changes its stdout contract for existing CI consumers.
--no-deps vs --deps=false semantics: keep both and define precedence if both are passed, or replace the default-true --deps with the explicit pair?
Should --output failures (unwritable path) map to exit 4 (internal) or 2 (usage)? The documented exit-code table (README:113-121) doesn't cover this.
Overlaps: none found in the cited code. If a sibling issue tracks check's exit-code/output contract, this should be coordinated with it; I did not enumerate the full issue list.
Automated maintainer review.
**Status**: confirmed — all three sub-claims reproduce against the current tree (built `dev`, SPDX list `3dfd9aa`): `--output` is silently ignored, `check` renders no report, and `--no-deps` is unbound.
**Severity**: high (matches the `bug` label, raised within `bug`'s range). This is a broken-public-contract defect, not a crash: three documented CLI behaviors are non-functional and one (`--no-deps`) is a hard usage error (exit 2). No data loss, so not critical — but CI artifact and machine-readable-check workflows are unusable as documented.
**Verified root cause** (exact locations):
- **`--output` ignored (audit):** `cmd/license-tool/commands.go:bindAuditFlags:154` binds `&f.output`, but `f.output` is read nowhere — `newAuditCmd`'s `RunE` at `commands.go:107` hardcodes `report.Render(cmd.OutOrStdout(), r, format)`. `grep` confirms line 154 is the only reference to `f.output` in the package.
- **`check` renders nothing:** `report.Check` (`internal/report/report.go:Check:377-386`) returns only `(exitCode int, err error)` and never renders. The `check` `RunE` (`commands.go:newCheckCmd:130-142`) consumes only `code`, calls `os.Exit(code)` on non-zero, and returns — so `--format`/`--output` for `check` are parsed and discarded. Reproduced: `check --format json` emitted 0 bytes.
- **`--no-deps` missing:** `bindAuditFlags:155` binds only `--deps` (`BoolVar`, default `true`). There is no negative alias. Reproduced: `audit --no-deps` exits 2 (unknown flag).
**Reproduction confirmed** (temp dir, MIT/notice config):
1. `audit --format json --output audit.json .` → exit 0, `audit.json` NOT created, JSON printed to stdout.
2. `check --format json .` → 0 bytes of report output.
3. `audit --no-deps .` → exit 2.
**Suggested fix**:
- Centralize a writer-selection helper shared by `audit` and `check`: when `f.output != ""`, open the file (`os.Create`) and render to it (close/error-handle); else `cmd.OutOrStdout()`. Apply at `commands.go:107` (audit) and add an equivalent render step in `check` after the policy decision.
- Make `check` actually render. `report.Check` currently throws away the `model.Report`. Cleanest path: have `check` call `report.Audit` for the report, render it (honoring `--format`/`--output`), then derive the exit code (extract the pass/fail logic from `report.Check:382-385` into an exported predicate, or change `Check` to return `(model.Report, int, error)`). Keep the `os.Exit(1)` gate on failure.
- `--no-deps`: prefer adding the alias over editing docs, since both `README.md:55` and `docs/license-tool-design.md:25` advertise `--deps|--no-deps`. cobra's `BoolVar` does not auto-generate a `--no-` form; register an explicit `--no-deps` (or use the `--deps`/`--no-deps` pair pattern) and reconcile it with the existing `--deps` default-true so the two cannot contradict.
- Like the v0.2.1 universal-shebang fix touched **both** the render INSERT path and the detect boundary, this fix must touch **both** command paths (`newAuditCmd` and `newCheckCmd`) consistently — fixing only `audit` would leave `check` still silent. (No filetype table is involved here; that caveat applies to header-boundary bugs, not these CLI-wiring defects.)
- 100% gate: add command-level tests in `cmd/license-tool` (or extend `internal/report` tests) covering: `--output` writes a file and stdout stays empty; `check --format json` emits a report on both pass and fail; `--no-deps` parses and disables dep resolution. The new file-open and writer-selection branches and the `check` render branch must each be exercised to keep `.testcoverage.yml` green.
**Corrections to the issue**: minor only.
- The body calls `--no-deps` a "dependency-skip alias." It is documented as the negative half of the `--deps|--no-deps` pair (README:55, design doc:25), not strictly an "alias" — functionally equivalent, but the fix is "add the negative flag," not "alias an existing one."
- The reproduction frames check's gap as "no report output" on a *passing* tree; the missing-render defect is unconditional (it never renders on pass or fail). My passing-config repro actually exited 1 due to policy, yet still produced 0 bytes — confirming the render gap is independent of pass/fail, slightly broader than the body implies.
- Otherwise all line references (`commands.go:73-80`, `98-107`, `120-142`, `151-157`) and the README references are accurate.
**Open questions** (maintainer must decide):
- For `check`, should the rendered report always print, or only when `--output`/non-default `--format` is given? Today check is silent-by-design as a pure gate; rendering changes its stdout contract for existing CI consumers.
- `--no-deps` vs `--deps=false` semantics: keep both and define precedence if both are passed, or replace the default-true `--deps` with the explicit pair?
- Should `--output` failures (unwritable path) map to exit 4 (internal) or 2 (usage)? The documented exit-code table (README:113-121) doesn't cover this.
**Overlaps**: none found in the cited code. If a sibling issue tracks `check`'s exit-code/output contract, this should be coordinated with it; I did not enumerate the full issue list.
_Automated maintainer review._
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Finding
Report-related CLI controls are documented and partially parsed, but do not produce the advertised behavior. Audit ignores the output destination, check parses format and output controls but does not render a report, and the documented dependency-skip alias is missing.
Evidence
README.md:53toREADME.md:55documents JSON and Markdown output files plus a dependency-skip flag.README.md:63toREADME.md:68sayscheckforces machine-friendly output and supports fail conditions.cmd/license-tool/commands.go:73tocmd/license-tool/commands.go:80stores format, output, dependency, resolver, and fail-on flags.cmd/license-tool/commands.go:98tocmd/license-tool/commands.go:107always renders audit to stdout.cmd/license-tool/commands.go:120tocmd/license-tool/commands.go:142callsreport.Checkand exits without rendering.cmd/license-tool/commands.go:151tocmd/license-tool/commands.go:157binds only a positive dependency boolean, not the documented dependency-skip alias.Reproduction
Why It Matters
Report-file workflows, CI artifacts, and machine-readable check output are part of the public CLI contract. Scripts depending on those options cannot currently use the tool as documented.
Suggested Fix
Centralize report rendering for audit and check. Honor output destinations, add the documented dependency-skip alias or remove it from docs, and add command tests for each advertised output path.
Status: confirmed — all three sub-claims reproduce against the current tree (built
dev, SPDX list3dfd9aa):--outputis silently ignored,checkrenders no report, and--no-depsis unbound.Severity: high (matches the
buglabel, raised withinbug's range). This is a broken-public-contract defect, not a crash: three documented CLI behaviors are non-functional and one (--no-deps) is a hard usage error (exit 2). No data loss, so not critical — but CI artifact and machine-readable-check workflows are unusable as documented.Verified root cause (exact locations):
--outputignored (audit):cmd/license-tool/commands.go:bindAuditFlags:154binds&f.output, butf.outputis read nowhere —newAuditCmd'sRunEatcommands.go:107hardcodesreport.Render(cmd.OutOrStdout(), r, format).grepconfirms line 154 is the only reference tof.outputin the package.checkrenders nothing:report.Check(internal/report/report.go:Check:377-386) returns only(exitCode int, err error)and never renders. ThecheckRunE(commands.go:newCheckCmd:130-142) consumes onlycode, callsos.Exit(code)on non-zero, and returns — so--format/--outputforcheckare parsed and discarded. Reproduced:check --format jsonemitted 0 bytes.--no-depsmissing:bindAuditFlags:155binds only--deps(BoolVar, defaulttrue). There is no negative alias. Reproduced:audit --no-depsexits 2 (unknown flag).Reproduction confirmed (temp dir, MIT/notice config):
audit --format json --output audit.json .→ exit 0,audit.jsonNOT created, JSON printed to stdout.check --format json .→ 0 bytes of report output.audit --no-deps .→ exit 2.Suggested fix:
auditandcheck: whenf.output != "", open the file (os.Create) and render to it (close/error-handle); elsecmd.OutOrStdout(). Apply atcommands.go:107(audit) and add an equivalent render step incheckafter the policy decision.checkactually render.report.Checkcurrently throws away themodel.Report. Cleanest path: havecheckcallreport.Auditfor the report, render it (honoring--format/--output), then derive the exit code (extract the pass/fail logic fromreport.Check:382-385into an exported predicate, or changeCheckto return(model.Report, int, error)). Keep theos.Exit(1)gate on failure.--no-deps: prefer adding the alias over editing docs, since bothREADME.md:55anddocs/license-tool-design.md:25advertise--deps|--no-deps. cobra'sBoolVardoes not auto-generate a--no-form; register an explicit--no-deps(or use the--deps/--no-depspair pattern) and reconcile it with the existing--depsdefault-true so the two cannot contradict.newAuditCmdandnewCheckCmd) consistently — fixing onlyauditwould leavecheckstill silent. (No filetype table is involved here; that caveat applies to header-boundary bugs, not these CLI-wiring defects.)cmd/license-tool(or extendinternal/reporttests) covering:--outputwrites a file and stdout stays empty;check --format jsonemits a report on both pass and fail;--no-depsparses and disables dep resolution. The new file-open and writer-selection branches and thecheckrender branch must each be exercised to keep.testcoverage.ymlgreen.Corrections to the issue: minor only.
--no-depsa "dependency-skip alias." It is documented as the negative half of the--deps|--no-depspair (README:55, design doc:25), not strictly an "alias" — functionally equivalent, but the fix is "add the negative flag," not "alias an existing one."commands.go:73-80,98-107,120-142,151-157) and the README references are accurate.Open questions (maintainer must decide):
check, should the rendered report always print, or only when--output/non-default--formatis given? Today check is silent-by-design as a pure gate; rendering changes its stdout contract for existing CI consumers.--no-depsvs--deps=falsesemantics: keep both and define precedence if both are passed, or replace the default-true--depswith the explicit pair?--outputfailures (unwritable path) map to exit 4 (internal) or 2 (usage)? The documented exit-code table (README:113-121) doesn't cover this.Overlaps: none found in the cited code. If a sibling issue tracks
check's exit-code/output contract, this should be coordinated with it; I did not enumerate the full issue list.Automated maintainer review.
Resolved on
developin commit742c124e6ec2afa9312075db3112bc2def3c91ff.Validation:
Closing as fixed.