mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 08:23:15 +01:00
Add API examples (#2517)
* [wip] initial syft api examples Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * smooth over some rough edges in the API Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * embed example file Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * address review comments Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * change name of builder function 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
b7a6d5e946
commit
3da679066e
15
examples/README.md
Normal file
15
examples/README.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Syft API Examples
|
||||||
|
|
||||||
|
This directory contains examples of how to use the Syft API.
|
||||||
|
|
||||||
|
- `create_simple_sbom`: Create a simple SBOM from scratch
|
||||||
|
- `create_custom_sbom`: Create an SBOM using as much custom configuration as possible, including a custom cataloger implementation
|
||||||
|
- `decode_sbom`: Take an existing SBOM file (of arbitrary format) and decode it into a Syft SBOM object
|
||||||
|
- `source_detection`: Shows how to detect what to catalog automatically from a user string (e.g. container image vs directory)
|
||||||
|
- `source_from_image`: Construct a source from a only a container image
|
||||||
|
|
||||||
|
You can run any of these examples from this directory with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go run ./DIRECTORY_NAME
|
||||||
|
```
|
||||||
127
examples/create_custom_sbom/alpine_configuration_cataloger.go
Normal file
127
examples/create_custom_sbom/alpine_configuration_cataloger.go
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is a contrived cataloger that attempts to capture useful APK files from the image as if it were a package.
|
||||||
|
This isn't a real cataloger, but it is a good example of how to use API elements to create a custom cataloger.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var _ pkg.Cataloger = (*alpineConfigurationCataloger)(nil)
|
||||||
|
|
||||||
|
type alpineConfigurationCataloger struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAlpineConfigurationCataloger() pkg.Cataloger {
|
||||||
|
return alpineConfigurationCataloger{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m alpineConfigurationCataloger) Name() string {
|
||||||
|
return "apk-configuration-cataloger"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m alpineConfigurationCataloger) Catalog(_ context.Context, resolver file.Resolver) ([]pkg.Package, []artifact.Relationship, error) {
|
||||||
|
version, versionLocations, err := getVersion(resolver)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("unable to get alpine version: %w", err)
|
||||||
|
}
|
||||||
|
if len(versionLocations) == 0 {
|
||||||
|
// this doesn't mean we should stop cataloging, just that we don't have a version to use, thus no package to raise up
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata, metadataLocations, err := newAlpineConfiguration(resolver)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var locations []file.Location
|
||||||
|
locations = append(locations, versionLocations...)
|
||||||
|
locations = append(locations, metadataLocations...)
|
||||||
|
|
||||||
|
p := newPackage(version, *metadata, locations...)
|
||||||
|
|
||||||
|
return []pkg.Package{p}, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPackage(version string, metadata AlpineConfiguration, locations ...file.Location) pkg.Package {
|
||||||
|
return pkg.Package{
|
||||||
|
Name: "alpine-configuration",
|
||||||
|
Version: version,
|
||||||
|
Locations: file.NewLocationSet(locations...),
|
||||||
|
Type: pkg.Type("system-configuration"), // you can make up your own package type here or use an existing one
|
||||||
|
Metadata: metadata,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAlpineConfiguration(resolver file.Resolver) (*AlpineConfiguration, []file.Location, error) {
|
||||||
|
var locations []file.Location
|
||||||
|
|
||||||
|
keys, keyLocations, err := getAPKKeys(resolver)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
locations = append(locations, keyLocations...)
|
||||||
|
|
||||||
|
return &AlpineConfiguration{
|
||||||
|
APKKeys: keys,
|
||||||
|
}, locations, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func getVersion(resolver file.Resolver) (string, []file.Location, error) {
|
||||||
|
locations, err := resolver.FilesByPath("/etc/alpine-release")
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, fmt.Errorf("unable to get alpine version: %w", err)
|
||||||
|
}
|
||||||
|
if len(locations) == 0 {
|
||||||
|
return "", nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
reader, err := resolver.FileContentsByLocation(locations[0])
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, fmt.Errorf("unable to read alpine version: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
version, err := io.ReadAll(reader)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, fmt.Errorf("unable to read alpine version: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(version), locations, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAPKKeys(resolver file.Resolver) (map[string]string, []file.Location, error) {
|
||||||
|
// name-to-content values
|
||||||
|
keyContent := make(map[string]string)
|
||||||
|
|
||||||
|
locations, err := resolver.FilesByGlob("/etc/apk/keys/*.rsa.pub")
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("unable to get apk keys: %w", err)
|
||||||
|
}
|
||||||
|
for _, location := range locations {
|
||||||
|
basename := path.Base(location.RealPath)
|
||||||
|
reader, err := resolver.FileContentsByLocation(location)
|
||||||
|
content, err := io.ReadAll(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("unable to read apk key content at %s: %w", location.RealPath, err)
|
||||||
|
}
|
||||||
|
keyContent[basename] = string(content)
|
||||||
|
}
|
||||||
|
return keyContent, locations, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type AlpineConfiguration struct {
|
||||||
|
APKKeys map[string]string `json:"apkKeys" yaml:"apkKeys"`
|
||||||
|
// Add more data you want to capture as part of the package metadata here...
|
||||||
|
}
|
||||||
138
examples/create_custom_sbom/main.go
Normal file
138
examples/create_custom_sbom/main.go
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft"
|
||||||
|
"github.com/anchore/syft/syft/cataloging"
|
||||||
|
"github.com/anchore/syft/syft/cataloging/filecataloging"
|
||||||
|
"github.com/anchore/syft/syft/cataloging/pkgcataloging"
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
|
"github.com/anchore/syft/syft/sbom"
|
||||||
|
"github.com/anchore/syft/syft/source"
|
||||||
|
)
|
||||||
|
|
||||||
|
const defaultImage = "alpine:3.19"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// automagically get a source.Source for arbitrary string input
|
||||||
|
src := getSource(imageReference())
|
||||||
|
|
||||||
|
// will catalog the given source and return a SBOM keeping in mind several configurable options
|
||||||
|
sbom := getSBOM(src)
|
||||||
|
|
||||||
|
// show a simple package summary
|
||||||
|
summarize(sbom)
|
||||||
|
|
||||||
|
// show the alpine-configuration cataloger results
|
||||||
|
showAlpineConfiguration(sbom)
|
||||||
|
}
|
||||||
|
|
||||||
|
func imageReference() string {
|
||||||
|
// read an image string reference from the command line or use a default
|
||||||
|
if len(os.Args) > 1 {
|
||||||
|
return os.Args[1]
|
||||||
|
}
|
||||||
|
return defaultImage
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSource(input string) source.Source {
|
||||||
|
fmt.Println("detecting source type for input:", input, "...")
|
||||||
|
|
||||||
|
detection, err := source.Detect(input,
|
||||||
|
source.DetectConfig{
|
||||||
|
DefaultImageSource: "docker",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
src, err := detection.NewSource(source.DefaultDetectionSourceConfig())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return src
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSBOM(src source.Source) sbom.SBOM {
|
||||||
|
fmt.Println("creating SBOM...")
|
||||||
|
|
||||||
|
cfg := syft.DefaultCreateSBOMConfig().
|
||||||
|
// run the catalogers in parallel (5 at a time concurrently max)
|
||||||
|
WithParallelism(5).
|
||||||
|
// bake a specific tool name and version into the SBOM
|
||||||
|
WithTool("my-tool", "v1.0").
|
||||||
|
// catalog all files with 3 digests
|
||||||
|
WithFilesConfig(
|
||||||
|
filecataloging.DefaultConfig().
|
||||||
|
WithSelection(file.AllFilesSelection).
|
||||||
|
WithHashers(
|
||||||
|
crypto.MD5,
|
||||||
|
crypto.SHA1,
|
||||||
|
crypto.SHA256,
|
||||||
|
),
|
||||||
|
).
|
||||||
|
// only use OS related catalogers that would have been used with the kind of
|
||||||
|
// source type (container image or directory), but also add a specific python cataloger
|
||||||
|
WithCatalogerSelection(
|
||||||
|
pkgcataloging.NewSelectionRequest().
|
||||||
|
WithSubSelections("os").
|
||||||
|
WithAdditions("python-package-cataloger"),
|
||||||
|
).
|
||||||
|
// which relationships to include
|
||||||
|
WithRelationshipsConfig(
|
||||||
|
cataloging.RelationshipsConfig{
|
||||||
|
PackageFileOwnership: true,
|
||||||
|
PackageFileOwnershipOverlap: true,
|
||||||
|
ExcludeBinaryPackagesWithFileOwnershipOverlap: true,
|
||||||
|
},
|
||||||
|
).
|
||||||
|
// add your own cataloger to the mix
|
||||||
|
WithCatalogers(
|
||||||
|
pkgcataloging.NewAlwaysEnabledCatalogerReference(
|
||||||
|
newAlpineConfigurationCataloger(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
s, err := syft.CreateSBOM(context.Background(), src, cfg)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return *s
|
||||||
|
}
|
||||||
|
|
||||||
|
func summarize(s sbom.SBOM) {
|
||||||
|
fmt.Printf("Cataloged %d packages:\n", s.Artifacts.Packages.PackageCount())
|
||||||
|
for _, p := range s.Artifacts.Packages.Sorted() {
|
||||||
|
fmt.Printf(" - %s@%s (%s)\n", p.Name, p.Version, p.Type)
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
|
func showAlpineConfiguration(s sbom.SBOM) {
|
||||||
|
pkgs := s.Artifacts.Packages.PackagesByName("alpine-configuration")
|
||||||
|
if len(pkgs) == 0 {
|
||||||
|
fmt.Println("no alpine-configuration package found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p := pkgs[0]
|
||||||
|
|
||||||
|
fmt.Printf("All 'alpine-configuration' packages: %s\n", p.Version)
|
||||||
|
meta, err := yaml.Marshal(p.Metadata)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fmt.Println(string(meta))
|
||||||
|
|
||||||
|
}
|
||||||
74
examples/create_simple_sbom/main.go
Normal file
74
examples/create_simple_sbom/main.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft"
|
||||||
|
"github.com/anchore/syft/syft/format"
|
||||||
|
"github.com/anchore/syft/syft/format/syftjson"
|
||||||
|
"github.com/anchore/syft/syft/sbom"
|
||||||
|
"github.com/anchore/syft/syft/source"
|
||||||
|
)
|
||||||
|
|
||||||
|
const defaultImage = "alpine:3.19"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// automagically get a source.Source for arbitrary string input
|
||||||
|
src := getSource(imageReference())
|
||||||
|
|
||||||
|
// catalog the given source and return a SBOM
|
||||||
|
sbom := getSBOM(src)
|
||||||
|
|
||||||
|
// take the SBOM object and encode it into the syft-json representation
|
||||||
|
bytes := formatSBOM(sbom)
|
||||||
|
|
||||||
|
// show the SBOM!
|
||||||
|
fmt.Println(string(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
func imageReference() string {
|
||||||
|
// read an image string reference from the command line or use a default
|
||||||
|
if len(os.Args) > 1 {
|
||||||
|
return os.Args[1]
|
||||||
|
}
|
||||||
|
return defaultImage
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSource(input string) source.Source {
|
||||||
|
detection, err := source.Detect(input,
|
||||||
|
source.DetectConfig{
|
||||||
|
DefaultImageSource: "docker",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
src, err := detection.NewSource(source.DefaultDetectionSourceConfig())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return src
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSBOM(src source.Source) sbom.SBOM {
|
||||||
|
s, err := syft.CreateSBOM(context.Background(), src, nil)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return *s
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatSBOM(s sbom.SBOM) []byte {
|
||||||
|
bytes, err := format.Encode(s, syftjson.NewFormatEncoder())
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return bytes
|
||||||
|
}
|
||||||
4964
examples/decode_sbom/alpine.syft.json
Normal file
4964
examples/decode_sbom/alpine.syft.json
Normal file
File diff suppressed because it is too large
Load Diff
53
examples/decode_sbom/main.go
Normal file
53
examples/decode_sbom/main.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/format"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed alpine.syft.json
|
||||||
|
var sbomContents string
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// decode the SBOM
|
||||||
|
fmt.Println("decoding SBOM...")
|
||||||
|
sbom, sbomFormat, formatVersion, err := format.Decode(sbomReader())
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("failed to decode sbom: %+v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("SBOM format: %s@%s\n", sbomFormat, formatVersion)
|
||||||
|
|
||||||
|
// print packages found...
|
||||||
|
fmt.Println("\nPackages found:")
|
||||||
|
for _, pkg := range sbom.Artifacts.Packages.Sorted() {
|
||||||
|
fmt.Printf(" %s : %s@%s (%s)\n", pkg.ID(), pkg.Name, pkg.Version, pkg.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
// print files found...
|
||||||
|
fmt.Println("\nFiles found:")
|
||||||
|
for c, f := range sbom.Artifacts.FileMetadata {
|
||||||
|
fmt.Printf(" %s : %s\n", c.ID(), f.Path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sbomReader() io.Reader {
|
||||||
|
// read file from sys args (or use the default)
|
||||||
|
var reader io.Reader
|
||||||
|
if len(os.Args) < 2 {
|
||||||
|
reader = strings.NewReader(sbomContents)
|
||||||
|
} else {
|
||||||
|
var err error
|
||||||
|
reader, err = os.Open(os.Args[1])
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reader
|
||||||
|
}
|
||||||
62
examples/source_detection/main.go
Normal file
62
examples/source_detection/main.go
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/source"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
This example demonstrates how to create a source object from a generic string input.
|
||||||
|
|
||||||
|
Example inputs:
|
||||||
|
alpine:3.19 pull an image from the docker daemon, podman, or the registry (based on what's available)
|
||||||
|
./my.tar interpret a local archive as an OCI archive, docker save archive, or raw file from disk to catalog
|
||||||
|
docker:yourrepo/yourimage:tag explicitly use the Docker daemon
|
||||||
|
podman:yourrepo/yourimage:tag explicitly use the Podman daemon
|
||||||
|
registry:yourrepo/yourimage:tag pull image directly from a registry (no container runtime required)
|
||||||
|
docker-archive:path/to/yourimage.tar use a tarball from disk for archives created from "docker save"
|
||||||
|
oci-archive:path/to/yourimage.tar use a tarball from disk for OCI archives (from Skopeo or otherwise)
|
||||||
|
oci-dir:path/to/yourimage read directly from a path on disk for OCI layout directories (from Skopeo or otherwise)
|
||||||
|
singularity:path/to/yourimage.sif read directly from a Singularity Image Format (SIF) container on disk
|
||||||
|
dir:path/to/yourproject read directly from a path on disk (any directory)
|
||||||
|
file:path/to/yourproject/file read directly from a path on disk (any single file)
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
const defaultImage = "alpine:3.19"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
detection, err := source.Detect(
|
||||||
|
imageReference(),
|
||||||
|
source.DetectConfig{
|
||||||
|
DefaultImageSource: "docker",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
src, err := detection.NewSource(source.DefaultDetectionSourceConfig())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show a basic description of the source to the screen
|
||||||
|
enc := json.NewEncoder(os.Stdout)
|
||||||
|
enc.SetIndent("", " ")
|
||||||
|
if err := enc.Encode(src.Describe()); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func imageReference() string {
|
||||||
|
// read an image string reference from the command line or use a default
|
||||||
|
if len(os.Args) > 1 {
|
||||||
|
return os.Args[1]
|
||||||
|
}
|
||||||
|
return defaultImage
|
||||||
|
}
|
||||||
50
examples/source_from_image/main.go
Normal file
50
examples/source_from_image/main.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/anchore/stereoscope/pkg/image"
|
||||||
|
"github.com/anchore/syft/syft/source"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
This shows how to create a source from an image reference. This is useful when you are programmatically always
|
||||||
|
expecting to catalog a container image and always from the same source (e.g. docker daemon, podman, registry, etc).
|
||||||
|
*/
|
||||||
|
|
||||||
|
const defaultImage = "alpine:3.19"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
platform, err := image.NewPlatform("linux/amd64")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
src, err := source.NewFromStereoscopeImage(
|
||||||
|
source.StereoscopeImageConfig{
|
||||||
|
Reference: imageReference(),
|
||||||
|
From: image.OciRegistrySource, // always use the registry, there are several other "Source" options here
|
||||||
|
Platform: platform,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show a basic description of the source to the screen
|
||||||
|
enc := json.NewEncoder(os.Stdout)
|
||||||
|
enc.SetIndent("", " ")
|
||||||
|
if err := enc.Encode(src.Describe()); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func imageReference() string {
|
||||||
|
// read an image string reference from the command line or use a default
|
||||||
|
if len(os.Args) > 1 {
|
||||||
|
return os.Args[1]
|
||||||
|
}
|
||||||
|
return defaultImage
|
||||||
|
}
|
||||||
@ -72,7 +72,12 @@ func (cfg Config) WithSelection(selection file.Selection) Config {
|
|||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg Config) WithHashers(hashers []crypto.Hash) Config {
|
func (cfg Config) WithHashers(hashers ...crypto.Hash) Config {
|
||||||
cfg.Hashers = intFile.NormalizeHashes(hashers)
|
cfg.Hashers = intFile.NormalizeHashes(hashers)
|
||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cfg Config) WithContentConfig(content filecontent.Config) Config {
|
||||||
|
cfg.Content = content
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|||||||
@ -139,7 +139,7 @@ func TestCreateSBOMConfig_makeTaskGroups(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "no file digest cataloger",
|
name: "no file digest cataloger",
|
||||||
src: imgSrc,
|
src: imgSrc,
|
||||||
cfg: DefaultCreateSBOMConfig().WithFilesConfig(filecataloging.DefaultConfig().WithHashers(nil)),
|
cfg: DefaultCreateSBOMConfig().WithFilesConfig(filecataloging.DefaultConfig().WithHashers()),
|
||||||
wantTaskNames: [][]string{
|
wantTaskNames: [][]string{
|
||||||
environmentCatalogerNames(),
|
environmentCatalogerNames(),
|
||||||
pkgCatalogerNamesWithTagOrName(t, "image"),
|
pkgCatalogerNamesWithTagOrName(t, "image"),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user