mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
Introduce package manager interaction abstraction
This commit is contained in:
+35
-2
@@ -14,6 +14,11 @@ import (
|
|||||||
"github.com/safedep/pmg/packagemanager"
|
"github.com/safedep/pmg/packagemanager"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type PackageManagerGuardInteraction struct {
|
||||||
|
SetStatus func(status string)
|
||||||
|
GetConfirmationOnMalware func(malwarePackages []*packagev1.PackageVersion) (bool, error)
|
||||||
|
}
|
||||||
|
|
||||||
type PackageManagerGuardConfig struct {
|
type PackageManagerGuardConfig struct {
|
||||||
ResolveDependencies bool
|
ResolveDependencies bool
|
||||||
MaxConcurrentAnalyzes int
|
MaxConcurrentAnalyzes int
|
||||||
@@ -30,6 +35,7 @@ func DefaultPackageManagerGuardConfig() PackageManagerGuardConfig {
|
|||||||
|
|
||||||
type packageManagerGuard struct {
|
type packageManagerGuard struct {
|
||||||
config PackageManagerGuardConfig
|
config PackageManagerGuardConfig
|
||||||
|
interaction PackageManagerGuardInteraction
|
||||||
analyzers []analyzer.MalysisAnalyzer
|
analyzers []analyzer.MalysisAnalyzer
|
||||||
packageManager packagemanager.PackageManager
|
packageManager packagemanager.PackageManager
|
||||||
packageResolver packagemanager.PackageResolver
|
packageResolver packagemanager.PackageResolver
|
||||||
@@ -70,6 +76,8 @@ func (g *packageManagerGuard) Run(ctx context.Context, args []string) error {
|
|||||||
|
|
||||||
log.Debugf("Found %d install targets", len(parsedCommand.InstallTargets))
|
log.Debugf("Found %d install targets", len(parsedCommand.InstallTargets))
|
||||||
|
|
||||||
|
g.setStatus(fmt.Sprintf("Resolving dependencies for %d packages", len(parsedCommand.InstallTargets)))
|
||||||
|
|
||||||
if g.config.ResolveDependencies {
|
if g.config.ResolveDependencies {
|
||||||
for _, pkg := range parsedCommand.InstallTargets {
|
for _, pkg := range parsedCommand.InstallTargets {
|
||||||
if pkg.PackageVersion.GetVersion() == "" {
|
if pkg.PackageVersion.GetVersion() == "" {
|
||||||
@@ -97,6 +105,9 @@ func (g *packageManagerGuard) Run(ctx context.Context, args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Checking %d packages for malware", len(packagesToAnalyze))
|
log.Debugf("Checking %d packages for malware", len(packagesToAnalyze))
|
||||||
|
|
||||||
|
g.setStatus(fmt.Sprintf("Analyzing %d packages for malware", len(packagesToAnalyze)))
|
||||||
|
|
||||||
analysisResults, err := g.concurrentAnalyzePackages(ctx, packagesToAnalyze)
|
analysisResults, err := g.concurrentAnalyzePackages(ctx, packagesToAnalyze)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to analyze packages: %w", err)
|
return fmt.Errorf("failed to analyze packages: %w", err)
|
||||||
@@ -110,8 +121,14 @@ func (g *packageManagerGuard) Run(ctx context.Context, args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(maliciousPackages) > 0 {
|
if len(maliciousPackages) > 0 {
|
||||||
log.Errorf("Found %d malicious packages", len(maliciousPackages))
|
confirmed, err := g.getConfirmationOnMalware(ctx, maliciousPackages)
|
||||||
return fmt.Errorf("found malicious packages")
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get confirmation on malware: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !confirmed {
|
||||||
|
return fmt.Errorf("malicious packages detected, installation aborted")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("No malicious packages found, continuing execution")
|
log.Debugf("No malicious packages found, continuing execution")
|
||||||
@@ -191,3 +208,19 @@ func (g *packageManagerGuard) concurrentAnalyzePackages(ctx context.Context,
|
|||||||
|
|
||||||
return analysisResults, nil
|
return analysisResults, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *packageManagerGuard) getConfirmationOnMalware(ctx context.Context, malwarePackages []*packagev1.PackageVersion) (bool, error) {
|
||||||
|
if g.interaction.GetConfirmationOnMalware == nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return g.interaction.GetConfirmationOnMalware(malwarePackages)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *packageManagerGuard) setStatus(status string) {
|
||||||
|
if g.interaction.SetStatus == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
g.interaction.SetStatus(status)
|
||||||
|
}
|
||||||
|
|||||||
@@ -42,6 +42,14 @@ func (npm *npmPackageManager) Name() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (npm *npmPackageManager) ParseCommand(args []string) (*ParsedCommand, error) {
|
func (npm *npmPackageManager) ParseCommand(args []string) (*ParsedCommand, error) {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return nil, fmt.Errorf("no command specified")
|
||||||
|
}
|
||||||
|
|
||||||
|
if args[0] == "npm" || args[0] == "pnpm" {
|
||||||
|
args = args[1:]
|
||||||
|
}
|
||||||
|
|
||||||
command := Command{Exe: npm.Config.CommandName, Args: args}
|
command := Command{Exe: npm.Config.CommandName, Args: args}
|
||||||
|
|
||||||
// No command specified
|
// No command specified
|
||||||
|
|||||||
@@ -20,6 +20,17 @@ func TestNpmParseCommand(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 1, len(parsedCommand.InstallTargets))
|
assert.Equal(t, 1, len(parsedCommand.InstallTargets))
|
||||||
assert.Equal(t, "@types/node", parsedCommand.InstallTargets[0].PackageVersion.Package.Name)
|
assert.Equal(t, "@types/node", parsedCommand.InstallTargets[0].PackageVersion.Package.Name)
|
||||||
|
assert.Empty(t, parsedCommand.InstallTargets[0].PackageVersion.Version)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "install a single package with specific version",
|
||||||
|
command: "npm install @types/node@1.2.3",
|
||||||
|
assert: func(t *testing.T, parsedCommand *ParsedCommand, err error) {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 1, len(parsedCommand.InstallTargets))
|
||||||
|
assert.Equal(t, "@types/node", parsedCommand.InstallTargets[0].PackageVersion.Package.Name)
|
||||||
|
assert.Equal(t, "1.2.3", parsedCommand.InstallTargets[0].PackageVersion.Version)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user