package model import ( "encoding/json" "fmt" "github.com/anchore/syft/syft/source" "github.com/anchore/syft/internal/log" "github.com/anchore/syft/syft/pkg" ) // Package represents a pkg.Package object specialized for JSON marshaling and unmarshalling. type Package struct { PackageBasicData PackageCustomData } // PackageBasicData contains non-ambiguous values (type-wise) from pkg.Package. type PackageBasicData struct { ID string `json:"id"` Name string `json:"name"` Version string `json:"version"` Type pkg.Type `json:"type"` FoundBy string `json:"foundBy"` Locations []source.Coordinates `json:"locations"` Licenses []string `json:"licenses"` Language pkg.Language `json:"language"` CPEs []string `json:"cpes"` PURL string `json:"purl"` } // PackageCustomData contains ambiguous values (type-wise) from pkg.Package. type PackageCustomData struct { MetadataType pkg.MetadataType `json:"metadataType,omitempty"` Metadata interface{} `json:"metadata,omitempty"` } // packageMetadataUnpacker is all values needed from Package to disambiguate ambiguous fields during json unmarshaling. type packageMetadataUnpacker struct { MetadataType pkg.MetadataType `json:"metadataType"` Metadata json.RawMessage `json:"metadata"` } func (p *packageMetadataUnpacker) String() string { return fmt.Sprintf("metadataType: %s, metadata: %s", p.MetadataType, string(p.Metadata)) } // UnmarshalJSON is a custom unmarshaller for handling basic values and values with ambiguous types. // nolint:funlen func (p *Package) UnmarshalJSON(b []byte) error { var basic PackageBasicData if err := json.Unmarshal(b, &basic); err != nil { return err } p.PackageBasicData = basic var unpacker packageMetadataUnpacker if err := json.Unmarshal(b, &unpacker); err != nil { log.Warnf("failed to unmarshall into packageMetadataUnpacker: %v", err) return err } p.MetadataType = unpacker.MetadataType switch p.MetadataType { case pkg.ApkMetadataType: var payload pkg.ApkMetadata if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil { return err } p.Metadata = payload case pkg.RpmdbMetadataType: var payload pkg.RpmdbMetadata if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil { return err } p.Metadata = payload case pkg.DpkgMetadataType: var payload pkg.DpkgMetadata if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil { return err } p.Metadata = payload case pkg.JavaMetadataType: var payload pkg.JavaMetadata if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil { return err } p.Metadata = payload case pkg.RustCargoPackageMetadataType: var payload pkg.CargoPackageMetadata if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil { return err } p.Metadata = payload case pkg.GemMetadataType: var payload pkg.GemMetadata if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil { return err } p.Metadata = payload case pkg.KbPackageMetadataType: var payload pkg.KbPackageMetadata if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil { return err } p.Metadata = payload case pkg.PythonPackageMetadataType: var payload pkg.PythonPackageMetadata if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil { return err } p.Metadata = payload case pkg.NpmPackageJSONMetadataType: var payload pkg.NpmPackageJSONMetadata if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil { return err } p.Metadata = payload case pkg.PhpComposerJSONMetadataType: var payload pkg.PhpComposerJSONMetadata if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil { return err } p.Metadata = payload case pkg.GolangBinMetadataType: var payload pkg.GolangBinMetadata if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil { return err } p.Metadata = payload case pkg.DartPubMetadataType: var payload pkg.DartPubMetadata if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil { return err } p.Metadata = payload default: log.Warnf("unknown package metadata type=%q for packageID=%q", p.MetadataType, p.ID) } return nil }