mirror of
https://github.com/anchore/syft.git
synced 2026-11-02 23:46:35 +01:00
Split the sbom.Format interface by encode and decode use cases (#2186)
* split up sbom.Format into encode and decode ops Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * update cmd pkg to inject format configs Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * bump cyclonedx schema to 1.5 Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * redact image metadata from github encoder tests Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * add more testing around format decoder identify Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * add test case for format version options Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * fix cli tests Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * fix CLI test Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * [wip] - review comments Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * keep encoder creation out of post load function Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * keep decider and identify functions Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * add a few more doc comments Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * remove format encoder default function helpers Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * address PR feedback Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * move back to streaming based decode functions Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * with common convention for encoder constructors Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * fix tests and allow for encoders to be created from cli options Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * fix cli tests Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * fix linting Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * buffer reads from stdin to support seeking 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:
+10
-87
@@ -1,17 +1,9 @@
|
||||
package sbom
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrEncodingNotSupported = errors.New("encoding not supported")
|
||||
ErrDecodingNotSupported = errors.New("decoding not supported")
|
||||
ErrValidationNotSupported = errors.New("validation not supported")
|
||||
)
|
||||
|
||||
type FormatID string
|
||||
|
||||
// String returns a string representation of the FormatID.
|
||||
@@ -21,88 +13,19 @@ func (f FormatID) String() string {
|
||||
|
||||
const AnyVersion = ""
|
||||
|
||||
type Format interface {
|
||||
type FormatEncoder interface {
|
||||
ID() FormatID
|
||||
IDs() []FormatID
|
||||
Aliases() []string
|
||||
Version() string
|
||||
Encode(io.Writer, SBOM) error
|
||||
Decode(io.Reader) (*SBOM, error)
|
||||
Validate(io.Reader) error
|
||||
fmt.Stringer
|
||||
}
|
||||
|
||||
type format struct {
|
||||
ids []FormatID
|
||||
version string
|
||||
encoder Encoder
|
||||
decoder Decoder
|
||||
validator Validator
|
||||
type FormatDecoder interface {
|
||||
// Decode will return an SBOM from the given reader. If the bytes are not a valid SBOM for the given format
|
||||
// then an error will be returned.
|
||||
Decode(io.ReadSeeker) (*SBOM, FormatID, string, error)
|
||||
|
||||
// Identify will return the format ID and version for the given reader. Note: this does not validate the
|
||||
// full SBOM, only pulls the minimal information necessary to identify the format.
|
||||
Identify(io.ReadSeeker) (FormatID, string)
|
||||
}
|
||||
|
||||
func (f format) IDs() []FormatID {
|
||||
return f.ids
|
||||
}
|
||||
|
||||
func (f format) Version() string {
|
||||
return f.version
|
||||
}
|
||||
|
||||
func (f format) String() string {
|
||||
if f.version == AnyVersion {
|
||||
return f.ID().String()
|
||||
}
|
||||
return fmt.Sprintf("%s@%s", f.ID(), f.version)
|
||||
}
|
||||
|
||||
// Decoder is a function that can convert an SBOM document of a specific format from a reader into Syft native objects.
|
||||
type Decoder func(reader io.Reader) (*SBOM, error)
|
||||
|
||||
// Encoder is a function that can transform Syft native objects into an SBOM document of a specific format written to the given writer.
|
||||
type Encoder func(io.Writer, SBOM) error
|
||||
|
||||
// Validator reads the SBOM from the given reader and assesses whether the document conforms to the specific SBOM format.
|
||||
// The validator should positively confirm if the SBOM is not only the format but also has the minimal set of values
|
||||
// that the format requires. For example, all syftjson formatted documents have a schema section which should have
|
||||
// "anchore/syft" within the version --if this isn't found then the validator should raise an error. These active
|
||||
// assertions protect against "simple" format decoding validations that may lead to false positives (e.g. I decoded
|
||||
// json successfully therefore this must be the target format, however, all values are their default zero-value and
|
||||
// really represent a different format that also uses json)
|
||||
type Validator func(reader io.Reader) error
|
||||
|
||||
func NewFormat(version string, encoder Encoder, decoder Decoder, validator Validator, ids ...FormatID) Format {
|
||||
return format{
|
||||
ids: ids,
|
||||
version: version,
|
||||
encoder: encoder,
|
||||
decoder: decoder,
|
||||
validator: validator,
|
||||
}
|
||||
}
|
||||
|
||||
func (f format) ID() FormatID {
|
||||
return f.ids[0]
|
||||
}
|
||||
|
||||
func (f format) Encode(output io.Writer, s SBOM) error {
|
||||
if f.encoder == nil {
|
||||
return ErrEncodingNotSupported
|
||||
}
|
||||
return f.encoder(output, s)
|
||||
}
|
||||
|
||||
func (f format) Decode(reader io.Reader) (*SBOM, error) {
|
||||
if f.decoder == nil {
|
||||
return nil, ErrDecodingNotSupported
|
||||
}
|
||||
return f.decoder(reader)
|
||||
}
|
||||
|
||||
func (f format) Validate(reader io.Reader) error {
|
||||
if f.validator == nil {
|
||||
return ErrValidationNotSupported
|
||||
}
|
||||
|
||||
return f.validator(reader)
|
||||
}
|
||||
|
||||
var _ Format = (*format)(nil)
|
||||
|
||||
Reference in New Issue
Block a user