Add support for indexing root filesystem (#442)

* change directory resolver to ignore system runtime paths + drive by index

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add event/etui support for filesystem indexing (for dir resolver)

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add warnings for path indexing problems

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add directory resolver index tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* improve testing around directory resolver

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* renamed p var to path when not conflicting with import

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* pull docker image in CLI dir scan timeout test

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* ensure file not exist errors do not stop directory resolver indexing

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
Alex Goodman
2021-06-29 22:06:47 +00:00
committed by GitHub
parent 962e82297c
commit fb0857ff93
25 changed files with 787 additions and 138 deletions
+46
View File
@@ -0,0 +1,46 @@
package cli
import (
"os/exec"
"strings"
"testing"
"time"
)
func TestDirectoryScanCompletesWithinTimeout(t *testing.T) {
image := "alpine:latest"
// we want to pull the image ahead of the test as to not affect the timeout value
pullDockerImage(t, image)
var cmd *exec.Cmd
var stdout, stderr string
done := make(chan struct{})
go func() {
defer close(done)
cmd, stdout, stderr = runSyftInDocker(t, nil, image, "dir:/", "-vv")
}()
select {
case <-done:
break
case <-time.After(5 * time.Second):
t.Fatalf("directory scan is taking too long")
}
assertions := []traitAssertion{
assertTableReport,
assertSuccessfulReturnCode,
}
for _, traitFn := range assertions {
traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
}
if t.Failed() {
t.Log("STDOUT:\n", stdout)
t.Log("STDERR:\n", stderr)
t.Log("COMMAND:", strings.Join(cmd.Args, " "))
}
}
+1 -1
View File
@@ -60,7 +60,7 @@ func TestJSONSchema(t *testing.T) {
args = append(args, a)
}
_, stdout, stderr := runSyftCommand(t, nil, args...)
_, stdout, stderr := runSyft(t, nil, args...)
if len(strings.Trim(stdout, "\n ")) < 100 {
t.Fatalf("bad syft run:\noutput: %q\n:error: %q", stdout, stderr)
+2 -2
View File
@@ -125,7 +125,7 @@ func TestPackagesCmdFlags(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
cmd, stdout, stderr := runSyftCommand(t, test.env, test.args...)
cmd, stdout, stderr := runSyft(t, test.env, test.args...)
for _, traitFn := range test.assertions {
traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
}
@@ -197,7 +197,7 @@ func TestRegistryAuth(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
cmd, stdout, stderr := runSyftCommand(t, test.env, test.args...)
cmd, stdout, stderr := runSyft(t, test.env, test.args...)
for _, traitAssertionFn := range test.assertions {
traitAssertionFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
}
+1 -1
View File
@@ -66,7 +66,7 @@ func TestPowerUserCmdFlags(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
cmd, stdout, stderr := runSyftCommand(t, test.env, test.args...)
cmd, stdout, stderr := runSyft(t, test.env, test.args...)
for _, traitFn := range test.assertions {
traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
}
+3 -3
View File
@@ -36,12 +36,12 @@ func TestRootCmdAliasesToPackagesSubcommand(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
aliasCmd, aliasStdout, aliasStderr := runSyftCommand(t, test.env, request)
aliasCmd, aliasStdout, aliasStderr := runSyft(t, test.env, request)
for _, traitFn := range test.assertions {
traitFn(t, aliasStdout, aliasStderr, aliasCmd.ProcessState.ExitCode())
}
pkgCmd, pkgsStdout, pkgsStderr := runSyftCommand(t, test.env, "packages", request)
pkgCmd, pkgsStdout, pkgsStderr := runSyft(t, test.env, "packages", request)
for _, traitFn := range test.assertions {
traitFn(t, pkgsStdout, pkgsStderr, pkgCmd.ProcessState.ExitCode())
}
@@ -102,7 +102,7 @@ func TestPersistentFlags(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
cmd, stdout, stderr := runSyftCommand(t, test.env, test.args...)
cmd, stdout, stderr := runSyft(t, test.env, test.args...)
for _, traitFn := range test.assertions {
traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
}
+1 -1
View File
@@ -59,7 +59,7 @@ func TestSPDXJSONSchema(t *testing.T) {
args = append(args, a)
}
_, stdout, _ := runSyftCommand(t, nil, args...)
_, stdout, _ := runSyft(t, nil, args...)
if len(strings.Trim(stdout, "\n ")) < 100 {
t.Fatalf("bad syft output: %q", stdout)
+56 -16
View File
@@ -19,8 +19,45 @@ func getFixtureImage(t testing.TB, fixtureImageName string) string {
return imagetest.GetFixtureImageTarPath(t, fixtureImageName)
}
func runSyftCommand(t testing.TB, env map[string]string, args ...string) (*exec.Cmd, string, string) {
func pullDockerImage(t testing.TB, image string) {
cmd := exec.Command("docker", "pull", image)
stdout, stderr := runCommand(cmd, nil)
if cmd.ProcessState.ExitCode() != 0 {
t.Log("STDOUT", stdout)
t.Log("STDERR", stderr)
t.Fatalf("could not pull docker image")
}
}
func runSyftInDocker(t testing.TB, env map[string]string, image string, args ...string) (*exec.Cmd, string, string) {
allArgs := append(
[]string{
"run",
"-t",
"-e",
"SYFT_CHECK_FOR_APP_UPDATE=false",
"-v",
fmt.Sprintf("%s:/syft", getSyftBinaryLocationByOS(t, "linux")),
image,
"/syft",
},
args...,
)
cmd := exec.Command("docker", allArgs...)
stdout, stderr := runCommand(cmd, env)
return cmd, stdout, stderr
}
func runSyft(t testing.TB, env map[string]string, args ...string) (*exec.Cmd, string, string) {
cmd := getSyftCommand(t, args...)
if env != nil {
env["SYFT_CHECK_FOR_APP_UPDATE"] = "false"
}
stdout, stderr := runCommand(cmd, env)
return cmd, stdout, stderr
}
func runCommand(cmd *exec.Cmd, env map[string]string) (string, string) {
if env != nil {
var envList []string
for key, val := range env {
@@ -38,29 +75,32 @@ func runSyftCommand(t testing.TB, env map[string]string, args ...string) (*exec.
// ignore errors since this may be what the test expects
cmd.Run()
return cmd, stdout.String(), stderr.String()
return stdout.String(), stderr.String()
}
func getSyftCommand(t testing.TB, args ...string) *exec.Cmd {
return exec.Command(getSyftBinaryLocation(t), args...)
}
var binaryLocation string
func getSyftBinaryLocation(t testing.TB) string {
if os.Getenv("SYFT_BINARY_LOCATION") != "" {
// SYFT_BINARY_LOCATION is the absolute path to the snapshot binary
binaryLocation = os.Getenv("SYFT_BINARY_LOCATION")
} else {
// note: there is a subtle - vs _ difference between these versions
switch runtime.GOOS {
case "darwin":
binaryLocation = path.Join(repoRoot(t), fmt.Sprintf("snapshot/syft-macos_darwin_%s/syft", runtime.GOARCH))
case "linux":
binaryLocation = path.Join(repoRoot(t), fmt.Sprintf("snapshot/syft_linux_%s/syft", runtime.GOARCH))
default:
t.Fatalf("unsupported OS: %s", runtime.GOOS)
}
return os.Getenv("SYFT_BINARY_LOCATION")
}
return getSyftBinaryLocationByOS(t, runtime.GOOS)
}
return exec.Command(binaryLocation, args...)
func getSyftBinaryLocationByOS(t testing.TB, goOS string) string {
// note: there is a subtle - vs _ difference between these versions
switch goOS {
case "darwin":
return path.Join(repoRoot(t), fmt.Sprintf("snapshot/syft-macos_darwin_%s/syft", runtime.GOARCH))
case "linux":
return path.Join(repoRoot(t), fmt.Sprintf("snapshot/syft_linux_%s/syft", runtime.GOARCH))
default:
t.Fatalf("unsupported OS: %s", runtime.GOOS)
}
return ""
}
func repoRoot(t testing.TB) string {