Skip to content
Merged
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
3 changes: 3 additions & 0 deletions cmd/grype/cli/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,9 @@ func runGrype(app clio.Application, opts *options.Grype, userInput string) (errs
log.WithFields("time", time.Since(startTime)).Info("found vulnerability matches")
startTime = time.Now()

// clear out the registry auth information to avoid including possibly sensitive information in the report
opts.Registry.Auth = nil

model, err := models.NewDocument(app.ID(), packages, pkgContext, *remainingMatches, ignoredMatches, vp, opts, dbInfo(status, vp), models.SortStrategy(opts.SortBy.Criteria), opts.Timestamp)
if err != nil {
return fmt.Errorf("failed to create document: %w", err)
Expand Down
8 changes: 4 additions & 4 deletions cmd/grype/cli/options/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type RegistryCredentials struct {
type registry struct {
InsecureSkipTLSVerify bool `yaml:"insecure-skip-tls-verify" json:"insecure-skip-tls-verify" mapstructure:"insecure-skip-tls-verify"`
InsecureUseHTTP bool `yaml:"insecure-use-http" json:"insecure-use-http" mapstructure:"insecure-use-http"`
Auth []RegistryCredentials `yaml:"auth" json:"auth" mapstructure:"auth"`
Auth []RegistryCredentials `yaml:"auth" json:"auth,omitempty" mapstructure:"auth"`
CACert string `yaml:"ca-cert" json:"ca-cert" mapstructure:"ca-cert"`
}

Expand Down Expand Up @@ -82,9 +82,9 @@ func (cfg *registry) ToOptions() *image.RegistryOptions {
for i, a := range cfg.Auth {
auth[i] = image.RegistryCredentials{
Authority: a.Authority,
Username: a.Username.String(),
Password: a.Password.String(),
Token: a.Token.String(),
Username: string(a.Username),
Password: string(a.Password),
Token: string(a.Token),
ClientCert: a.TLSCert,
ClientKey: a.TLSKey,
}
Expand Down
10 changes: 9 additions & 1 deletion cmd/grype/cli/options/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,13 @@ func (r *secret) PostLoad() error {
}

func (r secret) String() string {
return string(r)
if r == "" {
return ""
}
// match the redactor's behavior, replacing with 7 asterisks
return "*******"
}

func (r secret) MarshalText() ([]byte, error) {
return []byte(r.String()), nil
}
93 changes: 93 additions & 0 deletions test/cli/registry_auth_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package cli

import (
"os"
"path/filepath"
"strings"
"testing"

"github.com/stretchr/testify/require"
)

func TestRegistryAuth(t *testing.T) {
Expand Down Expand Up @@ -97,3 +101,92 @@ func TestRegistryAuth(t *testing.T) {
})
}
}

func TestRegistryAuthRedactions(t *testing.T) {
tmp := filepath.Join(t.TempDir(), "output.json")

assertNotInFile := func(text string) traitAssertion {
return func(tb testing.TB, stdout, stderr string, rc int) {
contents, err := os.ReadFile(tmp)
require.NoError(tb, err)
require.NotEmpty(tb, contents)
require.NotContains(tb, string(contents), text)
}
}

tests := []struct {
name string
args []string
env map[string]string
assertions []traitAssertion
}{
{
name: "use creds",
args: []string{"-vv", "sbom:test-fixtures/sbom-grype-source.json", "-o", "json"},
env: map[string]string{
"GRYPE_REGISTRY_AUTH_USERNAME": "foobar-username",
"GRYPE_REGISTRY_AUTH_PASSWORD": "foobar-password",
},
assertions: []traitAssertion{
assertSucceedingReturnCode,
assertNotInOutput("foobar-username"),
assertNotInOutput("foobar-password"),
},
},
{
name: "use token",
args: []string{"-vv", "sbom:test-fixtures/sbom-grype-source.json", "-o", "json"},
env: map[string]string{
"GRYPE_REGISTRY_AUTH_TOKEN": "foobar-token",
},
assertions: []traitAssertion{
assertSucceedingReturnCode,
assertNotInOutput("foobar-token"),
},
},
{
name: "use creds file",
args: []string{"-vv", "sbom:test-fixtures/sbom-grype-source.json", "-o", "json", "--file", tmp},
env: map[string]string{
"GRYPE_REGISTRY_AUTH_USERNAME": "foobar-username",
"GRYPE_REGISTRY_AUTH_PASSWORD": "foobar-password",
},
assertions: []traitAssertion{
assertSucceedingReturnCode,
assertNotInFile("foobar-username"),
assertNotInFile("foobar-password"),
assertNotInOutput("foobar-username"),
assertNotInOutput("foobar-password"),
},
},
{
name: "use token file",
args: []string{"-vv", "sbom:test-fixtures/sbom-grype-source.json", "-o", "json", "--file", tmp},
env: map[string]string{
"GRYPE_REGISTRY_AUTH_TOKEN": "foobar-token",
},
assertions: []traitAssertion{
assertSucceedingReturnCode,
assertNotInFile("foobar-token"),
assertNotInOutput("foobar-token"),
},
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
_ = os.Remove(tmp) // ok to fail
cmd, stdout, stderr := runGrype(t, test.env, test.args...)
for _, traitAssertionFn := range test.assertions {
traitAssertionFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
}
if t.Failed() {
fileContents, _ := os.ReadFile(tmp)
t.Log("FILE:\n", string(fileContents))
t.Log("STDOUT:\n", stdout)
t.Log("STDERR:\n", stderr)
t.Log("COMMAND:", strings.Join(cmd.Args, " "))
}
})
}
}