fix: DecoderCollection discarding input from non-seekable Readers (#2878)

Signed-off-by: Russell Haering <russellhaering@gmail.com>
This commit is contained in:
Russell Haering 2024-05-16 12:17:11 -07:00 committed by GitHub
parent 15c9fe092a
commit 1bec1fc5d3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 32 additions and 4 deletions

View file

@ -4,6 +4,8 @@ import (
"fmt"
"io"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/format/internal/stream"
"github.com/anchore/syft/syft/sbom"
)
@ -20,10 +22,16 @@ func NewDecoderCollection(decoders ...sbom.FormatDecoder) sbom.FormatDecoder {
}
// Decode takes a set of bytes and attempts to decode it into an SBOM relative to the decoders in the collection.
func (c *DecoderCollection) Decode(reader io.Reader) (*sbom.SBOM, sbom.FormatID, string, error) {
if reader == nil {
func (c *DecoderCollection) Decode(r io.Reader) (*sbom.SBOM, sbom.FormatID, string, error) {
if r == nil {
return nil, "", "", fmt.Errorf("no SBOM bytes provided")
}
reader, err := stream.SeekableReader(r)
if err != nil {
return nil, "", "", fmt.Errorf("unable to create a seekable reader: %w", err)
}
var bestID sbom.FormatID
for _, d := range c.decoders {
id, version := d.Identify(reader)
@ -45,10 +53,17 @@ func (c *DecoderCollection) Decode(reader io.Reader) (*sbom.SBOM, sbom.FormatID,
}
// Identify takes a set of bytes and attempts to identify the format of the SBOM relative to the decoders in the collection.
func (c *DecoderCollection) Identify(reader io.Reader) (sbom.FormatID, string) {
if reader == nil {
func (c *DecoderCollection) Identify(r io.Reader) (sbom.FormatID, string) {
if r == nil {
return "", ""
}
reader, err := stream.SeekableReader(r)
if err != nil {
log.Debugf("unable to create a seekable reader: %v", err)
return "", ""
}
for _, d := range c.decoders {
id, version := d.Identify(reader)
if id != "" && version != "" {

View file

@ -2,12 +2,14 @@ package format
import (
"fmt"
"io"
"os"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/anchore/syft/syft/format/spdxjson"
"github.com/anchore/syft/syft/format/syftjson"
"github.com/anchore/syft/syft/sbom"
)
@ -37,6 +39,17 @@ func TestIdentify(t *testing.T) {
}
}
func TestDecodeUnseekable(t *testing.T) {
reader, err := os.Open("spdxjson/test-fixtures/spdx/example7-go-module.spdx.json")
assert.NoError(t, err)
// io.NopCloser wraps the reader in a non-seekable type
unseekableReader := io.NopCloser(reader)
_, formatID, _, err := Decode(unseekableReader)
assert.NoError(t, err)
assert.Equal(t, spdxjson.ID, formatID)
}
func TestFormats_EmptyInput(t *testing.T) {
for _, format := range Decoders() {
name := strings.Split(fmt.Sprintf("%#v", format), "{")[0]