github.com/lineaje-labs/syft@v0.98.1-0.20231227153149-9e393f60ff1b/syft/format/syftjson/model/source.go (about)

     1  package model
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"reflect"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/anchore/syft/syft/source"
    11  	"github.com/lineaje-labs/syft/syft/internal/sourcemetadata"
    12  )
    13  
    14  // Source object represents the thing that was cataloged
    15  type Source struct {
    16  	ID       string      `json:"id"`
    17  	Name     string      `json:"name"`
    18  	Version  string      `json:"version"`
    19  	Type     string      `json:"type"`
    20  	Metadata interface{} `json:"metadata"`
    21  }
    22  
    23  // sourceUnpacker is used to unmarshal Source objects
    24  type sourceUnpacker struct {
    25  	ID       string          `json:"id,omitempty"`
    26  	Name     string          `json:"name"`
    27  	Version  string          `json:"version"`
    28  	Type     string          `json:"type"`
    29  	Metadata json.RawMessage `json:"metadata"`
    30  	Target   json.RawMessage `json:"target"` // pre-v9 schema support
    31  }
    32  
    33  // UnmarshalJSON populates a source object from JSON bytes.
    34  func (s *Source) UnmarshalJSON(b []byte) error {
    35  	var unpacker sourceUnpacker
    36  	err := json.Unmarshal(b, &unpacker)
    37  	if err != nil {
    38  		return err
    39  	}
    40  
    41  	s.Name = unpacker.Name
    42  	s.Version = unpacker.Version
    43  	s.Type = unpacker.Type
    44  	s.ID = unpacker.ID
    45  
    46  	if len(unpacker.Target) > 0 {
    47  		s.Type = cleanPreSchemaV9MetadataType(s.Type)
    48  		s.Metadata, err = extractPreSchemaV9Metadata(s.Type, unpacker.Target)
    49  		if err != nil {
    50  			return fmt.Errorf("unable to extract pre-schema-v9 source metadata: %w", err)
    51  		}
    52  		return nil
    53  	}
    54  
    55  	return unpackSrcMetadata(s, unpacker)
    56  }
    57  
    58  func unpackSrcMetadata(s *Source, unpacker sourceUnpacker) error {
    59  	rt := sourcemetadata.ReflectTypeFromJSONName(s.Type)
    60  	if rt == nil {
    61  		return fmt.Errorf("unable to find source metadata type=%q", s.Type)
    62  	}
    63  
    64  	val := reflect.New(rt).Interface()
    65  	if len(unpacker.Metadata) > 0 {
    66  		if err := json.Unmarshal(unpacker.Metadata, val); err != nil {
    67  			return err
    68  		}
    69  	}
    70  
    71  	s.Metadata = reflect.ValueOf(val).Elem().Interface()
    72  
    73  	return nil
    74  }
    75  
    76  func cleanPreSchemaV9MetadataType(t string) string {
    77  	t = strings.ToLower(t)
    78  	if t == "dir" {
    79  		return "directory"
    80  	}
    81  	return t
    82  }
    83  
    84  func extractPreSchemaV9Metadata(t string, target []byte) (interface{}, error) {
    85  	switch t {
    86  	case "directory", "dir":
    87  		cleanTarget, err := strconv.Unquote(string(target))
    88  		if err != nil {
    89  			cleanTarget = string(target)
    90  		}
    91  
    92  		return source.DirectorySourceMetadata{
    93  			Path: cleanTarget,
    94  		}, nil
    95  
    96  	case "file":
    97  		cleanTarget, err := strconv.Unquote(string(target))
    98  		if err != nil {
    99  			cleanTarget = string(target)
   100  		}
   101  
   102  		return source.FileSourceMetadata{
   103  			Path: cleanTarget,
   104  		}, nil
   105  
   106  	case "image":
   107  		var payload source.StereoscopeImageSourceMetadata
   108  		if err := json.Unmarshal(target, &payload); err != nil {
   109  			return nil, err
   110  		}
   111  		return payload, nil
   112  
   113  	default:
   114  		return nil, fmt.Errorf("unsupported package metadata type: %+v", t)
   115  	}
   116  }