Deduplicate digests from user configuration (#2522)

* deduplicate digests from user configuration

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* backout pointer reciever change on imageSource

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

---------

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
Alex Goodman 2024-01-19 16:51:55 -05:00 committed by GitHub
parent 0bc31f4e27
commit 3eab5932e5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 180 additions and 3 deletions

View File

@ -2,6 +2,9 @@ package options
import (
"fmt"
"sort"
"github.com/scylladb/go-set/strset"
intFile "github.com/anchore/syft/internal/file"
"github.com/anchore/syft/syft/file"
@ -35,6 +38,10 @@ func defaultFileConfig() fileConfig {
}
func (c *fileConfig) PostLoad() error {
digests := strset.New(c.Metadata.Digests...).List()
sort.Strings(digests)
c.Metadata.Digests = digests
switch c.Metadata.Selection {
case file.NoFilesSelection, file.FilesOwnedByPackageSelection, file.AllFilesSelection:
return nil

View File

@ -0,0 +1,56 @@
package options
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/anchore/syft/syft/file"
)
func Test_fileConfig_PostLoad(t *testing.T) {
tests := []struct {
name string
cfg fileConfig
assert func(t *testing.T, cfg fileConfig)
wantErr assert.ErrorAssertionFunc
}{
{
name: "deduplicate digests",
cfg: fileConfig{
Metadata: fileMetadata{
Selection: file.NoFilesSelection,
Digests: []string{"sha1", "sha1"},
},
},
assert: func(t *testing.T, cfg fileConfig) {
assert.Equal(t, []string{"sha1"}, cfg.Metadata.Digests)
},
},
{
name: "error on invalid selection",
cfg: fileConfig{
Metadata: fileMetadata{
Selection: file.Selection("invalid"),
},
},
wantErr: assert.Error,
},
{
name: "error on empty selection",
cfg: fileConfig{},
wantErr: assert.Error,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.wantErr == nil {
tt.wantErr = assert.NoError
}
tt.wantErr(t, tt.cfg.PostLoad())
if tt.assert != nil {
tt.assert(t, tt.cfg)
}
})
}
}

View File

@ -2,6 +2,7 @@ package options
import (
"fmt"
"sort"
"strings"
"github.com/scylladb/go-set/strset"
@ -34,6 +35,13 @@ func defaultSourceConfig() sourceConfig {
}
}
func (c *fileSource) PostLoad() error {
digests := strset.New(c.Digests...).List()
sort.Strings(digests)
c.Digests = digests
return nil
}
func (c imageSource) PostLoad() error {
return checkDefaultSourceValues(c.DefaultPullSource)
}

View File

@ -0,0 +1,37 @@
package options
import (
"testing"
"github.com/stretchr/testify/assert"
)
func Test_fileSource_PostLoad(t *testing.T) {
tests := []struct {
name string
cfg fileSource
assert func(t *testing.T, cfg fileSource)
wantErr assert.ErrorAssertionFunc
}{
{
name: "deduplicate digests",
cfg: fileSource{
Digests: []string{"sha1", "sha1"},
},
assert: func(t *testing.T, cfg fileSource) {
assert.Equal(t, []string{"sha1"}, cfg.Digests)
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.wantErr == nil {
tt.wantErr = assert.NoError
}
tt.wantErr(t, tt.cfg.PostLoad())
if tt.assert != nil {
tt.assert(t, tt.cfg)
}
})
}
}

View File

@ -22,6 +22,7 @@ func supportedHashAlgorithms() []crypto.Hash {
}
func NewDigestsFromFile(closer io.ReadCloser, hashes []crypto.Hash) ([]file.Digest, error) {
hashes = NormalizeHashes(hashes)
// create a set of hasher objects tied together with a single writer to feed content into
hashers := make([]hash.Hash, len(hashes))
writers := make([]io.Writer, len(hashes))
@ -67,7 +68,7 @@ func Hashers(names ...string) ([]crypto.Hash, error) {
}
hashers = append(hashers, hashObj)
}
return hashers, nil
return NormalizeHashes(hashers), nil
}
func CleanDigestAlgorithmName(name string) string {

View File

@ -0,0 +1,24 @@
package file
import (
"crypto"
"sort"
"github.com/scylladb/go-set/uset"
)
func NormalizeHashes(hashes []crypto.Hash) []crypto.Hash {
set := uset.New()
for _, h := range hashes {
set.Add(uint(h))
}
list := set.List()
sort.Slice(list, func(i, j int) bool {
return list[i] < list[j]
})
result := make([]crypto.Hash, len(list))
for i, v := range list {
result[i] = crypto.Hash(v)
}
return result
}

View File

@ -0,0 +1,44 @@
package file
import (
"crypto"
"testing"
"github.com/stretchr/testify/assert"
)
func TestNormalizeHashes(t *testing.T) {
tests := []struct {
name string
input []crypto.Hash
want []crypto.Hash
}{
{
name: "deduplicate hashes",
input: []crypto.Hash{
crypto.SHA1,
crypto.SHA1,
},
want: []crypto.Hash{
crypto.SHA1,
},
},
{
name: "sort hashes",
input: []crypto.Hash{
crypto.SHA512,
crypto.SHA1,
},
want: []crypto.Hash{
crypto.SHA1,
crypto.SHA512,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, NormalizeHashes(tt.input))
})
}
}

View File

@ -73,6 +73,6 @@ func (cfg Config) WithSelection(selection file.Selection) Config {
}
func (cfg Config) WithHashers(hashers []crypto.Hash) Config {
cfg.Hashers = hashers
cfg.Hashers = intFile.NormalizeHashes(hashers)
return cfg
}

View File

@ -25,7 +25,7 @@ type Cataloger struct {
func NewCataloger(hashes []crypto.Hash) *Cataloger {
return &Cataloger{
hashes: hashes,
hashes: intFile.NormalizeHashes(hashes),
}
}