Skip to content

Commit

Permalink
Automatic SootWrapper Installation (#281)
Browse files Browse the repository at this point in the history
* fix spelling mistakes and upgrade embedded SootWrapper

* Initial working solution

* Refactoring and tests

* Hide some defers and tests from linter

* windows copy test fix

* SootWrapper release archive changed to one file

* use current version for soot-wrapper jar

* Change name to DEBRICKED_VERSION

* fixes after reviews
  • Loading branch information
filip-debricked authored Dec 11, 2024
1 parent 1959b30 commit 1556b21
Show file tree
Hide file tree
Showing 46 changed files with 978 additions and 204 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ jobs:
distribution: 'temurin'

- name: Install Debricked CLI
run: go install -ldflags "-X main.version=${GITHUB_REF#refs/heads/}" ./cmd/debricked
run: |
go install -ldflags "-X main.version=${{ secrets.DEBRICKED_VERSION }}" ./cmd/debricked
- name: Callgraph E2E
run: ./scripts/test_e2e_callgraph_java_version.sh ${{matrix.java}}
Expand Down
8 changes: 7 additions & 1 deletion internal/callgraph/cgexec/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,13 @@ func RunCommand(cmd ICommand, ctx IContext) error {
go func() {
err := cmd.Wait()
if err != nil {
err = fmt.Errorf("Command '%s' executed in folder '%s' gave the following error: \n%s\n%s", args, cmd.GetDir(), cmd.GetStdOut().String(), cmd.GetStdErr().String())
err = fmt.Errorf(
"Command '%s' executed in folder '%s' gave the following error: \n%s\n%s",
args,
cmd.GetDir(),
cmd.GetStdOut().String(),
cmd.GetStdErr().String(),
)
}

done <- err
Expand Down
16 changes: 15 additions & 1 deletion internal/callgraph/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ type IConfig interface {
Kwargs() map[string]string
Build() bool
PackageManager() string
Version() string
}

type Config struct {
Expand All @@ -14,15 +15,24 @@ type Config struct {
kwargs map[string]string
build bool
packageManager string
version string
}

func NewConfig(language string, args []string, kwargs map[string]string, build bool, packageManager string) Config {
func NewConfig(
language string,
args []string,
kwargs map[string]string,
build bool,
packageManager string,
version string,
) Config {
return Config{
language,
args,
kwargs,
build,
packageManager,
version,
}
}

Expand All @@ -45,3 +55,7 @@ func (c Config) Build() bool {
func (c Config) PackageManager() string {
return c.packageManager
}

func (c Config) Version() string {
return c.version
}
1 change: 1 addition & 0 deletions internal/callgraph/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type DebrickedOptions struct {
Inclusions []string
Configs []config.IConfig
Timeout int
Version string
}

type IGenerator interface {
Expand Down
8 changes: 4 additions & 4 deletions internal/callgraph/generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func TestGenerate(t *testing.T) {
)

configs := []config.IConfig{
config.NewConfig("java", []string{}, map[string]string{"pm": "maven"}, true, "maven"),
config.NewConfig("java", []string{}, map[string]string{"pm": "maven"}, true, "maven", ""),
}
ctx, _ := ctxTestdata.NewContextMock()
err := g.Generate(
Expand All @@ -51,7 +51,7 @@ func TestGenerateWithTimer(t *testing.T) {
)

configs := []config.IConfig{
config.NewConfig("java", []string{}, map[string]string{"pm": "maven"}, true, "maven"),
config.NewConfig("java", []string{}, map[string]string{"pm": "maven"}, true, "maven", ""),
}
err := g.GenerateWithTimer(
DebrickedOptions{
Expand All @@ -73,7 +73,7 @@ func TestGenerateInvokeError(t *testing.T) {
)

configs := []config.IConfig{
config.NewConfig("java", []string{}, map[string]string{"pm": "maven"}, true, "maven"),
config.NewConfig("java", []string{}, map[string]string{"pm": "maven"}, true, "maven", ""),
}
ctx, _ := ctxTestdata.NewContextMock()
err := g.Generate(
Expand All @@ -94,7 +94,7 @@ func TestGenerateScheduleError(t *testing.T) {
)

configs := []config.IConfig{
config.NewConfig("java", []string{}, map[string]string{"pm": "maven"}, true, "maven"),
config.NewConfig("java", []string{}, map[string]string{"pm": "maven"}, true, "maven", ""),
}
ctx, _ := ctxTestdata.NewContextMock()
err := g.Generate(
Expand Down
16 changes: 8 additions & 8 deletions internal/callgraph/language/golang/job_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func TestRun(t *testing.T) {
}
}()

config := conf.NewConfig("golang", nil, nil, true, "go")
config := conf.NewConfig("golang", nil, nil, true, "go", "")
ctx, _ := ctxTestdata.NewContextMock()

rootFileDir := filepath.Dir("testdata/fixture/app.go")
Expand All @@ -65,7 +65,7 @@ func TestRun(t *testing.T) {

func TestRunCallgraphMockError(t *testing.T) {
fileWriterMock := &ioTestData.FileWriterMock{}
config := conf.NewConfig("golang", nil, nil, true, "go")
config := conf.NewConfig("golang", nil, nil, true, "go", "")
ctx, _ := ctxTestdata.NewContextMock()
callgraphMock := testdata.CallgraphMock{RunCallGraphError: fmt.Errorf("error")}

Expand All @@ -83,7 +83,7 @@ func TestRunCallgraphMockError(t *testing.T) {

func TestRunPostProcessZipFileError(t *testing.T) {
fileWriterMock := &ioTestData.FileWriterMock{}
config := conf.NewConfig("golang", nil, nil, true, "go")
config := conf.NewConfig("golang", nil, nil, true, "go", "")
ctx, _ := ctxTestdata.NewContextMock()
archiveMock := ioTestData.ArchiveMock{ZipFileError: fmt.Errorf("error")}
fs := io.FileSystem{}
Expand All @@ -98,7 +98,7 @@ func TestRunPostProcessZipFileError(t *testing.T) {

func TestRunPostProcessB64Error(t *testing.T) {
fileWriterMock := &ioTestData.FileWriterMock{}
config := conf.NewConfig("golang", nil, nil, true, "go")
config := conf.NewConfig("golang", nil, nil, true, "go", "")
ctx, _ := ctxTestdata.NewContextMock()
fs := io.FileSystem{}

Expand All @@ -114,7 +114,7 @@ func TestRunPostProcessB64Error(t *testing.T) {

func TestRunPostProcessCleanupError(t *testing.T) {
fileWriterMock := &ioTestData.FileWriterMock{}
config := conf.NewConfig("golang", nil, nil, true, "go")
config := conf.NewConfig("golang", nil, nil, true, "go", "")
ctx, _ := ctxTestdata.NewContextMock()
fs := io.FileSystem{}

Expand All @@ -130,7 +130,7 @@ func TestRunPostProcessCleanupError(t *testing.T) {

func TestRunPostProcessCleanupNoFileExistError(t *testing.T) {
fileWriterMock := &ioTestData.FileWriterMock{}
config := conf.NewConfig("golang", nil, nil, true, "go")
config := conf.NewConfig("golang", nil, nil, true, "go", "")
ctx, _ := ctxTestdata.NewContextMock()
fs := io.FileSystem{}

Expand All @@ -148,7 +148,7 @@ func TestRunPostProcessCleanupNoFileExistError(t *testing.T) {

func TestRunWithErrorsIsNotExistFalse(t *testing.T) {
fileWriterMock := &ioTestData.FileWriterMock{}
config := conf.NewConfig("golang", nil, nil, true, "go")
config := conf.NewConfig("golang", nil, nil, true, "go", "")
ctx, _ := ctxTestdata.NewContextMock()

fs := ioTestData.FileSystemMock{}
Expand All @@ -170,7 +170,7 @@ func TestRunWithErrorsIsNotExistFalse(t *testing.T) {

func TestRunWithErrorsIsNotExistTrue(t *testing.T) {
fileWriterMock := &ioTestData.FileWriterMock{}
config := conf.NewConfig("golang", nil, nil, true, "go")
config := conf.NewConfig("golang", nil, nil, true, "go", "")
ctx, _ := ctxTestdata.NewContextMock()

fs := ioTestData.FileSystemMock{}
Expand Down
10 changes: 5 additions & 5 deletions internal/callgraph/language/golang/strategy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func TestNewStrategy(t *testing.T) {
s = NewStrategy(nil, []string{"file-1", "file-2"}, []string{}, []string{}, nil, nil)
assert.NotNil(t, s)

conf := config.NewConfig("golang", []string{"arg1"}, map[string]string{"kwarg": "val"}, true, "go")
conf := config.NewConfig("golang", []string{"arg1"}, map[string]string{"kwarg": "val"}, true, "go", "")
finder := testdata.NewEmptyFinderMock()
testFiles := []string{"file-1"}
finder.FindRootsNames = testFiles
Expand All @@ -39,7 +39,7 @@ func TestInvokeNoFiles(t *testing.T) {
}

func TestInvokeOneFile(t *testing.T) {
conf := config.NewConfig("golang", []string{"arg1"}, map[string]string{"kwarg": "val"}, true, "go")
conf := config.NewConfig("golang", []string{"arg1"}, map[string]string{"kwarg": "val"}, true, "go", "")
finder := testdata.NewEmptyFinderMock()
testFiles := []string{"file-1"}
finder.FindRootsNames = testFiles
Expand All @@ -51,7 +51,7 @@ func TestInvokeOneFile(t *testing.T) {
}

func TestInvokeManyFiles(t *testing.T) {
conf := config.NewConfig("golang", []string{"arg1"}, map[string]string{"kwarg": "val"}, true, "go")
conf := config.NewConfig("golang", []string{"arg1"}, map[string]string{"kwarg": "val"}, true, "go", "")
finder := testdata.NewEmptyFinderMock()
testFiles := []string{"file-1", "file-2"}
finder.FindRootsNames = testFiles
Expand All @@ -62,7 +62,7 @@ func TestInvokeManyFiles(t *testing.T) {
}

func TestInvokeWithErrors(t *testing.T) {
conf := config.NewConfig("golang", []string{"arg1"}, map[string]string{"kwarg": "val"}, true, "go")
conf := config.NewConfig("golang", []string{"arg1"}, map[string]string{"kwarg": "val"}, true, "go", "")
finder := testdata.NewEmptyFinderMock()
testFiles := []string{"file-1", "file-2"}
finder.FindRootsNames = testFiles
Expand All @@ -82,7 +82,7 @@ func TestInvokeWithErrors(t *testing.T) {
}

func TestInvokeNoRoots(t *testing.T) {
conf := config.NewConfig("golang", []string{"arg1"}, map[string]string{"kwarg": "val"}, true, "go")
conf := config.NewConfig("golang", []string{"arg1"}, map[string]string{"kwarg": "val"}, true, "go", "")
finder := testdata.NewEmptyFinderMock()
testFiles := []string{}
finder.FindRootsNames = testFiles
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
package java

import (
"embed"
"path/filepath"
"fmt"
"regexp"

"github.com/debricked/cli/internal/callgraph/cgexec"
ioFs "github.com/debricked/cli/internal/io"
)

//go:embed embeded/SootWrapper.jar
var jarCallGraph embed.FS

type ICallgraph interface {
RunCallGraphWithSetup() error
RunCallGraph(callgraphJarPath string) error
Expand All @@ -19,11 +16,13 @@ type ICallgraph interface {
type Callgraph struct {
cmdFactory ICmdFactory
filesystem ioFs.IFileSystem
archive ioFs.IArchive
workingDirectory string
targetClasses []string
targetDir string
outputName string
ctx cgexec.IContext
sootHandler ISootHandler
}

func NewCallgraph(
Expand All @@ -33,7 +32,9 @@ func NewCallgraph(
targetDir string,
outputName string,
filesystem ioFs.IFileSystem,
archive ioFs.IArchive,
ctx cgexec.IContext,
sootHandler ISootHandler,
) Callgraph {
return Callgraph{
cmdFactory: cmdFactory,
Expand All @@ -42,43 +43,59 @@ func NewCallgraph(
targetDir: targetDir,
outputName: outputName,
filesystem: filesystem,
archive: archive,
ctx: ctx,
sootHandler: sootHandler,
}
}

func (cg *Callgraph) RunCallGraphWithSetup() error {
jarFile, err := cg.filesystem.FsOpenEmbed(jarCallGraph, "embeded/SootWrapper.jar")
version, err := cg.javaVersion(".")
if err != nil {
return err
}
defer cg.filesystem.FsCloseFile(jarFile)

tempDir, err := cg.filesystem.MkdirTemp("jar")
jarFile, err := cg.sootHandler.GetSootWrapper(version, cg.filesystem, cg.archive)
if err != nil {

return err
}
defer cg.filesystem.RemoveAll(tempDir)
tempJarFile := filepath.Join(tempDir, "SootWrapper.jar")

jarBytes, err := cg.filesystem.FsReadAll(jarFile)
if err != nil {
err = cg.RunCallGraph(jarFile)

return err
}
return err
}

err = cg.filesystem.FsWriteFile(tempJarFile, jarBytes, 0600)
func (cg *Callgraph) javaVersion(path string) (string, error) {
osCmd, err := cg.cmdFactory.MakeJavaVersionCmd(path, cg.ctx)
if err != nil {

return err
return "", err
}

err = cg.RunCallGraph(tempJarFile)

return err
cmd := cgexec.NewCommand(osCmd)
err = cgexec.RunCommand(*cmd, cg.ctx)
if err != nil {
return "", err
}
javaVersionRegex := regexp.MustCompile(`\b(\d+)\.\d+\.\d+\b`)
match := javaVersionRegex.FindStringSubmatch(cmd.GetStdOut().String())
if len(match) > 1 {
return match[1], nil
} else {
return "", fmt.Errorf("no version found in 'java --version' output, are you using a non-numeric version?")
}
}

func (cg *Callgraph) RunCallGraph(callgraphJarPath string) error {
osCmd, err := cg.cmdFactory.MakeCallGraphGenerationCmd(callgraphJarPath, cg.workingDirectory, cg.targetClasses, cg.targetDir, cg.outputName, cg.ctx)
osCmd, err := cg.cmdFactory.MakeCallGraphGenerationCmd(
callgraphJarPath,
cg.workingDirectory,
cg.targetClasses,
cg.targetDir,
cg.outputName,
cg.ctx,
)
if err != nil {

return err
Expand Down
Loading

0 comments on commit 1556b21

Please sign in to comment.