Support library

This commit is contained in:
knqyf263
2019-05-01 15:24:08 +09:00
parent fefe879691
commit e55ec73aba
8 changed files with 261 additions and 16 deletions

View File

@@ -5,13 +5,17 @@ import (
"io"
"time"
"golang.org/x/xerrors"
"github.com/knqyf263/fanal/extractor"
"github.com/knqyf263/go-dep-parser/pkg/types"
"github.com/pkg/errors"
)
var (
osAnalyzers []OSAnalyzer
pkgAnalyzers []PkgAnalyzer
libAnalyzers []LibraryAnalyzer
// ErrUnknownOS occurs when unknown OS is analyzed.
ErrUnknownOS = errors.New("Unknown OS")
@@ -29,6 +33,13 @@ type PkgAnalyzer interface {
RequiredFiles() []string
}
type FilePath string
type LibraryAnalyzer interface {
Analyze(extractor.FileMap) (map[FilePath][]types.Library, error)
RequiredFiles() []string
}
type OS struct {
Name string
Family string
@@ -61,6 +72,10 @@ func RegisterPkgAnalyzer(analyzer PkgAnalyzer) {
pkgAnalyzers = append(pkgAnalyzers, analyzer)
}
func RegisterLibraryAnalyzer(analyzer LibraryAnalyzer) {
libAnalyzers = append(libAnalyzers, analyzer)
}
func RequiredFilenames() []string {
filenames := []string{}
for _, analyzer := range osAnalyzers {
@@ -69,6 +84,9 @@ func RequiredFilenames() []string {
for _, analyzer := range pkgAnalyzers {
filenames = append(filenames, analyzer.RequiredFiles()...)
}
for _, analyzer := range libAnalyzers {
filenames = append(filenames, analyzer.RequiredFiles()...)
}
return filenames
}
@@ -116,3 +134,18 @@ func GetPackages(filesMap extractor.FileMap) ([]Package, error) {
func CheckPackage(pkg *Package) bool {
return pkg.Name != "" && pkg.Version != ""
}
func GetLibraries(filesMap extractor.FileMap) (map[FilePath][]types.Library, error) {
results := map[FilePath][]types.Library{}
for _, analyzer := range libAnalyzers {
libMap, err := analyzer.Analyze(filesMap)
if err != nil {
return nil, xerrors.Errorf("failed to analyze libraries: %w", err)
}
for filePath, libs := range libMap {
results[filePath] = libs
}
}
return results, nil
}

View File

@@ -0,0 +1,43 @@
package bundler
import (
"bytes"
"path/filepath"
"github.com/knqyf263/fanal/analyzer"
"github.com/knqyf263/fanal/extractor"
"github.com/knqyf263/fanal/utils"
"github.com/knqyf263/go-dep-parser/pkg/bundler"
"github.com/knqyf263/go-dep-parser/pkg/types"
"golang.org/x/xerrors"
)
func init() {
analyzer.RegisterLibraryAnalyzer(&bundlerLibraryAnalyzer{})
}
type bundlerLibraryAnalyzer struct{}
func (a bundlerLibraryAnalyzer) Analyze(fileMap extractor.FileMap) (map[analyzer.FilePath][]types.Library, error) {
libMap := map[analyzer.FilePath][]types.Library{}
requiredFiles := a.RequiredFiles()
for filename, content := range fileMap {
basename := filepath.Base(filename)
if !utils.StringInSlice(basename, requiredFiles) {
continue
}
r := bytes.NewBuffer(content)
libs, err := bundler.Parse(r)
if err != nil {
return nil, xerrors.Errorf("invalid Gemfile.lock format: %w", err)
}
libMap[analyzer.FilePath(filename)] = libs
}
return libMap, nil
}
func (a bundlerLibraryAnalyzer) RequiredFiles() []string {
return []string{"Gemfile.lock"}
}

View File

@@ -0,0 +1,43 @@
package composer
import (
"bytes"
"path/filepath"
"github.com/knqyf263/fanal/analyzer"
"github.com/knqyf263/fanal/extractor"
"github.com/knqyf263/fanal/utils"
"github.com/knqyf263/go-dep-parser/pkg/composer"
"github.com/knqyf263/go-dep-parser/pkg/types"
"golang.org/x/xerrors"
)
func init() {
analyzer.RegisterLibraryAnalyzer(&composerLibraryAnalyzer{})
}
type composerLibraryAnalyzer struct{}
func (a composerLibraryAnalyzer) Analyze(fileMap extractor.FileMap) (map[analyzer.FilePath][]types.Library, error) {
libMap := map[analyzer.FilePath][]types.Library{}
requiredFiles := a.RequiredFiles()
for filename, content := range fileMap {
basename := filepath.Base(filename)
if !utils.StringInSlice(basename, requiredFiles) {
continue
}
r := bytes.NewBuffer(content)
libs, err := composer.Parse(r)
if err != nil {
return nil, xerrors.Errorf("invalid composer.lock format: %w", err)
}
libMap[analyzer.FilePath(filename)] = libs
}
return libMap, nil
}
func (a composerLibraryAnalyzer) RequiredFiles() []string {
return []string{"composer.lock"}
}

View File

@@ -0,0 +1,43 @@
package npm
import (
"bytes"
"path/filepath"
"github.com/knqyf263/fanal/analyzer"
"github.com/knqyf263/fanal/extractor"
"github.com/knqyf263/fanal/utils"
"github.com/knqyf263/go-dep-parser/pkg/npm"
"github.com/knqyf263/go-dep-parser/pkg/types"
"golang.org/x/xerrors"
)
func init() {
analyzer.RegisterLibraryAnalyzer(&npmLibraryAnalyzer{})
}
type npmLibraryAnalyzer struct{}
func (a npmLibraryAnalyzer) Analyze(fileMap extractor.FileMap) (map[analyzer.FilePath][]types.Library, error) {
libMap := map[analyzer.FilePath][]types.Library{}
requiredFiles := a.RequiredFiles()
for filename, content := range fileMap {
basename := filepath.Base(filename)
if !utils.StringInSlice(basename, requiredFiles) {
continue
}
r := bytes.NewBuffer(content)
libs, err := npm.Parse(r)
if err != nil {
return nil, xerrors.Errorf("invalid package-lock.json format: %w", err)
}
libMap[analyzer.FilePath(filename)] = libs
}
return libMap, nil
}
func (a npmLibraryAnalyzer) RequiredFiles() []string {
return []string{"package-lock.json"}
}

View File

@@ -0,0 +1,43 @@
package pipenv
import (
"bytes"
"path/filepath"
"github.com/knqyf263/fanal/analyzer"
"github.com/knqyf263/fanal/extractor"
"github.com/knqyf263/fanal/utils"
"github.com/knqyf263/go-dep-parser/pkg/pipenv"
"github.com/knqyf263/go-dep-parser/pkg/types"
"golang.org/x/xerrors"
)
func init() {
analyzer.RegisterLibraryAnalyzer(&pipenvLibraryAnalyzer{})
}
type pipenvLibraryAnalyzer struct{}
func (a pipenvLibraryAnalyzer) Analyze(fileMap extractor.FileMap) (map[analyzer.FilePath][]types.Library, error) {
libMap := map[analyzer.FilePath][]types.Library{}
requiredFiles := a.RequiredFiles()
for filename, content := range fileMap {
basename := filepath.Base(filename)
if !utils.StringInSlice(basename, requiredFiles) {
continue
}
r := bytes.NewBuffer(content)
libs, err := pipenv.Parse(r)
if err != nil {
return nil, xerrors.Errorf("invalid Pipfile.lock format: %w", err)
}
libMap[analyzer.FilePath(filename)] = libs
}
return libMap, nil
}
func (a pipenvLibraryAnalyzer) RequiredFiles() []string {
return []string{"Pipfile.lock"}
}

View File

@@ -3,10 +3,15 @@ package main
import (
"context"
"flag"
"fmt"
"log"
"os"
"github.com/knqyf263/fanal/analyzer"
_ "github.com/knqyf263/fanal/analyzer/library/bundler"
_ "github.com/knqyf263/fanal/analyzer/library/composer"
_ "github.com/knqyf263/fanal/analyzer/library/npm"
_ "github.com/knqyf263/fanal/analyzer/library/pipenv"
_ "github.com/knqyf263/fanal/analyzer/os/alpine"
_ "github.com/knqyf263/fanal/analyzer/os/amazonlinux"
_ "github.com/knqyf263/fanal/analyzer/os/debian"
@@ -16,36 +21,61 @@ import (
_ "github.com/knqyf263/fanal/analyzer/pkg/apk"
_ "github.com/knqyf263/fanal/analyzer/pkg/dpkg"
_ "github.com/knqyf263/fanal/analyzer/pkg/rpm"
"github.com/knqyf263/fanal/extractor"
"golang.org/x/crypto/ssh/terminal"
)
func main() {
ctx := context.Background()
imageName := os.Args[1]
files, err := analyzer.Analyze(ctx, imageName)
if err != nil {
if err := run(); err != nil {
log.Fatal(err)
}
analyzer.GetOS(files)
analyzer.GetPackages(files)
}
func main2() {
func run() (err error) {
ctx := context.Background()
tarPath := flag.String("f", "-", "layer.tar path")
flag.Parse()
args := flag.Args()
var files extractor.FileMap
if len(args) > 0 {
files, err = analyzer.Analyze(ctx, args[1])
if err != nil {
return err
}
} else {
rc, err := openStream(*tarPath)
if err != nil {
log.Fatal(err)
return err
}
files, err := analyzer.AnalyzeFromFile(ctx, rc)
files, err = analyzer.AnalyzeFromFile(ctx, rc)
if err != nil {
log.Fatal(err)
return err
}
analyzer.GetOS(files)
analyzer.GetPackages(files)
}
os, err := analyzer.GetOS(files)
if err != nil {
return err
}
fmt.Printf("%+v\n", os)
pkgs, err := analyzer.GetPackages(files)
if err != nil {
return err
}
fmt.Printf("Packages: %d\n", len(pkgs))
libs, err := analyzer.GetLibraries(files)
if err != nil {
return err
}
for filepath, libList := range libs {
fmt.Printf("%s: %d\n", filepath, len(libList))
}
return nil
}
func openStream(path string) (*os.File, error) {

View File

@@ -266,7 +266,7 @@ func (d DockerExtractor) ExtractFiles(layer io.Reader, filenames []string) (File
// Determine if we should extract the element
extract := false
for _, s := range filenames {
if s == filePath || strings.HasPrefix(fileName, wh) {
if s == filePath || s == fileName || strings.HasPrefix(fileName, wh) {
extract = true
break
}

10
utils/utils.go Normal file
View File

@@ -0,0 +1,10 @@
package utils
func StringInSlice(a string, list []string) bool {
for _, b := range list {
if b == a {
return true
}
}
return false
}