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:
Alex Goodman
2023-10-25 13:43:06 +00:00
committed by GitHub
parent 7315f83f9d
commit 7392d607b6
254 changed files with 10450 additions and 2714 deletions
+116
View File
@@ -0,0 +1,116 @@
package model
import (
"encoding/json"
"fmt"
"reflect"
"strconv"
"strings"
"github.com/anchore/syft/syft/internal/sourcemetadata"
"github.com/anchore/syft/syft/source"
)
// Source object represents the thing that was cataloged
type Source struct {
ID string `json:"id"`
Name string `json:"name"`
Version string `json:"version"`
Type string `json:"type"`
Metadata interface{} `json:"metadata"`
}
// sourceUnpacker is used to unmarshal Source objects
type sourceUnpacker struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
Version string `json:"version"`
Type string `json:"type"`
Metadata json.RawMessage `json:"metadata"`
Target json.RawMessage `json:"target"` // pre-v9 schema support
}
// UnmarshalJSON populates a source object from JSON bytes.
func (s *Source) UnmarshalJSON(b []byte) error {
var unpacker sourceUnpacker
err := json.Unmarshal(b, &unpacker)
if err != nil {
return err
}
s.Name = unpacker.Name
s.Version = unpacker.Version
s.Type = unpacker.Type
s.ID = unpacker.ID
if len(unpacker.Target) > 0 {
s.Type = cleanPreSchemaV9MetadataType(s.Type)
s.Metadata, err = extractPreSchemaV9Metadata(s.Type, unpacker.Target)
if err != nil {
return fmt.Errorf("unable to extract pre-schema-v9 source metadata: %w", err)
}
return nil
}
return unpackSrcMetadata(s, unpacker)
}
func unpackSrcMetadata(s *Source, unpacker sourceUnpacker) error {
rt := sourcemetadata.ReflectTypeFromJSONName(s.Type)
if rt == nil {
return fmt.Errorf("unable to find source metadata type=%q", s.Type)
}
val := reflect.New(rt).Interface()
if len(unpacker.Metadata) > 0 {
if err := json.Unmarshal(unpacker.Metadata, val); err != nil {
return err
}
}
s.Metadata = reflect.ValueOf(val).Elem().Interface()
return nil
}
func cleanPreSchemaV9MetadataType(t string) string {
t = strings.ToLower(t)
if t == "dir" {
return "directory"
}
return t
}
func extractPreSchemaV9Metadata(t string, target []byte) (interface{}, error) {
switch t {
case "directory", "dir":
cleanTarget, err := strconv.Unquote(string(target))
if err != nil {
cleanTarget = string(target)
}
return source.DirectorySourceMetadata{
Path: cleanTarget,
}, nil
case "file":
cleanTarget, err := strconv.Unquote(string(target))
if err != nil {
cleanTarget = string(target)
}
return source.FileSourceMetadata{
Path: cleanTarget,
}, nil
case "image":
var payload source.StereoscopeImageSourceMetadata
if err := json.Unmarshal(target, &payload); err != nil {
return nil, err
}
return payload, nil
default:
return nil, fmt.Errorf("unsupported package metadata type: %+v", t)
}
}