2017-07-19 22:17:00 +01:00
|
|
|
package testutils
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"go/build"
|
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
|
|
|
"os"
|
|
|
|
"path"
|
|
|
|
"strings"
|
|
|
|
|
2020-04-01 21:18:39 +01:00
|
|
|
"github.com/securego/gosec/v2"
|
2019-04-25 08:25:32 +01:00
|
|
|
"golang.org/x/tools/go/packages"
|
2017-07-19 22:17:00 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
type buildObj struct {
|
2019-04-25 08:25:32 +01:00
|
|
|
pkg *build.Package
|
|
|
|
config *packages.Config
|
|
|
|
pkgs []*packages.Package
|
2017-07-19 22:17:00 +01:00
|
|
|
}
|
|
|
|
|
2017-12-13 07:39:00 +00:00
|
|
|
// TestPackage is a mock package for testing purposes
|
2017-07-19 22:17:00 +01:00
|
|
|
type TestPackage struct {
|
|
|
|
Path string
|
|
|
|
Files map[string]string
|
2020-05-18 08:35:14 +01:00
|
|
|
onDisk bool
|
2017-07-19 22:17:00 +01:00
|
|
|
build *buildObj
|
|
|
|
}
|
|
|
|
|
2017-12-13 07:39:00 +00:00
|
|
|
// NewTestPackage will create a new and empty package. Must call Close() to cleanup
|
2018-10-11 13:45:31 +01:00
|
|
|
// auxiliary files
|
2017-07-19 22:17:00 +01:00
|
|
|
func NewTestPackage() *TestPackage {
|
2019-04-25 08:25:32 +01:00
|
|
|
workingDir, err := ioutil.TempDir("", "gosecs_test")
|
2017-07-19 22:17:00 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return &TestPackage{
|
|
|
|
Path: workingDir,
|
|
|
|
Files: make(map[string]string),
|
2020-05-18 08:35:14 +01:00
|
|
|
onDisk: false,
|
2017-07-19 22:17:00 +01:00
|
|
|
build: nil,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddFile inserts the filename and contents into the package contents
|
|
|
|
func (p *TestPackage) AddFile(filename, content string) {
|
|
|
|
p.Files[path.Join(p.Path, filename)] = content
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *TestPackage) write() error {
|
2020-05-18 08:35:14 +01:00
|
|
|
if p.onDisk {
|
2017-07-19 22:17:00 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
for filename, content := range p.Files {
|
|
|
|
if e := ioutil.WriteFile(filename, []byte(content), 0644); e != nil {
|
|
|
|
return e
|
2020-02-28 11:48:18 +00:00
|
|
|
} // #nosec G306
|
2017-07-19 22:17:00 +01:00
|
|
|
}
|
2020-05-18 08:35:14 +01:00
|
|
|
p.onDisk = true
|
2017-07-19 22:17:00 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build ensures all files are persisted to disk and built
|
|
|
|
func (p *TestPackage) Build() error {
|
|
|
|
if p.build != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if err := p.write(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
basePackage, err := build.Default.ImportDir(p.Path, build.ImportComment)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-12-13 07:39:00 +00:00
|
|
|
var packageFiles []string
|
2017-07-19 22:17:00 +01:00
|
|
|
for _, filename := range basePackage.GoFiles {
|
|
|
|
packageFiles = append(packageFiles, path.Join(p.Path, filename))
|
|
|
|
}
|
|
|
|
|
2019-04-25 08:25:32 +01:00
|
|
|
conf := &packages.Config{
|
2019-10-02 13:05:14 +01:00
|
|
|
Mode: gosec.LoadMode,
|
2019-04-25 08:25:32 +01:00
|
|
|
Tests: false,
|
|
|
|
}
|
|
|
|
pkgs, err := packages.Load(conf, packageFiles...)
|
2017-07-19 22:17:00 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
p.build = &buildObj{
|
2019-04-25 08:25:32 +01:00
|
|
|
pkg: basePackage,
|
|
|
|
config: conf,
|
|
|
|
pkgs: pkgs,
|
2017-07-19 22:17:00 +01:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// CreateContext builds a context out of supplied package context
|
2018-07-19 17:42:25 +01:00
|
|
|
func (p *TestPackage) CreateContext(filename string) *gosec.Context {
|
2017-07-19 22:17:00 +01:00
|
|
|
if err := p.Build(); err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-04-25 08:25:32 +01:00
|
|
|
for _, pkg := range p.build.pkgs {
|
|
|
|
for _, file := range pkg.Syntax {
|
|
|
|
pkgFile := pkg.Fset.File(file.Pos()).Name()
|
2017-07-19 22:17:00 +01:00
|
|
|
strip := fmt.Sprintf("%s%c", p.Path, os.PathSeparator)
|
|
|
|
pkgFile = strings.TrimPrefix(pkgFile, strip)
|
|
|
|
if pkgFile == filename {
|
2018-07-19 17:42:25 +01:00
|
|
|
ctx := &gosec.Context{
|
2020-01-06 08:55:52 +00:00
|
|
|
FileSet: pkg.Fset,
|
|
|
|
Root: file,
|
|
|
|
Config: gosec.NewConfig(),
|
|
|
|
Info: pkg.TypesInfo,
|
|
|
|
Pkg: pkg.Types,
|
|
|
|
Imports: gosec.NewImportTracker(),
|
|
|
|
PassedValues: make(map[string]interface{}),
|
2017-07-19 22:17:00 +01:00
|
|
|
}
|
|
|
|
ctx.Imports.TrackPackages(ctx.Pkg.Imports()...)
|
|
|
|
return ctx
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close will delete the package and all files in that directory
|
|
|
|
func (p *TestPackage) Close() {
|
2020-05-18 08:35:14 +01:00
|
|
|
if p.onDisk {
|
2018-02-07 13:07:24 +00:00
|
|
|
err := os.RemoveAll(p.Path)
|
2018-03-09 05:36:31 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2017-07-19 22:17:00 +01:00
|
|
|
}
|
|
|
|
}
|
2019-04-29 17:32:39 +01:00
|
|
|
|
|
|
|
// Pkgs returns the current built packages
|
|
|
|
func (p *TestPackage) Pkgs() []*packages.Package {
|
|
|
|
if p.build != nil {
|
|
|
|
return p.build.pkgs
|
|
|
|
}
|
|
|
|
return []*packages.Package{}
|
|
|
|
}
|
2021-01-01 19:30:45 +00:00
|
|
|
|
|
|
|
// PrintErrors prints to os.Stderr the accumulated errors of built packages
|
|
|
|
func (p *TestPackage) PrintErrors() int {
|
|
|
|
return packages.PrintErrors(p.Pkgs())
|
|
|
|
}
|