Repository: google/osv-scanner
Pull request #555 (2023-09-26 20:27:48)

chore: move scripts into the `scripts` directory
We spoke about this a few weeks ago but I never got around to actioning it - overall I've tried to kept it light since this is more about keeping things tidy than committing to a long-term structure.


Patch:
diff --git a/.github/workflows/lint.yaml b/.github/workflows/checks.yml
similarity index 71%
rename from .github/workflows/lint.yaml
rename to .github/workflows/checks.yml
index a616a49..fed714b 100644
--- a/.github/workflows/lint.yaml
+++ b/.github/workflows/checks.yml
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-name: lint
+name: Checks
 
 on:
   push:
@@ -43,3 +43,19 @@ jobs:
           check-latest: true
       - name: Run lint action
         uses: ./.github/workflows/lint-action
+  test:
+    name: Run unit tests
+    runs-on: ubuntu-latest
+    steps:
+      - name: Check out code
+        uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
+        with:
+          persist-credentials: false
+          fetch-depth: 0
+      - name: Set up Go
+        uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
+        with:
+          go-version: '1.19'
+          check-latest: true
+      - name: Run test action
+        uses: ./.github/workflows/test-action
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d9226d0..90a9c25 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -34,9 +34,12 @@ Please review the documentation [README](docs/README.md) for more information ab
 
 ### Prerequisites
 Install:
-1. [Go](https://go.dev/) 1.18+, use `go version` to check.
+1. [Go](https://go.dev/) 1.19+, use `go version` to check.
 2. [GoReleaser](https://goreleaser.com/) (Optional, only if you want reproducible builds).
-3. [golangci-lint](https://golangci-lint.run/) (Optional, only if you want to run the linters locally)
+
+> **Note**
+>
+> The scripts within `/scripts` expect to be run from the root of the repository
 
 ### Building
 
@@ -44,7 +47,7 @@ Install:
 
 Run the following in the project directory:
 ```shell
-$ go build ./cmd/osv-scanner/
+./scripts/build.sh
 ```
 Produces `osv-scanner` binary in the project directory.
 
@@ -52,7 +55,7 @@ Produces `osv-scanner` binary in the project directory.
 
 Run the following in the project directory:
 ```shell
-$ goreleaser build --rm-dist --single-target --snapshot
+./scripts/build_snapshot.sh
 ```
 
 See GoReleaser [documentation](https://goreleaser.com/cmd/goreleaser_build/) for build options.
@@ -64,20 +67,20 @@ using the same Go version as the one used during the actual release (see gorelea
 
 To run tests:
 ```shell
-./run_tests.sh
+./scripts/run_tests.sh
 ```
 
-You can generate an HTML coverage report afterward by running:
+You can generate an HTML coverage report by running:
 
-```
-go tool cover -html=coverage.out -o coverage.html
+```shell
+./scripts/generate_coverage_report.sh
 ```
 
 ### Linting
 To lint your code, run
 
 ```shell
-./run_lints.sh
+./scripts/run_lints.sh
 ```
 
 ## Contributing documentation
diff --git a/scripts/build.sh b/scripts/build.sh
new file mode 100755
index 0000000..9b482d2
--- /dev/null
+++ b/scripts/build.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+set -e
+
+go build ./cmd/osv-scanner/
diff --git a/scripts/build_snapshot.sh b/scripts/build_snapshot.sh
new file mode 100755
index 0000000..dd5d0bd
--- /dev/null
+++ b/scripts/build_snapshot.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+set -e
+
+goreleaser build --rm-dist --single-target --snapshot
diff --git a/scripts/generate_coverage_report.sh b/scripts/generate_coverage_report.sh
new file mode 100755
index 0000000..be736c3
--- /dev/null
+++ b/scripts/generate_coverage_report.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+set -e
+
+./scripts/run_tests.sh
+
+go tool cover -html=coverage.out -o coverage.html


Test patch:
diff --git a/.github/workflows/test-action/action.yml b/.github/workflows/test-action/action.yml
index 36d5e12..a66778c 100644
--- a/.github/workflows/test-action/action.yml
+++ b/.github/workflows/test-action/action.yml
@@ -20,6 +20,6 @@ runs:
   steps:
     - name: Run go test
       shell: bash
-      run: ./run_tests.sh
+      run: ./scripts/run_tests.sh
     - name: Upload coverage to Codecov
       uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # v3.1.4
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
deleted file mode 100644
index de4a180..0000000
--- a/.github/workflows/test.yml
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright 2023 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-name: test
-
-on:
-  push:
-    branches: [ main ]
-  pull_request:
-    # The branches below must be a subset of the branches above
-    branches: [ main ]
-  merge_group:
-    branches: [ main ]
-
-permissions:
-  contents: read # to fetch code (actions/checkout)
-
-jobs:
-  lint:
-    name: Run unit tests
-    runs-on: ubuntu-latest
-    steps:
-      - name: Check out code
-        uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
-        with:
-          persist-credentials: false
-          fetch-depth: 0
-      - name: Set up Go
-        uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
-        with:
-          go-version: '1.19'
-          check-latest: true
-      - name: Run test action
-        uses: ./.github/workflows/test-action
diff --git a/cmd/osv-scanner/main_test.go b/cmd/osv-scanner/main_test.go
index 103617a..f12f275 100644
--- a/cmd/osv-scanner/main_test.go
+++ b/cmd/osv-scanner/main_test.go
@@ -446,6 +446,16 @@ func TestRun(t *testing.T) {
 			`,
 			wantStderr: "",
 		},
+		// output format: unsupported
+		{
+			name:         "",
+			args:         []string{"", "--format", "unknown", "./fixtures/locks-many/composer.lock"},
+			wantExitCode: 127,
+			wantStdout:   "",
+			wantStderr: `
+				unsupported output format "unknown" - must be one of: table, json, markdown, sarif, gh-annotations
+			`,
+		},
 	}
 	for _, tt := range tests {
 		tt := tt
diff --git a/pkg/config/config_internal_test.go b/pkg/config/config_internal_test.go
index 95e3bee..e271543 100644
--- a/pkg/config/config_internal_test.go
+++ b/pkg/config/config_internal_test.go
@@ -2,7 +2,9 @@ package config
 
 import (
 	"path/filepath"
+	"reflect"
 	"testing"
+	"time"
 
 	"github.com/google/go-cmp/cmp"
 )
@@ -74,3 +76,118 @@ func TestTryLoadConfig(t *testing.T) {
 		}
 	}
 }
+
+func TestConfig_ShouldIgnore(t *testing.T) {
+	t.Parallel()
+
+	type args struct {
+		vulnID string
+	}
+	tests := []struct {
+		name      string
+		config    Config
+		args      args
+		wantOk    bool
+		wantEntry IgnoreEntry
+	}{
+		// entry exists
+		{
+			name: "",
+			config: Config{
+				IgnoredVulns: []IgnoreEntry{
+					{
+						ID:          "GHSA-123",
+						IgnoreUntil: time.Time{},
+						Reason:      "",
+					},
+				},
+			},
+			args: args{
+				vulnID: "GHSA-123",
+			},
+			wantOk: true,
+			wantEntry: IgnoreEntry{
+				ID:          "GHSA-123",
+				IgnoreUntil: time.Time{},
+				Reason:      "",
+			},
+		},
+		// entry does not exist
+		{
+			name: "",
+			config: Config{
+				IgnoredVulns: []IgnoreEntry{
+					{
+						ID:          "GHSA-123",
+						IgnoreUntil: time.Time{},
+						Reason:      "",
+					},
+				},
+			},
+			args: args{
+				vulnID: "nonexistent",
+			},
+			wantOk:    false,
+			wantEntry: IgnoreEntry{},
+		},
+		// ignored until a time in the past
+		{
+			name: "",
+			config: Config{
+				IgnoredVulns: []IgnoreEntry{
+					{
+						ID:          "GHSA-123",
+						IgnoreUntil: time.Now().Add(-time.Hour).Round(time.Second),
+						Reason:      "",
+					},
+				},
+			},
+			args: args{
+				vulnID: "GHSA-123",
+			},
+			wantOk: false,
+			wantEntry: IgnoreEntry{
+				ID:          "GHSA-123",
+				IgnoreUntil: time.Now().Add(-time.Hour).Round(time.Second),
+				Reason:      "",
+			},
+		},
+		// ignored until a time in the future
+		{
+			name: "",
+			config: Config{
+				IgnoredVulns: []IgnoreEntry{
+					{
+						ID:          "GHSA-123",
+						IgnoreUntil: time.Now().Add(time.Hour).Round(time.Second),
+						Reason:      "",
+					},
+				},
+			},
+			args: args{
+				vulnID: "GHSA-123",
+			},
+			wantOk: true,
+			wantEntry: IgnoreEntry{
+				ID:          "GHSA-123",
+				IgnoreUntil: time.Now().Add(time.Hour).Round(time.Second),
+				Reason:      "",
+			},
+		},
+	}
+
+	for _, tt := range tests {
+		tt := tt
+		t.Run(tt.name, func(t *testing.T) {
+			t.Parallel()
+
+			gotOk, gotEntry := tt.config.ShouldIgnore(tt.args.vulnID)
+			if gotOk != tt.wantOk {
+				t.Errorf("ShouldIgnore() gotOk = %v, wantOk %v", gotOk, tt.wantOk)
+			}
+			if !reflect.DeepEqual(gotEntry, tt.wantEntry) {
+				t.Errorf("ShouldIgnore() gotEntry = %v, wantEntry %v", gotEntry, tt.wantEntry)
+			}
+		})
+	}
+}
diff --git a/pkg/lockfile/extract_test.go b/pkg/lockfile/extract_test.go
index a05042e..b014e1e 100644
--- a/pkg/lockfile/extract_test.go
+++ b/pkg/lockfile/extract_test.go
@@ -134,6 +134,20 @@ func TestExtractDeps_ExtractorNotFound(t *testing.T) {
 	}
 }
 
+func TestExtractDeps_ExtractorNotFound_WithExplicitExtractAs(t *testing.T) {
+	t.Parallel()
+
+	_, err := lockfile.ExtractDeps(openTestDepFile("/path/to/my/"), "unsupported")
+
+	if err == nil {
+		t.Errorf("Expected to get an error but did not")
+	}
+
+	if !errors.Is(err, lockfile.ErrExtractorNotFound) {
+		t.Errorf("Did not get the expected ErrExtractorNotFound error - got %v instead", err)
+	}
+}
+
 func TestListExtractors(t *testing.T) {
 	t.Parallel()
 
diff --git a/pkg/lockfile/parse_test.go b/pkg/lockfile/parse_test.go
index cdda673..8d5ecae 100644
--- a/pkg/lockfile/parse_test.go
+++ b/pkg/lockfile/parse_test.go
@@ -143,6 +143,20 @@ func TestParse_ParserNotFound(t *testing.T) {
 	}
 }
 
+func TestParse_ParserNotFound_WithExplicitParseAs(t *testing.T) {
+	t.Parallel()
+
+	_, err := lockfile.Parse("/path/to/my/", "unsupported")
+
+	if err == nil {
+		t.Errorf("Expected to get an error but did not")
+	}
+
+	if !errors.Is(err, lockfile.ErrParserNotFound) {
+		t.Errorf("Did not get the expected ErrParserNotFound error - got %v instead", err)
+	}
+}
+
 func TestListParsers(t *testing.T) {
 	t.Parallel()
 
diff --git a/pkg/reporter/format_test.go b/pkg/reporter/format_test.go
index 027356c..8e385f6 100644
--- a/pkg/reporter/format_test.go
+++ b/pkg/reporter/format_test.go
@@ -7,7 +7,7 @@ import (
 	"github.com/google/osv-scanner/pkg/reporter"
 )
 
-func TestGetReporter(t *testing.T) {
+func TestNew(t *testing.T) {
 	t.Parallel()
 
 	for _, format := range reporter.Format() {
@@ -20,3 +20,16 @@ func TestGetReporter(t *testing.T) {
 		}
 	}
 }
+
+func TestNew_UnsupportedFormatter(t *testing.T) {
+	t.Parallel()
+
+	stdout := &bytes.Buffer{}
+	stderr := &bytes.Buffer{}
+
+	_, err := reporter.New("unsupported", stdout, stderr, 0)
+
+	if err == nil {
+		t.Errorf("Did not get expected error")
+	}
+}