Skip to content

Commit 8667441

Browse files
authored
fix: exit with a non-zero code when showing help (#2309)
Note I've purposely not used a new error code for now because I can't imagine a use-case for wanting to identify this particular situation in a scripting context, which is where exit code values are relevant (we can always use a more specific code later if a use case is presented) Resolves #2303
1 parent 8a3916c commit 8667441

File tree

12 files changed

+103
-5
lines changed

12 files changed

+103
-5
lines changed

.github/workflows/checks.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,6 @@ jobs:
177177
) | .name' output.json | while read -r image; do
178178
echo "Testing image $image"
179179
180-
docker run $image -h
181-
182180
exit_code=0
183181
docker run -v ${PWD}:/src $image -L /src/go.mod || exit_code=$?
184182

cmd/osv-scanner/__snapshots__/main_test.snap

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,29 @@ OPTIONS:
2222

2323
---
2424

25+
[Test_run/#01 - 1]
26+
NAME:
27+
osv-scanner scan - scans projects and container images for dependencies, and checks them against the OSV database.
28+
29+
USAGE:
30+
osv-scanner scan [command [command options]]
31+
32+
DESCRIPTION:
33+
scans projects and container images for dependencies, and checks them against the OSV database.
34+
35+
COMMANDS:
36+
source scans a source project's dependencies for known vulnerabilities using the OSV database.
37+
image detects vulnerabilities in a container image's dependencies, pulling the image if it's not found locally
38+
39+
OPTIONS:
40+
--help, -h show help
41+
42+
---
43+
44+
[Test_run/#01 - 2]
45+
46+
---
47+
2548
[Test_run/version - 1]
2649
osv-scanner version: 2.2.4
2750
osv-scalibr version: 0.3.6

cmd/osv-scanner/internal/cmd/run.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ func Run(args []string, stdout, stderr io.Writer, commands []CommandBuilder) int
5050
}
5151
// ---
5252

53+
cli.HelpPrinter = func(w io.Writer, templ string, data any) {
54+
cmdlogger.SetHasErrored()
55+
cli.HelpPrinterCustom(w, templ, data, nil)
56+
}
57+
5358
cli.VersionPrinter = func(cmd *cli.Command) {
5459
cmdlogger.Infof("osv-scanner version: %s", cmd.Version)
5560
cmdlogger.Infof("osv-scalibr version: %s", scalibr.ScannerVersion)

cmd/osv-scanner/main_test.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@ func Test_run(t *testing.T) {
1515
{
1616
Name: "",
1717
Args: []string{""},
18-
Exit: 0,
18+
Exit: 127,
19+
},
20+
{
21+
Name: "",
22+
Args: []string{"--help"},
23+
Exit: 127,
1924
},
2025
{
2126
Name: "version",

cmd/osv-scanner/scan/__snapshots__/command_test.snap

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,26 @@ No issues found
1111

1212
---
1313

14+
[TestCommand_SubCommands/with_no_arguments - 1]
15+
NAME:
16+
osv-scanner scan - scans projects and container images for dependencies, and checks them against the OSV database.
17+
18+
USAGE:
19+
osv-scanner scan [command [command options]]
20+
21+
DESCRIPTION:
22+
scans projects and container images for dependencies, and checks them against the OSV database.
23+
24+
COMMANDS:
25+
source scans a source project's dependencies for known vulnerabilities using the OSV database.
26+
image detects vulnerabilities in a container image's dependencies, pulling the image if it's not found locally
27+
28+
---
29+
30+
[TestCommand_SubCommands/with_no_arguments - 2]
31+
32+
---
33+
1434
[TestCommand_SubCommands/with_no_subcommand - 1]
1535
Scanning dir ./testdata/locks-many/composer.lock
1636
Scanned <rootdir>/testdata/locks-many/composer.lock file and found 1 package

cmd/osv-scanner/scan/command_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ func TestCommand_SubCommands(t *testing.T) {
1111
t.Parallel()
1212

1313
tests := []testcmd.Case{
14+
{
15+
Name: "with_no_arguments",
16+
Args: []string{"", "scan"},
17+
Exit: 127,
18+
},
1419
// without subcommands
1520
{
1621
Name: "with no subcommand",

cmd/osv-scanner/update/__snapshots__/command_test.snap

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,3 +292,23 @@ file not found: ./testdata/does_not_exist.xml
292292
</project>
293293

294294
---
295+
296+
[TestCommand/with_no_arguments - 1]
297+
NAME:
298+
osv-scanner update - [EXPERIMENTAL] scans a manifest file then updates dependencies
299+
300+
USAGE:
301+
osv-scanner update
302+
303+
OPTIONS:
304+
--manifest string, -M string path to manifest file (required)
305+
--ignore-dev whether to ignore development dependencies for updates (default: false)
306+
--upgrade-config [package-name:]level [ --upgrade-config [package-name:]level ] the allowed package upgrades, in the format [package-name:]level. If package-name is omitted, level is applied to all packages. level must be one of (major, minor, patch, none). (default: major)
307+
--data-source string source to fetch package information from; value can be: deps.dev, native (default: "deps.dev")
308+
309+
---
310+
311+
[TestCommand/with_no_arguments - 2]
312+
Required flag "manifest" not set
313+
314+
---

cmd/osv-scanner/update/command_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ func TestCommand(t *testing.T) {
1212
t.Parallel()
1313

1414
tests := []testcmd.Case{
15+
{
16+
Name: "with_no_arguments",
17+
Args: []string{"", "update"},
18+
Exit: 127,
19+
},
1520
{
1621
Name: "update pom.xml with in-place changes",
1722
Args: []string{"", "update", "-M=./testdata/pom.xml"},

internal/cmdlogger/handler.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func (c *Handler) writer(level slog.Level) io.Writer {
4646

4747
func (c *Handler) Enabled(ctx context.Context, level slog.Level) bool {
4848
if level == slog.LevelError {
49-
c.hasErrored = true
49+
c.SetHasErrored()
5050
}
5151

5252
if c.overrideHandler != nil {
@@ -58,7 +58,7 @@ func (c *Handler) Enabled(ctx context.Context, level slog.Level) bool {
5858

5959
func (c *Handler) Handle(ctx context.Context, record slog.Record) error {
6060
if record.Level == slog.LevelError {
61-
c.hasErrored = true
61+
c.SetHasErrored()
6262

6363
if strings.HasPrefix(record.Message, "Ignored invalid config file") {
6464
c.hasErroredBecauseInvalidConfig = true
@@ -74,6 +74,10 @@ func (c *Handler) Handle(ctx context.Context, record slog.Record) error {
7474
return err
7575
}
7676

77+
func (c *Handler) SetHasErrored() {
78+
c.hasErrored = true
79+
}
80+
7781
// HasErrored returns true if there have been any calls to Handle with
7882
// a level of [slog.LevelError]
7983
func (c *Handler) HasErrored() bool {

internal/cmdlogger/interface.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import "log/slog"
55
type CmdLogger interface {
66
slog.Handler
77
SendEverythingToStderr()
8+
SetHasErrored()
89
HasErrored() bool
910
HasErroredBecauseInvalidConfig() bool
1011
SetLevel(level slog.Leveler)

0 commit comments

Comments
 (0)