mirror of
https://github.com/anchore/syft.git
synced 2026-11-01 15:06:36 +01:00
add file source digest support (#1914)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
@@ -10,10 +10,11 @@ import (
|
||||
stereoscopeFile "github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/bus"
|
||||
intFile "github.com/anchore/syft/internal/file"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/event"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
internal2 "github.com/anchore/syft/syft/file/cataloger/internal"
|
||||
intCataloger "github.com/anchore/syft/syft/file/cataloger/internal"
|
||||
)
|
||||
|
||||
var ErrUndigestableFile = errors.New("undigestable file")
|
||||
@@ -33,7 +34,7 @@ func (i *Cataloger) Catalog(resolver file.Resolver, coordinates ...file.Coordina
|
||||
var locations []file.Location
|
||||
|
||||
if len(coordinates) == 0 {
|
||||
locations = internal2.AllRegularFiles(resolver)
|
||||
locations = intCataloger.AllRegularFiles(resolver)
|
||||
} else {
|
||||
for _, c := range coordinates {
|
||||
locations = append(locations, file.NewLocationFromCoordinates(c))
|
||||
@@ -82,7 +83,7 @@ func (i *Cataloger) catalogLocation(resolver file.Resolver, location file.Locati
|
||||
}
|
||||
defer internal.CloseAndLogError(contentReader, location.VirtualPath)
|
||||
|
||||
digests, err := file.NewDigestsFromFile(contentReader, i.hashes)
|
||||
digests, err := intFile.NewDigestsFromFile(contentReader, i.hashes)
|
||||
if err != nil {
|
||||
return nil, internal.ErrPath{Context: "digests-cataloger", Path: location.RealPath, Err: err}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
stereoscopeFile "github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/stereoscope/pkg/imagetest"
|
||||
intFile "github.com/anchore/syft/internal/file"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
@@ -40,7 +41,7 @@ func testDigests(t testing.TB, root string, files []string, hashes ...crypto.Has
|
||||
h := hash.New()
|
||||
h.Write(b)
|
||||
digests[file.NewLocation(f).Coordinates] = append(digests[file.NewLocation(f).Coordinates], file.Digest{
|
||||
Algorithm: file.CleanDigestAlgorithmName(hash.String()),
|
||||
Algorithm: intFile.CleanDigestAlgorithmName(hash.String()),
|
||||
Value: fmt.Sprintf("%x", h.Sum(nil)),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,76 +1,6 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Digest struct {
|
||||
Algorithm string `json:"algorithm"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
func NewDigestsFromFile(closer io.ReadCloser, hashes []crypto.Hash) ([]Digest, error) {
|
||||
// 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))
|
||||
for idx, hashObj := range hashes {
|
||||
hashers[idx] = hashObj.New()
|
||||
writers[idx] = hashers[idx]
|
||||
}
|
||||
|
||||
size, err := io.Copy(io.MultiWriter(writers...), closer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if size == 0 {
|
||||
return make([]Digest, 0), nil
|
||||
}
|
||||
|
||||
result := make([]Digest, len(hashes))
|
||||
// only capture digests when there is content. It is important to do this based on SIZE and not
|
||||
// FILE TYPE. The reasoning is that it is possible for a tar to be crafted with a header-only
|
||||
// file type but a body is still allowed.
|
||||
for idx, hasher := range hashers {
|
||||
result[idx] = Digest{
|
||||
Algorithm: DigestAlgorithmName(hashes[idx]),
|
||||
Value: fmt.Sprintf("%+x", hasher.Sum(nil)),
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func Hashers(names ...string) ([]crypto.Hash, error) {
|
||||
supportedHashAlgorithms := make(map[string]crypto.Hash)
|
||||
for _, h := range []crypto.Hash{
|
||||
crypto.MD5,
|
||||
crypto.SHA1,
|
||||
crypto.SHA256,
|
||||
} {
|
||||
supportedHashAlgorithms[DigestAlgorithmName(h)] = h
|
||||
}
|
||||
|
||||
var hashers []crypto.Hash
|
||||
for _, hashStr := range names {
|
||||
hashObj, ok := supportedHashAlgorithms[CleanDigestAlgorithmName(hashStr)]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unsupported hash algorithm: %s", hashStr)
|
||||
}
|
||||
hashers = append(hashers, hashObj)
|
||||
}
|
||||
return hashers, nil
|
||||
}
|
||||
|
||||
func DigestAlgorithmName(hash crypto.Hash) string {
|
||||
return CleanDigestAlgorithmName(hash.String())
|
||||
}
|
||||
|
||||
func CleanDigestAlgorithmName(name string) string {
|
||||
lower := strings.ToLower(name)
|
||||
return strings.ReplaceAll(lower, "-", "")
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/CycloneDX/cyclonedx-go"
|
||||
|
||||
"github.com/anchore/syft/internal/file"
|
||||
syftFile "github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
@@ -116,7 +117,7 @@ func decodeExternalReferences(c *cyclonedx.Component, metadata interface{}) {
|
||||
if ref.Hashes != nil {
|
||||
for _, hash := range *ref.Hashes {
|
||||
digests = append(digests, syftFile.Digest{
|
||||
Algorithm: syftFile.CleanDigestAlgorithmName(string(hash.Algorithm)),
|
||||
Algorithm: file.CleanDigestAlgorithmName(string(hash.Algorithm)),
|
||||
Value: hash.Value,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ func (j *archiveParser) discoverMainPackage() (*pkg.Package, error) {
|
||||
defer archiveCloser.Close()
|
||||
|
||||
// grab and assign digest for the entire archive
|
||||
digests, err := file.NewDigestsFromFile(archiveCloser, javaArchiveHashes)
|
||||
digests, err := intFile.NewDigestsFromFile(archiveCloser, javaArchiveHashes)
|
||||
if err != nil {
|
||||
log.Warnf("failed to create digest for file=%q: %+v", j.archivePath, err)
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/opencontainers/go-digest"
|
||||
|
||||
stereoFile "github.com/anchore/stereoscope/pkg/file"
|
||||
intFile "github.com/anchore/syft/internal/file"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
@@ -67,7 +68,7 @@ func NewFromFile(cfg FileConfig) (*FileSource, error) {
|
||||
|
||||
defer fh.Close()
|
||||
|
||||
digests, err = file.NewDigestsFromFile(fh, cfg.DigestAlgorithms)
|
||||
digests, err = intFile.NewDigestsFromFile(fh, cfg.DigestAlgorithms)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to calculate digests for file=%q: %w", cfg.Path, err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user