Skip to content

Commit

Permalink
feat: add capability to have folder-specific additional parameters [I…
Browse files Browse the repository at this point in the history
…DE-567] (#646)

Co-authored-by: bastiandoetsch <[email protected]>
  • Loading branch information
bastiandoetsch and bastiandoetsch authored Sep 4, 2024
1 parent fa9fa40 commit 00d8c2c
Show file tree
Hide file tree
Showing 14 changed files with 181 additions and 49 deletions.
27 changes: 26 additions & 1 deletion application/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ import (
frameworkLogging "github.com/snyk/go-application-framework/pkg/logging"
"github.com/snyk/go-application-framework/pkg/runtimeinfo"
"github.com/snyk/go-application-framework/pkg/workflow"

"github.com/snyk/snyk-ls/infrastructure/cli/cli_constants"
"github.com/snyk/snyk-ls/infrastructure/cli/filename"
"github.com/snyk/snyk-ls/internal/concurrency"
gitconfig "github.com/snyk/snyk-ls/internal/git_config"
"github.com/snyk/snyk-ls/internal/logging"
"github.com/snyk/snyk-ls/internal/storage"
"github.com/snyk/snyk-ls/internal/types"
Expand Down Expand Up @@ -200,6 +200,7 @@ type Config struct {
m sync.RWMutex
clientProtocolVersion string
isOpenBrowserActionEnabled bool
folderAdditionalParameters map[string][]string
}

func CurrentConfig() *Config {
Expand Down Expand Up @@ -231,6 +232,7 @@ func IsDevelopment() bool {
// New creates a configuration object with default values
func New() *Config {
c := &Config{}
c.folderAdditionalParameters = make(map[string][]string)
c.scrubbingDict = frameworkLogging.ScrubbingDict{}
c.logger = getNewScrubbingLogger(c)
c.cliSettings = NewCliSettings(c)
Expand Down Expand Up @@ -1119,3 +1121,26 @@ func (c *Config) SetSnykOpenBrowserActionsEnabled(enable bool) {
defer c.m.Unlock()
c.isOpenBrowserActionEnabled = enable
}

func (c *Config) FolderConfig(path string) *types.FolderConfig {
var folderConfig *types.FolderConfig
var err error
folderConfig, err = gitconfig.GetOrCreateFolderConfig(path)
if err != nil {
folderConfig = &types.FolderConfig{}
}
c.m.RLock()
addParams, ok := c.folderAdditionalParameters[path]
if ok {
folderConfig.AdditionalParameters = addParams
}
c.m.RUnlock()
return folderConfig
}

func (c *Config) SetAdditionalParameters(path string, parameters []string) {
c.m.Lock()
defer c.m.Unlock()

c.folderAdditionalParameters[path] = parameters
}
5 changes: 5 additions & 0 deletions application/server/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ func updateSnykOpenBrowserCodeActions(c *config.Config, settings types.Settings)

func updateFolderConfig(c *config.Config, settings types.Settings) {
gitconfig.SetBaseBranch(c.Logger(), settings.FolderConfigs)
for _, folderConfig := range settings.FolderConfigs {
if len(folderConfig.AdditionalParameters) > 0 {
c.SetAdditionalParameters(folderConfig.FolderPath, folderConfig.AdditionalParameters)
}
}
}

func updateAuthenticationMethod(c *config.Config, settings types.Settings) {
Expand Down
25 changes: 14 additions & 11 deletions application/server/configuration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import (
"github.com/stretchr/testify/assert"

"github.com/snyk/go-application-framework/pkg/configuration"
gitconfig "github.com/snyk/snyk-ls/internal/git_config"
"github.com/snyk/snyk-ls/internal/types"

"github.com/snyk/snyk-ls/application/config"
Expand Down Expand Up @@ -200,8 +199,9 @@ func Test_UpdateSettings(t *testing.T) {
EnableSnykOpenBrowserActions: "true",
FolderConfigs: []types.FolderConfig{
{
FolderPath: tempDir1,
BaseBranch: "testBaseBranch1",
FolderPath: tempDir1,
BaseBranch: "testBaseBranch1",
AdditionalParameters: []string{"--file=asdf"},
},
{
FolderPath: tempDir2,
Expand All @@ -210,6 +210,12 @@ func Test_UpdateSettings(t *testing.T) {
},
}

err := initTestRepo(t, tempDir1)
assert.NoError(t, err)

err = initTestRepo(t, tempDir2)
assert.NoError(t, err)

UpdateSettings(c, settings)

assert.Equal(t, false, c.IsSnykCodeEnabled())
Expand All @@ -235,17 +241,14 @@ func Test_UpdateSettings(t *testing.T) {
assert.Equal(t, sampleSettings.SnykCodeApi, c.SnykCodeApi())
assert.Equal(t, true, c.IsSnykOpenBrowserActionEnabled())

err := initTestRepo(t, tempDir1)
assert.NoError(t, err)
folderConfig1, err := gitconfig.GetOrCreateFolderConfig(tempDir1)
assert.NoError(t, err)
folderConfig1 := c.FolderConfig(tempDir1)
assert.NotEmpty(t, folderConfig1.BaseBranch)
assert.Equal(t, settings.FolderConfigs[0].AdditionalParameters[0],
folderConfig1.AdditionalParameters[0])

err = initTestRepo(t, tempDir2)
assert.NoError(t, err)
folderConfig2, err := gitconfig.GetOrCreateFolderConfig(tempDir2)
assert.NoError(t, err)
folderConfig2 := c.FolderConfig(tempDir2)
assert.NotEmpty(t, folderConfig2.BaseBranch)
assert.Empty(t, folderConfig2.AdditionalParameters)

assert.Eventually(t, func() bool { return "a fancy token" == c.Token() }, time.Second*5, time.Millisecond)
})
Expand Down
4 changes: 3 additions & 1 deletion application/server/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@

package server

const nodejsGoof = "https://github.com/snyk-labs/nodejs-goof"
import "github.com/snyk/snyk-ls/internal/testutil"

const nodejsGoof = testutil.NodejsGoof
10 changes: 3 additions & 7 deletions domain/ide/command/folder_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ package command
import (
"context"
"fmt"

"github.com/snyk/snyk-ls/domain/snyk/persistence"
gitconfig "github.com/snyk/snyk-ls/internal/git_config"
noti "github.com/snyk/snyk-ls/internal/notification"

"github.com/pkg/errors"
Expand All @@ -40,15 +40,11 @@ func HandleFolders(ctx context.Context, srv types.Server, notifier noti.Notifier
}

func sendFolderConfigsNotification(notifier noti.Notifier) {
logger := config.CurrentConfig().Logger().With().Str("method", "HandleFolders").Logger()
c := config.CurrentConfig()
ws := workspace.Get()
var folderConfigs []types.FolderConfig
for _, f := range ws.Folders() {
folderConfig, err := gitconfig.GetOrCreateFolderConfig(f.Path())
if err != nil {
logger.Warn().Err(err).Msg("error determining folder config")
continue
}
folderConfig := c.FolderConfig(f.Path())
folderConfigs = append(folderConfigs, *folderConfig)
}
folderConfigsParam := types.FolderConfigsParam{FolderConfigs: folderConfigs}
Expand Down
2 changes: 1 addition & 1 deletion infrastructure/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func (c *SnykCli) Execute(ctx context.Context, cmd []string, workingDir string)
c.c.Logger().Debug().Str("method", method).Interface("cmd", cmd).Str("workingDir", workingDir).Msg("calling Snyk CLI")

// set deadline to handle CLI hanging when obtaining semaphore
ctx, cancel := context.WithDeadline(ctx, time.Now().Add(c.cliTimeout))
ctx, cancel := context.WithTimeout(ctx, c.cliTimeout)
defer cancel()

output, err := c.doExecute(ctx, cmd, workingDir)
Expand Down
8 changes: 5 additions & 3 deletions infrastructure/oss/cli_package_scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ package oss

import (
"context"
"github.com/snyk/snyk-ls/domain/snyk/scanner"
"path/filepath"
"strings"

"github.com/snyk/snyk-ls/domain/snyk/scanner"

"github.com/snyk/snyk-ls/application/config"
"github.com/snyk/snyk-ls/domain/snyk"
"github.com/snyk/snyk-ls/infrastructure/oss/parser"
Expand Down Expand Up @@ -68,7 +69,7 @@ func (cliScanner *CLIScanner) ScanPackages(
notCached := cliScanner.updateCachedDependencies(dependencies)

if len(notCached) > 0 {
commandFunc := func(_ []string, _ map[string]bool) (deps []string) {
commandFunc := func(_ []string, _ map[string]bool, path string) (deps []string) {
for _, d := range notCached {
deps = append(deps, d.ArtifactID+"@"+d.Version)
}
Expand All @@ -77,9 +78,10 @@ func (cliScanner *CLIScanner) ScanPackages(
"": true,
"--all-projects": true,
"--dev": true,
"--file": true,
}

return cliScanner.prepareScanCommand(deps, blacklist)
return cliScanner.prepareScanCommand(deps, blacklist, path)
}
_, err := cliScanner.scanInternal(ctx, path, commandFunc)
if err != nil {
Expand Down
18 changes: 14 additions & 4 deletions infrastructure/oss/cli_scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ func (cliScanner *CLIScanner) Scan(ctx context.Context, path string, _ string) (
return cliScanner.scanInternal(ctx, path, cliScanner.prepareScanCommand)
}

func (cliScanner *CLIScanner) scanInternal(ctx context.Context, path string, commandFunc func(args []string, parameterBlacklist map[string]bool) []string) ([]snyk.Issue, error) {
func (cliScanner *CLIScanner) scanInternal(ctx context.Context, path string, commandFunc func(args []string, parameterBlacklist map[string]bool, path string) []string) ([]snyk.Issue, error) {
method := "cliScanner.Scan"
logger := cliScanner.config.Logger().With().Str("method", method).Logger()

Expand Down Expand Up @@ -203,7 +203,7 @@ func (cliScanner *CLIScanner) scanInternal(ctx context.Context, path string, com
cliScanner.runningScans[workDir] = newScan
cliScanner.mutex.Unlock()

cmd := commandFunc([]string{workDir}, map[string]bool{"": true})
cmd := commandFunc([]string{workDir}, map[string]bool{"": true}, workDir)
res, scanErr := cliScanner.cli.Execute(ctx, cmd, workDir)
noCancellation := ctx.Err() == nil
if scanErr != nil {
Expand All @@ -230,7 +230,8 @@ func (cliScanner *CLIScanner) scanInternal(ctx context.Context, path string, com
return issues, nil
}

func (cliScanner *CLIScanner) prepareScanCommand(args []string, parameterBlacklist map[string]bool) []string {
func (cliScanner *CLIScanner) prepareScanCommand(args []string, parameterBlacklist map[string]bool, path string) []string {
c := config.CurrentConfig()
allProjectsParamAllowed := true
allProjectsParam := "--all-projects"

Expand All @@ -240,7 +241,14 @@ func (cliScanner *CLIScanner) prepareScanCommand(args []string, parameterBlackli
})
cmd = append(cmd, args...)
cmd = append(cmd, "--json")

additionalParams := cliScanner.config.CliSettings().AdditionalOssParameters

// append folder parameters if set
folderConfig := c.FolderConfig(path)
additionalParams = append(additionalParams, folderConfig.AdditionalParameters...)

// now add all additional parameters, skipping blacklisted ones
for _, parameter := range additionalParams {
p := strings.Split(parameter, "=")[0]
if parameterBlacklist[p] {
Expand All @@ -249,7 +257,9 @@ func (cliScanner *CLIScanner) prepareScanCommand(args []string, parameterBlackli
if allProjectsParamBlacklist[p] {
allProjectsParamAllowed = false
}
cmd = append(cmd, parameter)
if parameter != allProjectsParam {
cmd = append(cmd, parameter)
}
}

// only append --all-projects, if it's not on the global blacklist
Expand Down
19 changes: 15 additions & 4 deletions infrastructure/oss/oss_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (

"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/snyk/snyk-ls/application/config"
"github.com/snyk/snyk-ls/domain/snyk"
Expand All @@ -37,6 +38,7 @@ import (
"github.com/snyk/snyk-ls/internal/observability/error_reporting"
"github.com/snyk/snyk-ls/internal/observability/performance"
"github.com/snyk/snyk-ls/internal/testutil"
"github.com/snyk/snyk-ls/internal/types"
)

const testDataPackageJson = "/testdata/package.json"
Expand Down Expand Up @@ -356,9 +358,18 @@ func Test_prepareScanCommand(t *testing.T) {
}
c.SetCliSettings(&settings)

cmd := scanner.prepareScanCommand([]string{"a"}, map[string]bool{})
repo, err := testutil.SetupCustomTestRepo(t, t.TempDir(), testutil.NodejsGoof, "", c.Logger())
require.NoError(t, err)
folderConfigs := []types.FolderConfig{{
FolderPath: repo,
AdditionalParameters: []string{"--file=pom.xml"},
}}

assert.Contains(t, cmd, "--all-projects")
c.SetAdditionalParameters(repo, folderConfigs[0].AdditionalParameters)

cmd := scanner.prepareScanCommand([]string{"a"}, map[string]bool{}, repo)

assert.Contains(t, cmd, "--file=pom.xml")
assert.Contains(t, cmd, "-d")
})

Expand All @@ -369,7 +380,7 @@ func Test_prepareScanCommand(t *testing.T) {
}
c.SetCliSettings(&settings)

cmd := scanner.prepareScanCommand([]string{"a"}, map[string]bool{})
cmd := scanner.prepareScanCommand([]string{"a"}, map[string]bool{}, "")

assert.NotContains(t, cmd, "--all-projects")
assert.Contains(t, cmd, "-d")
Expand All @@ -383,7 +394,7 @@ func Test_prepareScanCommand(t *testing.T) {
}
c.SetCliSettings(&settings)

cmd := scanner.prepareScanCommand([]string{"a"}, map[string]bool{})
cmd := scanner.prepareScanCommand([]string{"a"}, map[string]bool{}, "")

assert.Contains(t, cmd, "--all-projects")
assert.Len(t, cmd, 4)
Expand Down
48 changes: 31 additions & 17 deletions internal/git_config/git_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package gitconfig

import (
"fmt"

"github.com/rs/zerolog"

"github.com/go-git/go-git/v5"
Expand Down Expand Up @@ -50,6 +51,20 @@ func GetOrCreateFolderConfig(path string) (*types.FolderConfig, error) {
return nil, fmt.Errorf("no local branches found")
}

baseBranch, err := getBaseBranch(repoConfig, folderSection, localBranches)
if err != nil {
return nil, err
}

return &types.FolderConfig{
FolderPath: path,
BaseBranch: baseBranch,
LocalBranches: localBranches,
AdditionalParameters: nil,
}, nil
}

func getBaseBranch(repoConfig *config2.Config, folderSection *config.Subsection, localBranches []string) (string, error) {
// base branch is either overwritten or we return the default branch
baseBranch := repoConfig.Init.DefaultBranch
if folderSection.HasOption(baseBranchKey) {
Expand All @@ -62,15 +77,10 @@ func GetOrCreateFolderConfig(path string) (*types.FolderConfig, error) {
} else if slices.Contains(localBranches, "master") {
baseBranch = "master"
} else {
return nil, fmt.Errorf("could not determine base branch")
return "", fmt.Errorf("could not determine base branch")
}
}

return &types.FolderConfig{
FolderPath: path,
BaseBranch: baseBranch,
LocalBranches: localBranches,
}, nil
return baseBranch, nil
}

func getConfigSection(path string) (*git.Repository, *config2.Config, *config.Config, *config.Subsection, error) {
Expand Down Expand Up @@ -108,15 +118,19 @@ func getLocalBranches(repository *git.Repository) ([]string, error) {

func SetBaseBranch(logger *zerolog.Logger, config []types.FolderConfig) {
for _, folderConfig := range config {
repo, repoConfig, _, subsection, err := getConfigSection(folderConfig.FolderPath)
if err != nil {
logger.Error().Err(err).Msg("could not get git config for folder " + folderConfig.FolderPath)
continue
}
subsection.SetOption(baseBranchKey, folderConfig.BaseBranch)
err = repo.Storer.SetConfig(repoConfig)
if err != nil {
logger.Error().Err(err).Msg("could not store base branch configuration for folder " + folderConfig.FolderPath)
}
SetOption(logger, folderConfig.FolderPath, baseBranchKey, folderConfig.BaseBranch)
}
}

func SetOption(logger *zerolog.Logger, folderPath, key string, value string) {
repo, repoConfig, _, subsection, err := getConfigSection(folderPath)
if err != nil {
logger.Error().Err(err).Msg("could not get git config for folder " + folderPath)
return
}
subsection.SetOption(key, value)
err = repo.Storer.SetConfig(repoConfig)
if err != nil {
logger.Error().Err(err).Msgf("could not store %s=%s configuration for folder %s", key, value, folderPath)
}
}
1 change: 1 addition & 0 deletions internal/testutil/test_setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
const (
integTestEnvVar = "INTEG_TESTS"
smokeTestEnvVar = "SMOKE_TESTS"
NodejsGoof = "https://github.com/snyk-labs/nodejs-goof"
)

func IntegTest(t *testing.T) *config.Config {
Expand Down
Loading

0 comments on commit 00d8c2c

Please sign in to comment.