diff --git a/cmd/npm/common.go b/cmd/npm/common.go new file mode 100644 index 0000000..34d117e --- /dev/null +++ b/cmd/npm/common.go @@ -0,0 +1,43 @@ +package npm + +import ( + "context" + "fmt" + + "github.com/safedep/pmg/analyzer" + "github.com/safedep/pmg/guard" + "github.com/safedep/pmg/packagemanager" +) + +func executeCommonFlow(pm packagemanager.PackageManager, args []string) error { + packageResolver, err := packagemanager.NewNpmDependencyResolver(packagemanager.NewDefaultNpmDependencyResolverConfig()) + if err != nil { + return fmt.Errorf("failed to create npm dependency resolver: %w", err) + } + + proxy, err := guard.NewPackageManagerGuard(guard.PackageManagerGuardConfig{}, + pm, packageResolver, []analyzer.Analyzer{}) + if err != nil { + return fmt.Errorf("failed to create package manager guard: %w", err) + } + + return proxy.Run(context.Background(), args) +} + +func executeNpmFlow(args []string) error { + packageManager, err := packagemanager.NewNpmPackageManager(packagemanager.DefaultNpmPackageManagerConfig()) + if err != nil { + return fmt.Errorf("failed to create npm package manager: %w", err) + } + + return executeCommonFlow(packageManager, args) +} + +func executePnpmFlow(args []string) error { + packageManager, err := packagemanager.NewNpmPackageManager(packagemanager.DefaultPnpmPackageManagerConfig()) + if err != nil { + return fmt.Errorf("failed to create pnpm package manager: %w", err) + } + + return executeCommonFlow(packageManager, args) +} diff --git a/cmd/npm/npm.go b/cmd/npm/npm.go index a4b1937..9016ac4 100644 --- a/cmd/npm/npm.go +++ b/cmd/npm/npm.go @@ -2,51 +2,17 @@ package npm import ( _ "embed" - "fmt" - "os" - "github.com/safedep/pmg/pkg/common/utils" - "github.com/safedep/pmg/pkg/registry" - "github.com/safedep/pmg/pkg/wrapper" "github.com/spf13/cobra" ) func NewNpmCommand() *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "npm [action] [package]", - Short: "Scan packages from npm registry", + Short: "Guard npm package manager", DisableFlagParsing: true, RunE: func(cmd *cobra.Command, args []string) error { - execPath, err := utils.GetExecutablePath(string(registry.RegistryNPM)) - if err != nil { - fmt.Fprintf(os.Stderr, "npm not found: %v\n", err) - return err - } - - if len(args) >= 2 && utils.IsInstallCommand(string(registry.RegistryNPM), args[0]) { - // Parse arguments to separate flags and packages - flags, packages := utils.ParseNpmInstallArgs(args[1:]) - - // If no packages specified, just pass through to npm - if len(packages) == 0 { - return utils.ExecCmd(execPath, args, []string{}) - } - - // Create single wrapper instance for all packages - pmw := wrapper.NewPackageManagerWrapper(registry.RegistryNPM, flags, packages, args[0]) - if err := pmw.Wrap(); err != nil { - return err - } - - return nil - } - - if err := utils.ExecCmd(execPath, args, []string{}); err != nil { - os.Exit(1) - } - os.Exit(0) - return nil + return executeNpmFlow(args) }, } - return cmd } diff --git a/cmd/npm/pnpm.go b/cmd/npm/pnpm.go index 2105e72..5019c72 100644 --- a/cmd/npm/pnpm.go +++ b/cmd/npm/pnpm.go @@ -2,51 +2,17 @@ package npm import ( _ "embed" - "fmt" - "os" - "github.com/safedep/pmg/pkg/common/utils" - "github.com/safedep/pmg/pkg/registry" - "github.com/safedep/pmg/pkg/wrapper" "github.com/spf13/cobra" ) func NewPnpmCommand() *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "pnpm [action] [package]", - Short: "Scan packages from npm registry", + Short: "Guard pnpm package manager", DisableFlagParsing: true, RunE: func(cmd *cobra.Command, args []string) error { - execPath, err := utils.GetExecutablePath(string(registry.RegistryPNPM)) - if err != nil { - fmt.Fprintf(os.Stderr, "pnpm not found: %v\n", err) - return err - } - - if len(args) >= 2 && utils.IsInstallCommand(string(registry.RegistryPNPM), args[0]) { - // Parse arguments to separate flags and packages - flags, packages := utils.ParseNpmInstallArgs(args[1:]) - - // If no packages specified, just pass through to npm - if len(packages) == 0 { - return utils.ExecCmd(execPath, args, []string{}) - } - - // Create single wrapper instance for all packages - pmw := wrapper.NewPackageManagerWrapper(registry.RegistryPNPM, flags, packages, args[0]) - if err := pmw.Wrap(); err != nil { - return err - } - - return nil - } - - if err := utils.ExecCmd(execPath, args, []string{}); err != nil { - os.Exit(1) - } - os.Exit(0) - return nil + return executePnpmFlow(args) }, } - return cmd } diff --git a/guard/guard.go b/guard/guard.go new file mode 100644 index 0000000..c5fe808 --- /dev/null +++ b/guard/guard.go @@ -0,0 +1,64 @@ +package guard + +import ( + "context" + "fmt" + "os" + "os/exec" + + "github.com/safedep/dry/log" + "github.com/safedep/pmg/analyzer" + "github.com/safedep/pmg/packagemanager" +) + +type PackageManagerGuardConfig struct{} + +type packageManagerGuard struct { + config PackageManagerGuardConfig + analyzers []analyzer.Analyzer + packageManager packagemanager.PackageManager + packageResolver packagemanager.PackageResolver +} + +func NewPackageManagerGuard(config PackageManagerGuardConfig, + packageManager packagemanager.PackageManager, + packageResolver packagemanager.PackageResolver, + analyzers []analyzer.Analyzer) (*packageManagerGuard, error) { + return &packageManagerGuard{ + analyzers: analyzers, + packageManager: packageManager, + packageResolver: packageResolver, + config: config, + }, nil +} + +func (g *packageManagerGuard) Run(ctx context.Context, args []string) error { + log.Debugf("Running package manager guard with args: %v", args) + + parsedCommand, err := g.packageManager.ParseCommand(args) + if err != nil { + return fmt.Errorf("failed to parse command: %w", err) + } + + if !parsedCommand.HasInstallTarget() { + log.Debugf("No install target found, continuing execution") + return g.continueExecution(ctx, parsedCommand) + } + + log.Debugf("Install targets: %v", parsedCommand.InstallTargets) + + return nil +} + +func (g *packageManagerGuard) continueExecution(ctx context.Context, pc *packagemanager.ParsedCommand) error { + if len(pc.Command.Exe) == 0 { + return fmt.Errorf("no command to execute") + } + + cmd := exec.CommandContext(ctx, pc.Command.Exe, pc.Command.Args...) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + return cmd.Run() +} diff --git a/main.go b/main.go index a85baf7..adaed60 100644 --- a/main.go +++ b/main.go @@ -9,21 +9,27 @@ import ( "github.com/spf13/cobra" ) -func main() { - var debug bool +var ( + debug bool +) +func main() { cmd := &cobra.Command{ Use: "pmg", TraverseChildren: true, PersistentPreRun: func(cmd *cobra.Command, args []string) { if debug { - log.Init("pmg-logger", "debug") + os.Setenv("APP_LOG_LEVEL", "debug") } + + log.InitZapLogger("pmg", "") }, RunE: func(cmd *cobra.Command, args []string) error { if len(args) == 0 { + cmd.Help() return nil } + return fmt.Errorf("pmg: %s is not a valid command", args[0]) }, } diff --git a/packagemanager/npm.go b/packagemanager/npm.go index 92da955..aa67b5a 100644 --- a/packagemanager/npm.go +++ b/packagemanager/npm.go @@ -10,11 +10,20 @@ import ( type NpmPackageManagerConfig struct { InstallCommands []string + CommandName string } func DefaultNpmPackageManagerConfig() NpmPackageManagerConfig { return NpmPackageManagerConfig{ InstallCommands: []string{"install", "i", "add"}, + CommandName: "npm", + } +} + +func DefaultPnpmPackageManagerConfig() NpmPackageManagerConfig { + return NpmPackageManagerConfig{ + InstallCommands: []string{"install", "i", "add"}, + CommandName: "pnpm", } } @@ -33,17 +42,19 @@ func (npm *npmPackageManager) Name() string { } func (npm *npmPackageManager) ParseCommand(args []string) (*ParsedCommand, error) { + command := Command{Exe: npm.Config.CommandName, Args: args} + // No command specified if len(args) < 2 { return &ParsedCommand{ - Command: Command{Args: args}, + Command: command, }, nil } // Check if this is an install command if !npm.isInstallCommand(args[1]) { return &ParsedCommand{ - Command: Command{Args: args}, + Command: command, }, nil } @@ -59,7 +70,7 @@ func (npm *npmPackageManager) ParseCommand(args []string) (*ParsedCommand, error // No packages specified if len(packages) == 0 { return &ParsedCommand{ - Command: Command{Args: args}, + Command: command, }, nil } @@ -88,7 +99,7 @@ func (npm *npmPackageManager) ParseCommand(args []string) (*ParsedCommand, error } return &ParsedCommand{ - Command: Command{Args: args}, + Command: command, InstallTargets: installTargets, }, nil } diff --git a/packagemanager/packagemanager.go b/packagemanager/packagemanager.go index 732b123..5ac1d9d 100644 --- a/packagemanager/packagemanager.go +++ b/packagemanager/packagemanager.go @@ -7,6 +7,7 @@ import ( ) type Command struct { + Exe string Args []string }