Skip to content

Commit

Permalink
Add npm resolver (#172)
Browse files Browse the repository at this point in the history
* Add npm resolver
  • Loading branch information
4ernovm authored Dec 22, 2023
1 parent 41801a6 commit 645f2c3
Show file tree
Hide file tree
Showing 25 changed files with 621 additions and 90 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ internal/cmd/scan/testdata/npm/yarn.lock
internal/file/embedded/supported_formats.json
internal/resolution/pm/gradle/.gradle-init-script.debricked.groovy
internal/callgraph/language/java11/testdata/mvnproj/target
test/resolve/testdata/composer/composer.lock
test/resolve/testdata/npm/yarn.lock
test/resolve/testdata/npm/package-lock.json
test/resolve/testdata/nuget/packages.lock.json
test/resolve/testdata/nuget/csproj/packages.lock.json
test/resolve/testdata/nuget/packagesconfig/packages.config.nuget.debricked.lock
Expand All @@ -25,9 +27,13 @@ debricked.fingerprints.txt
test/resolve/testdata/gomod/gomod.debricked.lock
test/resolve/testdata/maven/maven.debricked.lock
test/callgraph/**/maven.debricked.lock
internal/file/testdata/**/go.sum
internal/file/testdata/**/gomod.debricked.lock
internal/file/testdata/**/yarn-error.log
internal/scan/composer/**/yarn.lock
internal/scan/testdata/**/yarn.lock
internal/scan/testdata/**/package-lock.json
internal/scan/testdata/**/debricked.fingerprints.wfp
test/resolve/testdata/gradle/*/**
**.gradle-init-script.debricked.groovy
test/resolve/testdata/gradle/gradle.debricked.lock
Expand Down
3 changes: 2 additions & 1 deletion build/docker/alpine.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,13 @@ RUN apk --no-cache --update add \
py3-pip \
go~=1.21 \
nodejs \
npm \
yarn \
dotnet7-sdk \
g++ \
curl

RUN dotnet --version
RUN dotnet --version && npm -v && yarn -v

RUN apk add --no-cache \
git \
Expand Down
2 changes: 2 additions & 0 deletions build/docker/debian.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ RUN apt -y update && apt -y upgrade && apt -y install nodejs && \
apt -y clean && rm -rf /var/lib/apt/lists/*
RUN npm install --global npm@latest && npm install --global yarn

RUN npm -v && yarn -v

# https://learn.microsoft.com/en-us/dotnet/core/install/linux-scripted-manual#scripted-install
# https://learn.microsoft.com/en-us/dotnet/core/install/linux-debian
# Package manager installs are only supported on the x64 architecture. Other architectures, such as Arm, must install .NET by some other means such as with Snap, an installer script, or through a manual binary installation.
Expand Down
24 changes: 20 additions & 4 deletions internal/cmd/resolve/resolve.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,24 @@ package resolve
import (
"fmt"
"path/filepath"
"strings"

"github.com/debricked/cli/internal/file"
"github.com/debricked/cli/internal/resolution"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

var exclusions = file.Exclusions()
var verbose bool
var (
exclusions = file.Exclusions()
verbose bool
npmPreferred bool
)

const (
ExclusionFlag = "exclusion"
VerboseFlag = "verbose"
ExclusionFlag = "exclusion"
VerboseFlag = "verbose"
NpmPreferredFlag = "prefer-npm"
)

func NewResolveCmd(resolver resolution.IResolver) *cobra.Command {
Expand Down Expand Up @@ -49,7 +54,16 @@ Example:
$ debricked resolve . `+exampleFlags)
cmd.Flags().BoolVar(&verbose, VerboseFlag, true, "set to false to disable extensive resolution error messages")

npmPreferredDoc := strings.Join(
[]string{
"This flag allows you to select which package manager will be used as a resolver: Yarn (default) or NPM.",
"Example: debricked resolve --prefer-npm",
}, "\n")

cmd.Flags().BoolP(NpmPreferredFlag, "", npmPreferred, npmPreferredDoc)

viper.MustBindEnv(ExclusionFlag)
viper.MustBindEnv(NpmPreferredFlag)

return cmd
}
Expand All @@ -59,6 +73,8 @@ func RunE(resolver resolution.IResolver) func(_ *cobra.Command, args []string) e
if len(args) == 0 {
args = append(args, ".")
}

resolver.SetNpmPreferred(viper.GetBool(NpmPreferredFlag))
_, err := resolver.Resolve(args, viper.GetStringSlice(ExclusionFlag), viper.GetBool(VerboseFlag))

return err
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/root/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func TestNewRootCmd(t *testing.T) {
}
}
assert.Truef(t, match, "failed to assert that flag was present: "+AccessTokenFlag)
assert.Len(t, viperKeys, 14)
assert.Len(t, viperKeys, 15)
}

func TestPreRun(t *testing.T) {
Expand Down
13 changes: 13 additions & 0 deletions internal/cmd/scan/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"path/filepath"
"strings"

"github.com/debricked/cli/internal/file"
"github.com/debricked/cli/internal/scan"
Expand All @@ -24,6 +25,7 @@ var noResolve bool
var noFingerprint bool
var passOnDowntime bool
var callgraph bool
var npmPreferred bool
var callgraphUploadTimeout int
var callgraphGenerateTimeout int

Expand All @@ -42,6 +44,7 @@ const (
CallGraphFlag = "callgraph"
CallGraphUploadTimeoutFlag = "callgraph-upload-timeout"
CallGraphGenerateTimeoutFlag = "callgraph-generate-timeout"
NpmPreferredFlag = "prefer-npm"
)

var scanCmdError error
Expand Down Expand Up @@ -101,13 +104,22 @@ For example, if there is a "go.mod" in the target path, its dependencies are goi
cmd.Flags().IntVar(&callgraphUploadTimeout, CallGraphUploadTimeoutFlag, 10*60, "Set a timeout (in seconds) on call graph upload.")
cmd.Flags().IntVar(&callgraphGenerateTimeout, CallGraphGenerateTimeoutFlag, 60*60, "Set a timeout (in seconds) on call graph generation.")

npmPreferredDoc := strings.Join(
[]string{
"This flag allows you to select which package manager will be used as a resolver: Yarn (default) or NPM.",
"Example: debricked resolve --prefer-npm",
}, "\n")

cmd.Flags().BoolP(NpmPreferredFlag, "", npmPreferred, npmPreferredDoc)

viper.MustBindEnv(RepositoryFlag)
viper.MustBindEnv(CommitFlag)
viper.MustBindEnv(BranchFlag)
viper.MustBindEnv(CommitAuthorFlag)
viper.MustBindEnv(RepositoryUrlFlag)
viper.MustBindEnv(IntegrationFlag)
viper.MustBindEnv(PassOnTimeOut)
viper.MustBindEnv(NpmPreferredFlag)

return cmd
}
Expand All @@ -130,6 +142,7 @@ func RunE(s *scan.IScanner) func(_ *cobra.Command, args []string) error {
CommitAuthor: viper.GetString(CommitAuthorFlag),
RepositoryUrl: viper.GetString(RepositoryUrlFlag),
IntegrationName: viper.GetString(IntegrationFlag),
NpmPreferred: viper.GetBool(NpmPreferredFlag),
PassOnTimeOut: viper.GetBool(PassOnTimeOut),
CallGraph: viper.GetBool(CallGraphFlag),
CallGraphUploadTimeout: viper.GetInt(CallGraphUploadTimeoutFlag),
Expand Down
33 changes: 29 additions & 4 deletions internal/resolution/file/file_batch_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,38 @@ import (
"regexp"

"github.com/debricked/cli/internal/resolution/pm"
"github.com/debricked/cli/internal/resolution/pm/npm"
"github.com/debricked/cli/internal/resolution/pm/yarn"
)

type IBatchFactory interface {
Make(files []string) []IBatch
SetNpmPreferred(npmPreferred bool)
}

type BatchFactory struct {
pms []pm.IPm
pms []pm.IPm
npmPreferred bool
}

func NewBatchFactory() BatchFactory {
return BatchFactory{
func NewBatchFactory() *BatchFactory {
return &BatchFactory{
pms: pm.Pms(),
}
}

func (bf BatchFactory) Make(files []string) []IBatch {
func (bf *BatchFactory) SetNpmPreferred(npmPreferred bool) {
bf.npmPreferred = npmPreferred
}

func (bf *BatchFactory) Make(files []string) []IBatch {
batchMap := make(map[string]IBatch)
for _, file := range files {
for _, p := range bf.pms {
if bf.skipPackageManager(p) {
continue
}

for _, manifest := range p.Manifests() {
compiledRegex, _ := regexp.Compile(manifest)
if compiledRegex.MatchString(path.Base(file)) {
Expand All @@ -47,3 +59,16 @@ func (bf BatchFactory) Make(files []string) []IBatch {

return batches
}

func (bf *BatchFactory) skipPackageManager(p pm.IPm) bool {
name := p.Name()

switch true {
case name == npm.Name && !bf.npmPreferred:
return true
case name == yarn.Name && bf.npmPreferred:
return true
}

return false
}
3 changes: 3 additions & 0 deletions internal/resolution/file/testdata/file_batch_factory_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ func NewBatchFactoryMock() BatchFactoryMock {
}
}

func (bf BatchFactoryMock) SetNpmPreferred(_ bool) {
}

func (bf BatchFactoryMock) Make(_ []string) []file.IBatch {

return []file.IBatch{}
Expand Down
44 changes: 44 additions & 0 deletions internal/resolution/pm/npm/cmd_factory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package npm

import (
"os/exec"
"path/filepath"
)

type ICmdFactory interface {
MakeInstallCmd(command string, file string) (*exec.Cmd, error)
}

type IExecPath interface {
LookPath(file string) (string, error)
}

type ExecPath struct {
}

func (ExecPath) LookPath(file string) (string, error) {
return exec.LookPath(file)
}

type CmdFactory struct {
execPath IExecPath
}

func (cmdf CmdFactory) MakeInstallCmd(command string, file string) (*exec.Cmd, error) {
path, err := cmdf.execPath.LookPath(command)

fileDir := filepath.Dir(file)

return &exec.Cmd{
Path: path,
Args: []string{
//"yes |", // Answer 'y' to any prompts...
command,
"install",
"--ignore-scripts", // Avoid risky scripts
"--audit=false", // Do not run audit
"--bin-links=false", // We don't need symlinks to binaries as we won't run any code
},
Dir: fileDir,
}, err
}
19 changes: 19 additions & 0 deletions internal/resolution/pm/npm/cmd_factory_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package npm

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestMakeInstallCmd(t *testing.T) {
npmCommand := "npm"
cmd, err := CmdFactory{
execPath: ExecPath{},
}.MakeInstallCmd(npmCommand, "file")
assert.NoError(t, err)
assert.NotNil(t, cmd)
args := cmd.Args
assert.Contains(t, args, "npm")
assert.Contains(t, args, "install")
}
Loading

0 comments on commit 645f2c3

Please sign in to comment.