Skip to content

Instantly share code, notes, and snippets.

@wagoodman
Created October 6, 2023 15:23
Show Gist options
  • Save wagoodman/5d654cec6ac23063cb7551d5e8ac973e to your computer and use it in GitHub Desktop.
Save wagoodman/5d654cec6ac23063cb7551d5e8ac973e to your computer and use it in GitHub Desktop.
Using syft source and file resolver objects
package main
import (
"fmt"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/generic"
"github.com/anchore/syft/syft/source"
"io"
)
func main() {
// I've got the following layout:
// .
// ├── main.go
// └── where
// └── lib
// └── is
// └── thing <--- has "contents!" in the file
fmt.Println("via directory source...")
dirExample()
fmt.Println("via file source...")
fileExample()
fmt.Println("with cataloger pattern...")
catalogerExample()
}
func dirExample() {
// we want to make a single source object to access all of the files of interest.
src, err := source.NewFromDirectory(source.DirectoryConfig{
Path: "./where",
})
handleErr(err)
// in the context of a directory the scope doesn't matter, but if this was a container image this would be relevant.
resolver, err := src.FileResolver(source.SquashedScope)
handleErr(err)
// let's look for all files that match the glob pattern "**/thing"
locations, err := resolver.FilesByGlob("**/thing")
handleErr(err)
//// alternatively, we could have referenced the exact path we're interested in.
//// Note that this is the path within the analysis path ("./where/" is the analysis path, so "./lib/is/thing"
//// is the path to the file we're interested in).
//locations, err := resolver.FilesByPath("./lib/is/thing")
//handleErr(err)
for _, location := range locations {
printContents(resolver, location)
}
}
func fileExample() {
// let's look at a single file (not ideal, but possible). This can be treated like a directory that contains
// the single file of interest (in this case "thing").
src, err := source.NewFromFile(source.FileConfig{
Path: "./where/lib/is/thing",
})
handleErr(err)
resolver, err := src.FileResolver(source.SquashedScope)
handleErr(err)
// reference the exact path we're interested in.
locations, err := resolver.FilesByPath("thing")
handleErr(err)
//// alternatively, let's look for all files that match the glob pattern "**/thing"
//locations, err := resolver.FilesByGlob("**/thing")
//handleErr(err)
for _, location := range locations {
printContents(resolver, location)
}
}
func catalogerExample() {
// we have a generic cataloger that allows for handler functions to be registered for specific file patterns.
cat := generic.NewCataloger("my-cataloger").
WithParserByGlobs(thingParser, "**/thing")
// we want to make a single source object to access all of the files of interest.
src, err := source.NewFromDirectory(source.DirectoryConfig{
Path: "./where",
})
handleErr(err)
// in the context of a directory the scope doesn't matter, but if this was a container image this would be relevant.
resolver, err := src.FileResolver(source.SquashedScope)
handleErr(err)
_, _, err = cat.Catalog(resolver)
handleErr(err)
}
func thingParser(_ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
// we're given a reader to the contents of the file we're interested in
contents, err := io.ReadAll(reader)
handleErr(err)
fmt.Println(string(contents))
// assuming that the "thing" we parsed has packages we can return those here
return nil, nil, nil
}
func printContents(resolver file.Resolver, location file.Location) {
// now that we have a location we can get the file contents
reader, err := resolver.FileContentsByLocation(location)
handleErr(err)
contents, err := io.ReadAll(reader)
handleErr(err)
fmt.Println(string(contents))
}
func handleErr(err error) {
if err != nil {
panic(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment