mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 16:33:21 +01:00
Use the json schema as input for templating (#2542)
* use the json schema as input for templating Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * fix cli tests 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:
parent
11c0b1c234
commit
a32b8d7fc6
17
README.md
17
README.md
@ -555,6 +555,7 @@ select-catalogers: []
|
||||
format:
|
||||
|
||||
# default value for all formats that support the "pretty" option (default is unset)
|
||||
# SYFT_FORMAT_PRETTY env var
|
||||
pretty:
|
||||
|
||||
# all syft-json format options
|
||||
@ -562,6 +563,7 @@ format:
|
||||
|
||||
# include space indention and newlines (inherits default value from 'format.pretty' or 'false' if parent is unset)
|
||||
# note: inherits default value from 'format.pretty' or 'false' if parent is unset
|
||||
# SYFT_FORMAT_JSON_PRETTY env var
|
||||
pretty: false
|
||||
|
||||
# transform any syft-json output to conform to an approximation of the v11.0.1 schema. This includes:
|
||||
@ -571,21 +573,30 @@ format:
|
||||
# that output might not strictly be json schema v11 compliant, however, for consumers that require time to port
|
||||
# over to the final syft 1.0 json output this option can be used to ease the transition.
|
||||
#
|
||||
# Note: long term support for this option is not guaranteed.
|
||||
# Note: long term support for this option is not guaranteed (it may change or break at any time).
|
||||
# SYFT_FORMAT_JSON_LEGACY env var
|
||||
legacy: false
|
||||
|
||||
# all template format options
|
||||
template:
|
||||
# path to the template file to use when rendering the output with the `template` output format.
|
||||
# Note that all template paths are based on the current syft-json schema.
|
||||
# SYFT_TEMPLATE_PATH env var / -t flag
|
||||
# SYFT_FORMAT_TEMPLATE_PATH env var / -t flag
|
||||
path: ""
|
||||
|
||||
# if true, uses the go structs for the syft-json format for templating.
|
||||
# if false, uses the syft-json output for templating (which follows the syft JSON schema exactly).
|
||||
#
|
||||
# Note: long term support for this option is not guaranteed (it may change or break at any time).
|
||||
# SYFT_FORMAT_TEMPLATE_LEGACY env var
|
||||
legacy: false
|
||||
|
||||
# all spdx-json format options
|
||||
spdx-json:
|
||||
|
||||
# include space indention and newlines
|
||||
# note: inherits default value from 'format.pretty' or 'false' if parent is unset
|
||||
# SYFT_FORMAT_SPDX_JSON_PRETTY env var
|
||||
pretty: false
|
||||
|
||||
# all cyclonedx-json format options
|
||||
@ -593,6 +604,7 @@ format:
|
||||
|
||||
# include space indention and newlines
|
||||
# note: inherits default value from 'format.pretty' or 'false' if parent is unset
|
||||
# SYFT_FORMAT_CYCLONEDX_JSON_PRETTY env var
|
||||
pretty: false
|
||||
|
||||
# all cyclonedx-xml format options
|
||||
@ -600,6 +612,7 @@ format:
|
||||
|
||||
# include space indention
|
||||
# note: inherits default value from 'format.pretty' or 'false' if parent is unset
|
||||
# SYFT_FORMAT_CYCLONEDX_XML_PRETTY env var
|
||||
pretty: false
|
||||
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@ var _ clio.FlagAdder = (*FormatTemplate)(nil)
|
||||
type FormatTemplate struct {
|
||||
Enabled bool `yaml:"-" json:"-" mapstructure:"-"`
|
||||
Path string `yaml:"path" json:"path" mapstructure:"path"` // -t template file to use for output
|
||||
Legacy bool `yaml:"legacy" json:"legacy" mapstructure:"legacy"`
|
||||
}
|
||||
|
||||
func DefaultFormatTemplate() FormatTemplate {
|
||||
@ -28,5 +29,6 @@ func (o *FormatTemplate) AddFlags(flags clio.FlagSet) {
|
||||
func (o FormatTemplate) config() template.EncoderConfig {
|
||||
return template.EncoderConfig{
|
||||
TemplatePath: o.Path,
|
||||
Legacy: o.Legacy,
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,9 +72,7 @@ func (o EncodersConfig) Encoders() ([]sbom.FormatEncoder, error) {
|
||||
}
|
||||
|
||||
func (o EncodersConfig) templateEncoders() ([]sbom.FormatEncoder, error) {
|
||||
enc, err := template.NewFormatEncoder(template.EncoderConfig{
|
||||
TemplatePath: o.Template.TemplatePath,
|
||||
})
|
||||
enc, err := template.NewFormatEncoder(o.Template)
|
||||
return []sbom.FormatEncoder{enc}, err
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
package template
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@ -19,6 +21,7 @@ const ID sbom.FormatID = "template"
|
||||
|
||||
type EncoderConfig struct {
|
||||
TemplatePath string
|
||||
Legacy bool
|
||||
syftjson.EncoderConfig
|
||||
}
|
||||
|
||||
@ -90,6 +93,28 @@ func (e encoder) Encode(writer io.Writer, s sbom.SBOM) error {
|
||||
return fmt.Errorf("unable to parse template: %w", err)
|
||||
}
|
||||
|
||||
doc := syftjson.ToFormatModel(s, e.cfg.EncoderConfig)
|
||||
var doc any
|
||||
if e.cfg.Legacy {
|
||||
doc = syftjson.ToFormatModel(s, e.cfg.EncoderConfig)
|
||||
} else {
|
||||
enc, err := syftjson.NewFormatEncoderWithConfig(e.cfg.EncoderConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create json encoder: %w", err)
|
||||
}
|
||||
|
||||
var buff bytes.Buffer
|
||||
if err = enc.Encode(&buff, s); err != nil {
|
||||
return fmt.Errorf("unable to encode json: %w", err)
|
||||
}
|
||||
|
||||
deserializedDoc := make(map[string]any)
|
||||
|
||||
if err = json.Unmarshal(buff.Bytes(), &deserializedDoc); err != nil {
|
||||
return fmt.Errorf("unable to unmarshal json for template: %w", err)
|
||||
}
|
||||
|
||||
doc = deserializedDoc
|
||||
}
|
||||
|
||||
return tmpl.Execute(writer, doc)
|
||||
}
|
||||
|
||||
@ -12,6 +12,42 @@ import (
|
||||
|
||||
var updateSnapshot = flag.Bool("update-template", false, "update the *.golden files for json encoders")
|
||||
|
||||
func TestFormatWithOption_Legacy(t *testing.T) {
|
||||
f, err := NewFormatEncoder(EncoderConfig{
|
||||
TemplatePath: "test-fixtures/legacy/csv.template",
|
||||
Legacy: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
testutil.AssertEncoderAgainstGoldenSnapshot(t,
|
||||
testutil.EncoderSnapshotTestConfig{
|
||||
Subject: testutil.DirectoryInput(t, t.TempDir()),
|
||||
Format: f,
|
||||
UpdateSnapshot: *updateSnapshot,
|
||||
PersistRedactionsInSnapshot: true,
|
||||
IsJSON: false,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestFormatWithOptionAndHasField_Legacy(t *testing.T) {
|
||||
f, err := NewFormatEncoder(EncoderConfig{
|
||||
TemplatePath: "test-fixtures/legacy/csv-hasField.template",
|
||||
Legacy: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
testutil.AssertEncoderAgainstGoldenSnapshot(t,
|
||||
testutil.EncoderSnapshotTestConfig{
|
||||
Subject: testutil.DirectoryInputWithAuthorField(t),
|
||||
Format: f,
|
||||
UpdateSnapshot: *updateSnapshot,
|
||||
PersistRedactionsInSnapshot: true,
|
||||
IsJSON: false,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestFormatWithOption(t *testing.T) {
|
||||
f, err := NewFormatEncoder(EncoderConfig{
|
||||
TemplatePath: "test-fixtures/csv.template",
|
||||
@ -44,7 +80,6 @@ func TestFormatWithOptionAndHasField(t *testing.T) {
|
||||
IsJSON: false,
|
||||
},
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
func TestFormatWithoutOptions(t *testing.T) {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
"Package","Version Installed","Found by","Author"
|
||||
{{- range .Artifacts}}
|
||||
"{{.Name}}","{{.Version}}","{{.FoundBy}}","{{ if hasField .Metadata "Author" }}{{.Metadata.Author}}{{ else }}NO AUTHOR SUPPLIED{{end}}"
|
||||
{{- range .artifacts}}
|
||||
"{{.name}}","{{.version}}","{{.foundBy}}","{{ if index .metadata "author" }}{{.metadata.author}}{{ else }}NO AUTHOR SUPPLIED{{end}}"
|
||||
{{- end}}
|
||||
@ -1,4 +1,4 @@
|
||||
"Package","Version Installed", "Found by"
|
||||
{{- range .Artifacts}}
|
||||
"{{.Name}}","{{.Version}}","{{.FoundBy}}"
|
||||
{{- range .artifacts}}
|
||||
"{{.name}}","{{.version}}","{{.foundBy}}"
|
||||
{{- end}}
|
||||
@ -0,0 +1,4 @@
|
||||
"Package","Version Installed","Found by","Author"
|
||||
{{- range .Artifacts}}
|
||||
"{{.Name}}","{{.Version}}","{{.FoundBy}}","{{ if hasField .Metadata "Author" }}{{.Metadata.Author}}{{ else }}NO AUTHOR SUPPLIED{{end}}"
|
||||
{{- end}}
|
||||
4
syft/format/template/test-fixtures/legacy/csv.template
Normal file
4
syft/format/template/test-fixtures/legacy/csv.template
Normal file
@ -0,0 +1,4 @@
|
||||
"Package","Version Installed", "Found by"
|
||||
{{- range .Artifacts}}
|
||||
"{{.Name}}","{{.Version}}","{{.FoundBy}}"
|
||||
{{- end}}
|
||||
@ -0,0 +1,3 @@
|
||||
"Package","Version Installed","Found by","Author"
|
||||
"package-1","1.0.1","the-cataloger-1","test-author"
|
||||
"package-2","2.0.1","the-cataloger-2","NO AUTHOR SUPPLIED"
|
||||
@ -0,0 +1,3 @@
|
||||
"Package","Version Installed", "Found by"
|
||||
"package-1","1.0.1","the-cataloger-1"
|
||||
"package-2","2.0.1","the-cataloger-2"
|
||||
@ -1,4 +1,4 @@
|
||||
"Package","Version Installed", "Found by"
|
||||
{{- range .Artifacts}}
|
||||
"{{.Name}}","{{.Version}}","{{.FoundBy}}"
|
||||
{{- range .artifacts}}
|
||||
"{{.name}}","{{.version}}","{{.foundBy}}"
|
||||
{{- end}}
|
||||
Loading…
x
Reference in New Issue
Block a user