feat: add manifest-based package installation detection

This commit is contained in:
Sahilb315
2025-06-10 02:43:56 +05:30
parent 9ed94f5312
commit 7ab669e623
8 changed files with 346 additions and 72 deletions
+80
View File
@@ -73,6 +73,12 @@ func (g *packageManagerGuard) Run(ctx context.Context, args []string, parsedComm
log.Debugf("Running package manager guard with args: %v", args)
if !parsedCommand.HasInstallTarget() {
// Check if this is a manifest-based installation
if parsedCommand.ShouldExtractFromManifest() {
log.Debugf("Detected manifest-based installation, extracting packages from manifest files")
return g.handleManifestInstallation(ctx, parsedCommand)
}
log.Debugf("No install target found, continuing execution")
return g.continueExecution(ctx, parsedCommand)
}
@@ -268,3 +274,77 @@ func (g *packageManagerGuard) clearStatus() {
g.interaction.ClearStatus()
}
func (g *packageManagerGuard) handleManifestInstallation(ctx context.Context, parsedCommand *packagemanager.ParsedCommand) error {
g.setStatus("Extracting packages from manifest files")
// Create extractor with appropriate ecosystem
var ecosystem packagev1.Ecosystem
switch g.packageManager.Name() {
case "pip":
ecosystem = packagev1.Ecosystem_ECOSYSTEM_PYPI
case "npm", "pnpm":
ecosystem = packagev1.Ecosystem_ECOSYSTEM_NPM
default:
return fmt.Errorf("unsupported package manager for manifest extraction: %s", g.packageManager.Name())
}
extractorConfig := packagemanager.NewDefaultExtractorConfig()
extractorConfig.ExtractorEcosystem = ecosystem
switch ecosystem {
case packagev1.Ecosystem_ECOSYSTEM_PYPI:
extractorConfig.ExtractorsName = packagemanager.PyPiExtractors
case packagev1.Ecosystem_ECOSYSTEM_NPM:
extractorConfig.ExtractorsName = packagemanager.NpmExtractors
}
extractor := packagemanager.NewExtractor(*extractorConfig)
packages, err := extractor.ExtractManifestFiles()
if err != nil {
return fmt.Errorf("failed to extract packages from manifest files: %w", err)
}
if len(packages) == 0 {
log.Debugf("No packages found in manifest files, continuing execution")
return g.continueExecution(ctx, parsedCommand)
}
log.Debugf("Extracted %d packages from manifest files", len(packages))
// Analyze the extracted packages
g.setStatus(fmt.Sprintf("Analyzing %d packages from manifest files", len(packages)))
analysisResults, err := g.concurrentAnalyzePackages(ctx, packages)
if err != nil {
return fmt.Errorf("failed to analyze packages: %w", err)
}
confirmableMalwarePackages := []*analyzer.PackageVersionAnalysisResult{}
for _, result := range analysisResults {
if result.Action == analyzer.ActionBlock {
return g.blockInstallation(result)
}
if result.Action == analyzer.ActionConfirm {
confirmableMalwarePackages = append(confirmableMalwarePackages, result)
}
}
if len(confirmableMalwarePackages) > 0 {
confirmed, err := g.getConfirmationOnMalware(ctx, confirmableMalwarePackages)
if err != nil {
return fmt.Errorf("failed to get confirmation on malware: %w", err)
}
if !confirmed {
return g.blockInstallation(confirmableMalwarePackages...)
}
}
log.Debugf("No malicious packages found in manifest files, continuing execution")
g.clearStatus()
return g.continueExecution(ctx, parsedCommand)
}