mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
* feat: Add cloud sync event emit * fix: Linter fixes * fix: Include malysis metadata in confirmed event * fix: Code review fixes * fix: Emit session complet event * fix: Code review fixes * chore: Add comment * chore: Add cloud info in setup info command * fix: Proxy flow must call install started * fix: Code review fixes * fix: Code review fixes * Update internal/audit/cloud_sink.go Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com> Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com> * fix: Code review fixes --------- Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com> Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
132 lines
4.3 KiB
Go
132 lines
4.3 KiB
Go
package flows
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/safedep/pmg/analyzer"
|
|
"github.com/safedep/pmg/config"
|
|
"github.com/safedep/pmg/guard"
|
|
"github.com/safedep/pmg/internal/audit"
|
|
"github.com/safedep/pmg/internal/ui"
|
|
"github.com/safedep/pmg/packagemanager"
|
|
)
|
|
|
|
type commonFlow struct {
|
|
pm packagemanager.PackageManager
|
|
packageResolver packagemanager.PackageResolver
|
|
}
|
|
|
|
// 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, pkgResolver packagemanager.PackageResolver) *commonFlow {
|
|
return &commonFlow{
|
|
pm: pm,
|
|
packageResolver: pkgResolver,
|
|
}
|
|
}
|
|
|
|
func (f *commonFlow) Run(ctx context.Context, args []string, parsedCmd *packagemanager.ParsedCommand) error {
|
|
var analyzers []analyzer.PackageVersionAnalyzer
|
|
|
|
// Configure sandbox based on command type and enforcement policy
|
|
config.ConfigureSandbox(parsedCmd.IsInstallationCommand())
|
|
|
|
cfg := config.Get()
|
|
|
|
// Initialize report data at the start
|
|
reportData := ui.NewReportData()
|
|
reportData.PackageManagerName = f.pm.Name()
|
|
reportData.FlowType = ui.FlowTypeGuard
|
|
reportData.DryRun = cfg.DryRun
|
|
reportData.InsecureMode = cfg.InsecureInstallation
|
|
reportData.TransitiveEnabled = cfg.Config.Transitive
|
|
reportData.ParanoidMode = cfg.Config.Paranoid
|
|
reportData.SandboxEnabled = cfg.Config.Sandbox.Enabled
|
|
|
|
if cfg.Config.Sandbox.Enabled {
|
|
if policyRef, exists := cfg.Config.Sandbox.Policies[f.pm.Name()]; exists {
|
|
reportData.SandboxProfile = policyRef.Profile
|
|
}
|
|
}
|
|
if cfg.SandboxProfileOverride != "" {
|
|
reportData.SandboxProfile = cfg.SandboxProfileOverride
|
|
}
|
|
|
|
startTime := time.Now()
|
|
|
|
malysisQueryAnalyzer, err := analyzer.NewMalysisQueryAnalyzer(analyzer.MalysisQueryAnalyzerConfig{})
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create malware analyzer: %w", err)
|
|
}
|
|
|
|
analyzers = append(analyzers, malysisQueryAnalyzer)
|
|
|
|
interaction := guard.PackageManagerGuardInteraction{
|
|
SetStatus: ui.SetStatus,
|
|
ClearStatus: ui.ClearStatus,
|
|
ShowWarning: ui.ShowWarning,
|
|
GetConfirmationOnMalware: ui.GetConfirmationOnMalware,
|
|
Block: ui.BlockNoExit,
|
|
}
|
|
|
|
guardConfig := guard.DefaultPackageManagerGuardConfig()
|
|
guardConfig.DryRun = cfg.DryRun
|
|
guardConfig.InsecureInstallation = cfg.InsecureInstallation
|
|
|
|
guardManager, err := guard.NewPackageManagerGuard(guardConfig, f.pm, f.packageResolver, analyzers, interaction)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create package manager guard: %s", err)
|
|
}
|
|
|
|
guardResult, err := guardManager.Run(ctx, args, parsedCmd)
|
|
|
|
// Populate report data from guard result
|
|
reportData.StartTime = startTime
|
|
if guardResult != nil {
|
|
reportData.TotalAnalyzed = guardResult.TotalAnalyzed
|
|
reportData.TrustedSkipped = guardResult.TrustedSkipped
|
|
reportData.AllowedCount = guardResult.AllowedCount
|
|
reportData.ConfirmedCount = guardResult.ConfirmedCount
|
|
reportData.BlockedCount = guardResult.BlockedCount
|
|
reportData.BlockedPackages = guardResult.BlockedPackages
|
|
reportData.ConfirmedPackages = guardResult.ConfirmedPackages
|
|
}
|
|
|
|
// Infer outcome from data and config using shared inference logic
|
|
blockedCount := 0
|
|
userCancelledCount := 0
|
|
|
|
if guardResult != nil {
|
|
blockedCount = guardResult.BlockedCount
|
|
// In guard flow, if user cancelled, all blocked packages are due to user cancellation
|
|
// (guard returns immediately on ActionBlock, so we can't have both types)
|
|
if guardResult.WasUserCancelled {
|
|
userCancelledCount = guardResult.BlockedCount
|
|
}
|
|
}
|
|
|
|
reportData.Outcome = inferOutcome(cfg.InsecureInstallation, cfg.DryRun, blockedCount, userCancelledCount, err)
|
|
|
|
// Session complete is called here (not deferred) because guard.Run() calls
|
|
// LogInstallStarted internally, and all paths after guard.Run() reach this point.
|
|
audit.LogSessionComplete(audit.Outcome(reportData.Outcome.String()), audit.FlowTypeGuard)
|
|
|
|
// Show the report
|
|
ui.Report(reportData)
|
|
|
|
// Exit after report for blocked/cancelled outcomes
|
|
if reportData.Outcome == ui.OutcomeBlocked || reportData.Outcome == ui.OutcomeUserCancelled {
|
|
os.Exit(1)
|
|
}
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("failed to run package manager guard: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|