fix: Show error messages on fatal failures #32

This commit is contained in:
abhisek
2025-05-17 16:55:48 +05:30
parent b85f77cfbc
commit 3d55ef079c
7 changed files with 86 additions and 41 deletions
+1 -1
View File
@@ -39,7 +39,7 @@ var _ Analyzer = &malysisActiveScanAnalyzer{}
func NewMalysisActiveScanAnalyzer(config MalysisActiveScanAnalyzerConfig) (*malysisActiveScanAnalyzer, error) {
if config.TenantId == "" || config.ApiKey == "" {
return nil, fmt.Errorf("active scanning requires SafeDep Cloud authentication credentials")
return nil, fmt.Errorf("active scanning requires SafeDep Cloud credentials (https://docs.safedep.io/cloud/malware-analysis)")
}
headers := http.Header{}
+13 -7
View File
@@ -1,11 +1,13 @@
package npm
import (
"context"
_ "embed"
"github.com/safedep/dry/log"
"github.com/safedep/pmg/config"
"github.com/safedep/pmg/internal/flows"
"github.com/safedep/pmg/internal/ui"
"github.com/safedep/pmg/packagemanager"
"github.com/spf13/cobra"
)
@@ -15,12 +17,7 @@ func NewNpmCommand() *cobra.Command {
Short: "Guard npm package manager",
DisableFlagParsing: true,
RunE: func(cmd *cobra.Command, args []string) error {
config, err := config.FromContext(cmd.Context())
if err != nil {
ui.Fatalf("Failed to get config: %s", err)
}
err = executeNpmFlow(cmd.Context(), config, args)
err := executeNpmFlow(cmd.Context(), args)
if err != nil {
log.Errorf("Failed to execute npm flow: %s", err)
}
@@ -29,3 +26,12 @@ func NewNpmCommand() *cobra.Command {
},
}
}
func executeNpmFlow(ctx context.Context, args []string) error {
packageManager, err := packagemanager.NewNpmPackageManager(packagemanager.DefaultNpmPackageManagerConfig())
if err != nil {
ui.Fatalf("Failed to create npm package manager proxy: %s", err)
}
return flows.Common(packageManager).Run(ctx, args)
}
+13 -7
View File
@@ -1,11 +1,13 @@
package npm
import (
"context"
_ "embed"
"github.com/safedep/dry/log"
"github.com/safedep/pmg/config"
"github.com/safedep/pmg/internal/flows"
"github.com/safedep/pmg/internal/ui"
"github.com/safedep/pmg/packagemanager"
"github.com/spf13/cobra"
)
@@ -15,12 +17,7 @@ func NewPnpmCommand() *cobra.Command {
Short: "Guard pnpm package manager",
DisableFlagParsing: true,
RunE: func(cmd *cobra.Command, args []string) error {
config, err := config.FromContext(cmd.Context())
if err != nil {
ui.Fatalf("Failed to get config: %s", err)
}
err = executePnpmFlow(cmd.Context(), config, args)
err := executePnpmFlow(cmd.Context(), args)
if err != nil {
log.Errorf("Failed to execute pnpm flow: %s", err)
}
@@ -29,3 +26,12 @@ func NewPnpmCommand() *cobra.Command {
},
}
}
func executePnpmFlow(ctx context.Context, args []string) error {
packageManager, err := packagemanager.NewNpmPackageManager(packagemanager.DefaultPnpmPackageManagerConfig())
if err != nil {
ui.Fatalf("Failed to create pnpm package manager proxy: %s", err)
}
return flows.Common(packageManager).Run(ctx, args)
}
+3
View File
@@ -0,0 +1,3 @@
# Development
- [User Interface](./ui.md)
+29
View File
@@ -0,0 +1,29 @@
# User Interface
PMG is an interactive tool. We support multiple interactivity modes such as `silent`, `verbose` etc. to meet different developer experience needs. As such, we need to standardize the UI, UX and interactive messaging guidance for developers.
## Messaging
Two types of messages to users are supported:
1. UI messages
2. Logs
### UI messages
UI messages are displayed in the user interface, currently in the terminal. Following types of messages are supported:
1. **Status updates** - Meant for showing the stage or status of the workflow.
2. **Error messages** - Meant for showing fatal error messages
| Type | Mode | Show? |
| ------ | ------- | ----- |
| Status | Silent | No |
| Status | Verbose | Yes |
| Error | Silent | Yes |
| Error | Verbose | Yes |
### Logs
Logs are by default for inspection and debugging purposes. They are not shown by default but can be configured through verbosity levels or logging to files. Consider logs as something meant for use only when there is an unexpected behavior.
+2
View File
@@ -172,6 +172,8 @@ func (g *packageManagerGuard) continueExecution(ctx context.Context, pc *package
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
// We will fail based on executed command's exit code. This is important
// because other tools (scripts, CI etc.) may depend on this exit code.
return cmd.Run()
}
+25 -26
View File
@@ -1,8 +1,7 @@
package npm
package flows
import (
"context"
"fmt"
"github.com/safedep/pmg/analyzer"
"github.com/safedep/pmg/config"
@@ -11,7 +10,25 @@ import (
"github.com/safedep/pmg/packagemanager"
)
func executeCommonFlow(ctx context.Context, config config.Config, pm packagemanager.PackageManager, args []string) error {
type commonFlow struct {
pm packagemanager.PackageManager
}
// Creates a common flow of execution for all package managers. This should work for most
// of the cases unless a package manager has its own unique requirements. Configuration
// should be passed through the context (Global Config)
func Common(pm packagemanager.PackageManager) *commonFlow {
return &commonFlow{
pm: pm,
}
}
func (f *commonFlow) Run(ctx context.Context, args []string) error {
config, err := config.FromContext(ctx)
if err != nil {
ui.Fatalf("Failed to get config: %s", err)
}
packageResolverConfig := packagemanager.NewDefaultNpmDependencyResolverConfig()
packageResolverConfig.IncludeTransitiveDependencies = config.Transitive
packageResolverConfig.TransitiveDepth = config.TransitiveDepth
@@ -19,7 +36,7 @@ func executeCommonFlow(ctx context.Context, config config.Config, pm packagemana
packageResolver, err := packagemanager.NewNpmDependencyResolver(packageResolverConfig)
if err != nil {
return fmt.Errorf("failed to create npm dependency resolver: %w", err)
ui.Fatalf("Failed to create dependency resolver: %s", err)
}
var analyzers []analyzer.PackageVersionAnalyzer
@@ -27,14 +44,14 @@ func executeCommonFlow(ctx context.Context, config config.Config, pm packagemana
if config.Paranoid {
malysisActiveScanAnalyzer, err := analyzer.NewMalysisActiveScanAnalyzer(analyzer.DefaultMalysisActiveScanAnalyzerConfig())
if err != nil {
return fmt.Errorf("failed to create malysis active scan analyzer: %w", err)
ui.Fatalf("Failed to create malware analyzer: %s", err)
}
analyzers = append(analyzers, malysisActiveScanAnalyzer)
} else {
malysisQueryAnalyzer, err := analyzer.NewMalysisQueryAnalyzer(analyzer.MalysisQueryAnalyzerConfig{})
if err != nil {
return fmt.Errorf("failed to create malysis query analyzer: %w", err)
ui.Fatalf("Failed to create malware analyzer: %s", err)
}
analyzers = append(analyzers, malysisQueryAnalyzer)
@@ -50,28 +67,10 @@ func executeCommonFlow(ctx context.Context, config config.Config, pm packagemana
guardConfig := guard.DefaultPackageManagerGuardConfig()
guardConfig.DryRun = config.DryRun
proxy, err := guard.NewPackageManagerGuard(guardConfig, pm, packageResolver, analyzers, interaction)
proxy, err := guard.NewPackageManagerGuard(guardConfig, f.pm, packageResolver, analyzers, interaction)
if err != nil {
return fmt.Errorf("failed to create package manager guard: %w", err)
ui.Fatalf("Failed to create package manager guard: %s", err)
}
return proxy.Run(ctx, args)
}
func executeNpmFlow(ctx context.Context, config config.Config, 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(ctx, config, packageManager, args)
}
func executePnpmFlow(ctx context.Context, config config.Config, 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(ctx, config, packageManager, args)
}