package opensca
import (
"context"
"path/filepath"
"reflect"
"time"
"github.com/xmirrorsecurity/opensca-cli/v3/opensca/logs"
"github.com/xmirrorsecurity/opensca-cli/v3/opensca/model"
"github.com/xmirrorsecurity/opensca-cli/v3/opensca/sca"
"github.com/xmirrorsecurity/opensca-cli/v3/opensca/sca/filter"
"github.com/xmirrorsecurity/opensca-cli/v3/opensca/walk"
)
type TaskArg struct {
DataOrigin string
Name string
Timeout int
Sca []sca.Sca
ExtractFileFilter walk.ExtractFileFilter
IgnoreFileFilter walk.ExtractFileFilter
ResCallFunc model.ResCallback
}
type TaskResult struct {
Arg *TaskArg
Deps []*model.DepGraph
Error error
Start time.Time
End time.Time
Size int64
}
func RunTask(ctx context.Context, arg *TaskArg) (result TaskResult) {
result.Start = time.Now()
defer func() {
result.End = time.Now()
result.Arg = arg
}()
if arg == nil {
arg = &TaskArg{DataOrigin: "./"}
}
if arg.ExtractFileFilter == nil {
arg.ExtractFileFilter = filter.CompressFile
}
if arg.Name == "" {
arg.Name = filepath.Base(arg.DataOrigin)
}
if arg.Timeout > 0 {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, time.Duration(arg.Timeout)*time.Second)
if cancel != nil {
defer cancel()
}
}
if len(arg.Sca) == 0 {
arg.Sca = sca.AllSca
}
result.Size, result.Error = walk.Walk(ctx, arg.Name, arg.DataOrigin, func(relpath string) bool {
if arg.ExtractFileFilter != nil && arg.ExtractFileFilter(relpath) {
return true
}
for _, sca := range arg.Sca {
if sca.Filter(relpath) {
return true
}
}
return false
}, arg.IgnoreFileFilter, func(parent *model.File, files []*model.File) {
for _, sca := range arg.Sca {
fs := []*model.File{}
for _, f := range files {
if sca.Filter(f.Relpath()) {
fs = append(fs, f)
}
}
if len(fs) == 0 {
continue
}
scaType := reflect.TypeOf(sca).String()
logs.Debugf("start sca:%s file:%s files:%v", scaType, parent, fs)
defer func() {
if err := recover(); err != nil {
logs.Errorf("sca:%s file:%s err:%v", scaType, parent, err)
}
}()
sca.Sca(ctx, parent, fs, func(file *model.File, root ...*model.DepGraph) {
for _, dep := range root {
if dep == nil {
continue
}
count := 0
dep.ForEachNode(func(p, n *model.DepGraph) bool { count++; return true })
logs.Infof("file:%s deps:%d language:%s", file.Relpath(), count, sca.Language())
dep.Build(false, sca.Language())
result.Deps = append(result.Deps, dep)
if arg.ResCallFunc != nil {
arg.ResCallFunc(file, dep)
}
}
})
logs.Debugf("end sca:%s file:%s", scaType, parent)
}
})
return result
}