Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Use osv-scalibr SBOM extractors #1380

Closed
wants to merge 16 commits into from
Closed
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
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
**/fixtures/**
**/testdata/**
**/fixtures-go/**
/docs/vendor/**
/internal/output/html/*template.html
100 changes: 81 additions & 19 deletions cmd/osv-scanner/__snapshots__/main_test.snap
Original file line number Diff line number Diff line change
Expand Up @@ -349,9 +349,9 @@ overriding license for package Packagist/league/flysystem/1.0.8 with 0BSD
| LICENSE VIOLATION | ECOSYSTEM | PACKAGE | VERSION | SOURCE |
+-------------------+-----------+------------------------------------------------+---------+-------------------------------------------------------+
| 0BSD | Packagist | league/flysystem | 1.0.8 | fixtures/locks-insecure/composer.lock |
| UNKNOWN | | https://github.com/flutter/buildroot.git | | fixtures/locks-insecure/osv-scanner-flutter-deps.json |
| UNKNOWN | | https://github.com/brendan-duncan/archive.git | | fixtures/locks-insecure/osv-scanner-flutter-deps.json |
| UNKNOWN | | https://chromium.googlesource.com/chromium/src | | fixtures/locks-insecure/osv-scanner-flutter-deps.json |
| UNKNOWN | | https://github.com/brendan-duncan/archive.git | | fixtures/locks-insecure/osv-scanner-flutter-deps.json |
| UNKNOWN | | https://github.com/flutter/buildroot.git | | fixtures/locks-insecure/osv-scanner-flutter-deps.json |
| UNKNOWN | RubyGems | ast | 2.4.2 | fixtures/locks-many/Gemfile.lock |
| 0BSD | Packagist | sentry/sdk | 2.0.4 | fixtures/locks-many/composer.lock |
+-------------------+-----------+------------------------------------------------+---------+-------------------------------------------------------+
Expand Down Expand Up @@ -908,6 +908,68 @@ Scanned <rootdir>/fixtures/call-analysis-go-project/go.mod file and found 4 pack

---

[TestRun_Docker/Fake_alpine_image - 1]
Pulling docker image ("alpine:non-existent-tag")...

---

[TestRun_Docker/Fake_alpine_image - 2]
Docker command exited with code ("/usr/bin/docker pull -q alpine:non-existent-tag"): 1
STDERR:
> Error response from daemon: manifest for alpine:non-existent-tag not found: manifest unknown: manifest unknown
failed to run docker command

---

[TestRun_Docker/Fake_image_entirely - 1]
Pulling docker image ("this-image-definitely-does-not-exist-abcde")...

---

[TestRun_Docker/Fake_image_entirely - 2]
Docker command exited with code ("/usr/bin/docker pull -q this-image-definitely-does-not-exist-abcde"): 1
STDERR:
> Error response from daemon: pull access denied for this-image-definitely-does-not-exist-abcde, repository does not exist or may require 'docker login': denied: requested access to the resource is denied
failed to run docker command

---

[TestRun_Docker/Real_Alpine_image - 1]
Pulling docker image ("alpine:3.18.9")...
Saving docker image ("alpine:3.18.9") to temporary file...
Scanning image...
No issues found

---

[TestRun_Docker/Real_Alpine_image - 2]

---

[TestRun_Docker/Real_empty_image - 1]
Pulling docker image ("hello-world")...
Saving docker image ("hello-world") to temporary file...
Scanning image...

---

[TestRun_Docker/Real_empty_image - 2]
No package sources found, --help for usage information.

---

[TestRun_Docker/Real_empty_image_with_tag - 1]
Pulling docker image ("hello-world:linux")...
Saving docker image ("hello-world:linux") to temporary file...
Scanning image...

---

[TestRun_Docker/Real_empty_image_with_tag - 2]
No package sources found, --help for usage information.

---

[TestRun_GithubActions/scanning_osv-scanner_custom_format - 1]
Scanned <rootdir>/fixtures/locks-insecure/osv-scanner-flutter-deps.json file as a osv-scanner and found 3 packages
+--------------------------------+------+-----------+----------------------------+----------------------------+-------------------------------------------------------+
Expand Down Expand Up @@ -2270,7 +2332,7 @@ No issues found
---

[TestRun_LockfileWithExplicitParseAs/empty_works_as_an_escape_(no_fixture_because_it's_not_valid_on_Windows) - 2]
open <rootdir>/path/to/my:file: no such file or directory
stat <rootdir>/path/to/my:file: no such file or directory

---

Expand All @@ -2279,7 +2341,7 @@ open <rootdir>/path/to/my:file: no such file or directory
---

[TestRun_LockfileWithExplicitParseAs/empty_works_as_an_escape_(no_fixture_because_it's_not_valid_on_Windows)#01 - 2]
open <rootdir>/path/to/my:project/package-lock.json: no such file or directory
stat <rootdir>/path/to/my:project/package-lock.json: no such file or directory

---

Expand All @@ -2288,7 +2350,7 @@ open <rootdir>/path/to/my:project/package-lock.json: no such file or directory
---

[TestRun_LockfileWithExplicitParseAs/files_that_error_on_parsing_stop_parsable_files_from_being_checked - 2]
(extracting as Cargo.lock) could not extract from <rootdir>/fixtures/locks-insecure/my-package-lock.json: toml: line 1: expected '.' or '=', but got '{' instead
(extracting as rust/Cargolock) could not extract from <rootdir>/fixtures/locks-insecure/my-package-lock.json: toml: line 1: expected '.' or '=', but got '{' instead

---

Expand Down Expand Up @@ -2346,7 +2408,7 @@ No issues found
---

[TestRun_LockfileWithExplicitParseAs/parse-as_takes_priority,_even_if_it's_wrong - 2]
(extracting as package-lock.json) could not extract from <rootdir>/fixtures/locks-many/yarn.lock: invalid character '#' looking for beginning of value
(extracting as javascript/packagelockjson) could not extract from "<rootdir>/fixtures/locks-many/yarn.lock": invalid character '#' looking for beginning of value

---

Expand Down Expand Up @@ -2399,7 +2461,7 @@ No issues found

---

[TestRun_MavenTransitive/resolve_transitive_dependencies_with_native_datda_source - 1]
[TestRun_MavenTransitive/resolve_transitive_dependencies_with_native_data_source - 1]
Scanned <rootdir>/fixtures/maven-transitive/registry.xml file as a pom.xml and found 59 packages
+-------------------------------------+------+-----------+-----------------------------------------------+---------+----------------------------------------+
| OSV URL | CVSS | ECOSYSTEM | PACKAGE | VERSION | SOURCE |
Expand All @@ -2413,7 +2475,7 @@ Scanned <rootdir>/fixtures/maven-transitive/registry.xml file as a pom.xml and f

---

[TestRun_MavenTransitive/resolve_transitive_dependencies_with_native_datda_source - 2]
[TestRun_MavenTransitive/resolve_transitive_dependencies_with_native_data_source - 2]

---

Expand Down Expand Up @@ -2528,17 +2590,17 @@ Scanning image ../../internal/image/fixtures/test-node_modules-npm-empty.tar

[TestRun_OCIImage/scanning_node_modules_using_npm_with_some_packages - 1]
Scanning image ../../internal/image/fixtures/test-node_modules-npm-full.tar
+-------------------------------------+------+--------------+----------+------------+-------------------------------------------------------------------------------------------------------+
| OSV URL | CVSS | ECOSYSTEM | PACKAGE | VERSION | SOURCE |
+-------------------------------------+------+--------------+----------+------------+-------------------------------------------------------------------------------------------------------+
| https://osv.dev/CVE-2023-42363 | 5.5 | Alpine:v3.19 | busybox | 1.36.1-r15 | ../../internal/image/fixtures/test-node_modules-npm-full.tar:/lib/apk/db/installed |
| https://osv.dev/CVE-2023-42364 | 5.5 | Alpine:v3.19 | busybox | 1.36.1-r15 | ../../internal/image/fixtures/test-node_modules-npm-full.tar:/lib/apk/db/installed |
| https://osv.dev/CVE-2023-42365 | 5.5 | Alpine:v3.19 | busybox | 1.36.1-r15 | ../../internal/image/fixtures/test-node_modules-npm-full.tar:/lib/apk/db/installed |
| https://osv.dev/CVE-2023-42366 | 5.5 | Alpine:v3.19 | busybox | 1.36.1-r15 | ../../internal/image/fixtures/test-node_modules-npm-full.tar:/lib/apk/db/installed |
| https://osv.dev/GHSA-38f5-ghc2-fcmv | 9.8 | npm | cryo | 0.0.6 | ../../internal/image/fixtures/test-node_modules-npm-full.tar:/usr/app/node_modules/.package-lock.json |
| https://osv.dev/GHSA-vh95-rmgr-6w4m | 9.8 | npm | minimist | 0.0.8 | ../../internal/image/fixtures/test-node_modules-npm-full.tar:/usr/app/node_modules/.package-lock.json |
| https://osv.dev/GHSA-xvch-5gv4-984h | | | | | |
+-------------------------------------+------+--------------+----------+------------+-------------------------------------------------------------------------------------------------------+
+-------------------------------------+------+--------------+----------+------------+--------------------------------------------------------------------------------------------------------+
| OSV URL | CVSS | ECOSYSTEM | PACKAGE | VERSION | SOURCE |
+-------------------------------------+------+--------------+----------+------------+--------------------------------------------------------------------------------------------------------+
| https://osv.dev/CVE-2023-42363 | 5.5 | Alpine:v3.19 | busybox | 1.36.1-r15 | ../../internal/image/fixtures/test-node_modules-npm-full.tar:/lib/apk/db/installed |
| https://osv.dev/CVE-2023-42364 | 5.5 | Alpine:v3.19 | busybox | 1.36.1-r15 | ../../internal/image/fixtures/test-node_modules-npm-full.tar:/lib/apk/db/installed |
| https://osv.dev/CVE-2023-42365 | 5.5 | Alpine:v3.19 | busybox | 1.36.1-r15 | ../../internal/image/fixtures/test-node_modules-npm-full.tar:/lib/apk/db/installed |
| https://osv.dev/CVE-2023-42366 | 5.5 | Alpine:v3.19 | busybox | 1.36.1-r15 | ../../internal/image/fixtures/test-node_modules-npm-full.tar:/lib/apk/db/installed |
| https://osv.dev/GHSA-38f5-ghc2-fcmv | 9.8 | npm | cryo | 0.0.6 | ../../internal/image/fixtures/test-node_modules-npm-full.tar:/prod/app/node_modules/.package-lock.json |
| https://osv.dev/GHSA-vh95-rmgr-6w4m | 9.8 | npm | minimist | 0.0.8 | ../../internal/image/fixtures/test-node_modules-npm-full.tar:/prod/app/node_modules/.package-lock.json |
| https://osv.dev/GHSA-xvch-5gv4-984h | | | | | |
+-------------------------------------+------+--------------+----------+------------+--------------------------------------------------------------------------------------------------------+

---

Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
flask
flask==1.0.0
Original file line number Diff line number Diff line change
@@ -1 +1 @@
black
black==1.0.0
4 changes: 2 additions & 2 deletions cmd/osv-scanner/fixtures/locks-requirements/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
flask
flask-cors
flask==1.0.0
flask-cors==1.0.0
pandas==0.23.4
Original file line number Diff line number Diff line change
@@ -1 +1 @@
pytest
pytest==1.0.0
65 changes: 2 additions & 63 deletions cmd/osv-scanner/fixtures/sbom-insecure/osv-scanner.toml
Original file line number Diff line number Diff line change
@@ -1,64 +1,3 @@
[[IgnoredVulns]]
id = "GO-2022-0274"
# ignoreUntil = n/a
reason = "This is an intentionally vulnerable test sbom"

[[IgnoredVulns]]
id = "GO-2022-0493"
# ignoreUntil = n/a
reason = "This is an intentionally vulnerable test sbom"

[[IgnoredVulns]]
id = "GHSA-vpvm-3wq2-2wvm"
# ignoreUntil = n/a
reason = "This is an intentionally vulnerable test sbom"

[[IgnoredVulns]]
id = "GHSA-m8cg-xc2p-r3fc"
# ignoreUntil = n/a
reason = "This is an intentionally vulnerable test sbom"

[[IgnoredVulns]]
id = "GHSA-g2j6-57v7-gm8c"
# ignoreUntil = n/a
reason = "This is an intentionally vulnerable test sbom"

[[IgnoredVulns]]
id = "GHSA-f3fp-gc8g-vw66"
# ignoreUntil = n/a
reason = "This is an intentionally vulnerable test sbom"

[[IgnoredVulns]]
id = "DLA-3008-1"
# ignoreUntil = n/a
reason = "This is an intentionally vulnerable test sbom"

[[IgnoredVulns]]
id = "DLA-3012-1"
# ignoreUntil = n/a
reason = "This is an intentionally vulnerable test sbom"

[[IgnoredVulns]]
id = "DLA-3022-1"
# ignoreUntil = n/a
reason = "This is an intentionally vulnerable test sbom"

[[IgnoredVulns]]
id = "DLA-3051-1"
# ignoreUntil = n/a
reason = "This is an intentionally vulnerable test sbom"

[[IgnoredVulns]]
id = "CVE-2022-37434"
# ignoreUntil = n/a
reason = "This is an intentionally vulnerable test sbom"

[[IgnoredVulns]]
id = "CVE-2018-25032"
# ignoreUntil = n/a
reason = "This is an intentionally vulnerable test sbom"

[[IgnoredVulns]]
id = "GHSA-xr7r-f8xq-vfvv"
# ignoreUntil = n/a
[[PackageOverrides]]
ignore = true
reason = "This is an intentionally vulnerable test sbom"
12 changes: 12 additions & 0 deletions cmd/osv-scanner/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ func run(args []string, stdout, stderr io.Writer) int {
},
}

// If ExitErrHandler is not set, cli will use the default cli.HandleExitCoder.
// This is not ideal as cli.HandleExitCoder checks if the error implements cli.ExitCode interface.
//
// 99% of the time, this is fine, as we do not implement cli.ExitCode in our errors, so errors pass through
// that handler untouched.
// However, because of Go's duck typing, any error that happens to have a ExitCode() function
// (e.g. *exec.ExitError) will be assumed to implement cli.ExitCode interface and cause the program to exit
// early without proper error handling.
//
// This removes the handler entirely so that behavior will not unexpectedly happen.
app.ExitErrHandler = func(_ *cli.Context, _ error) {}

args = insertDefaultCommand(args, app.Commands, app.DefaultCommand, stdout, stderr)

if err := app.Run(args); err != nil {
Expand Down
55 changes: 53 additions & 2 deletions cmd/osv-scanner/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"
"path/filepath"
"reflect"
"runtime"
"strings"
"testing"

Expand Down Expand Up @@ -517,7 +518,12 @@ func TestRun_LockfileWithExplicitParseAs(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()

testCli(t, tt)
stdout, stderr := runCli(t, tt)

testutility.NewSnapshot().MatchText(t, stdout)
testutility.NewSnapshot().WithWindowsReplacements(map[string]string{
"CreateFile": "stat",
}).MatchText(t, stderr)
})
}
}
Expand Down Expand Up @@ -728,6 +734,51 @@ func TestRun_Licenses(t *testing.T) {
}
}

func TestRun_Docker(t *testing.T) {
t.Parallel()

testutility.SkipIfNotAcceptanceTesting(t, "Takes a long time to pull down images")

tests := []cliTestCase{
{
name: "Fake alpine image",
args: []string{"", "--docker", "alpine:non-existent-tag"},
exit: 127,
},
{
name: "Fake image entirely",
args: []string{"", "--docker", "this-image-definitely-does-not-exist-abcde"},
exit: 127,
},
// TODO: How to prevent these snapshots from changing constantly
{
name: "Real empty image",
args: []string{"", "--docker", "hello-world"},
exit: 128, // No packages found
},
{
name: "Real empty image with tag",
args: []string{"", "--docker", "hello-world:linux"},
exit: 128, // No package found
},
{
name: "Real Alpine image",
args: []string{"", "--docker", "alpine:3.18.9"},
exit: 0,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()

// Only test on linux, and mac/windows CI/CD does not come with docker preinstalled
if runtime.GOOS == "linux" {
testCli(t, tt)
}
})
}
}

func TestRun_OCIImage(t *testing.T) {
t.Parallel()

Expand Down Expand Up @@ -923,7 +974,7 @@ func TestRun_MavenTransitive(t *testing.T) {
exit: 1,
},
{
name: "resolve transitive dependencies with native datda source",
name: "resolve transitive dependencies with native data source",
args: []string{"", "--config=./fixtures/osv-scanner-empty-config.toml", "--experimental-resolution-data-source=native", "-L", "pom.xml:./fixtures/maven-transitive/registry.xml"},
exit: 1,
},
Expand Down
22 changes: 11 additions & 11 deletions cmd/osv-scanner/scan/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ func Command(stdout, stderr io.Writer, r *reporter.Reporter) *cli.Command {
Usage: "scans various mediums for dependencies and matches it against the OSV database",
Description: "scans various mediums for dependencies and matches it against the OSV database",
Flags: []cli.Flag{
&cli.StringSliceFlag{
&cli.StringFlag{
Name: "docker",
Aliases: []string{"D"},
Usage: "scan docker image with this name. Warning: Only run this on a trusted container image, as it runs the container image to retrieve the package versions",
Usage: "scan docker image with this name. This is a convenience function which runs `docker save` before scanning the saved image using --oci-image",
TakesFile: false,
},
&cli.StringSliceFlag{
Expand Down Expand Up @@ -258,15 +258,15 @@ func action(context *cli.Context, stdout, stderr io.Writer) (reporter.Reporter,
}

vulnResult, err := osvscanner.DoScan(osvscanner.ScannerActions{
LockfilePaths: context.StringSlice("lockfile"),
SBOMPaths: context.StringSlice("sbom"),
DockerContainerNames: context.StringSlice("docker"),
Recursive: context.Bool("recursive"),
SkipGit: context.Bool("skip-git"),
NoIgnore: context.Bool("no-ignore"),
ConfigOverridePath: context.String("config"),
DirectoryPaths: context.Args().Slice(),
CallAnalysisStates: callAnalysisStates,
LockfilePaths: context.StringSlice("lockfile"),
SBOMPaths: context.StringSlice("sbom"),
DockerImageName: context.String("docker"),
Recursive: context.Bool("recursive"),
SkipGit: context.Bool("skip-git"),
NoIgnore: context.Bool("no-ignore"),
ConfigOverridePath: context.String("config"),
DirectoryPaths: context.Args().Slice(),
CallAnalysisStates: callAnalysisStates,
ExperimentalScannerActions: osvscanner.ExperimentalScannerActions{
LocalDBPath: context.String("experimental-local-db-path"),
DownloadDatabases: context.Bool("experimental-download-offline-databases"),
Expand Down
Loading
Loading