@@ -41,10 +41,11 @@ type Payload struct {
4141 NodeProjects []model.NodeScanResult `json:"node_projects"`
4242 BrewPkgManager * model.PkgManager `json:"brew_package_manager,omitempty"`
4343 BrewScans []model.BrewScanResult `json:"brew_scans"`
44- PythonPkgManagers []model.PkgManager `json:"python_package_managers"`
45- PythonGlobalPackages []model.PythonScanResult `json:"python_global_packages"`
46- PythonProjects []model.ProjectInfo `json:"python_projects"`
47- AIAgents []model.AITool `json:"ai_agents"`
44+ PythonPkgManagers []model.PkgManager `json:"python_package_managers"`
45+ PythonGlobalPackages []model.PythonScanResult `json:"python_global_packages"`
46+ PythonProjects []model.ProjectInfo `json:"python_projects"`
47+ SystemPackageScans []model.SystemPackageScanResult `json:"system_package_scans"`
48+ AIAgents []model.AITool `json:"ai_agents"`
4849 MCPConfigs []model.MCPConfigEnterprise `json:"mcp_configs"`
4950
5051 ExecutionLogs * ExecutionLogs `json:"execution_logs,omitempty"`
@@ -68,6 +69,7 @@ type PerformanceMetrics struct {
6869 BrewCasksCount int `json:"brew_casks_count"`
6970 PythonGlobalPkgsCount int `json:"python_global_packages_count"`
7071 PythonProjectsCount int `json:"python_projects_count"`
72+ SystemPackagesCount int `json:"system_packages_count"`
7173}
7274
7375// Run executes enterprise telemetry: scan, build payload, upload to S3.
@@ -305,6 +307,67 @@ func Run(exec executor.Executor, log *progress.Logger, cfg *cli.Config) error {
305307 fmt .Fprintln (os .Stderr )
306308 }
307309
310+ // System package scanning (Linux only — rpm, dpkg, pacman, apk, snap, flatpak)
311+ var systemPackageScans []model.SystemPackageScanResult
312+
313+ if exec .GOOS () == model .PlatformLinux {
314+ log .Progress ("Detecting system packages..." )
315+ sysPkgDetector := detector .NewSystemPkgDetector (userExec )
316+
317+ // Primary system PM (rpm, dpkg, pacman, or apk)
318+ if pm := sysPkgDetector .Detect (ctx ); pm != nil {
319+ log .Progress (" Found: %s v%s at %s" , pm .Name , pm .Version , pm .Path )
320+ start := time .Now ()
321+ packages := sysPkgDetector .ListPackages (ctx )
322+ duration := time .Since (start ).Milliseconds ()
323+ if packages == nil {
324+ packages = []model.SystemPackage {}
325+ }
326+ systemPackageScans = append (systemPackageScans , model.SystemPackageScanResult {
327+ ScanType : pm .Name ,
328+ PackageManager : pm ,
329+ Packages : packages ,
330+ PackagesCount : len (packages ),
331+ ScanDurationMs : duration ,
332+ })
333+ log .Progress (" %s: %d packages in %dms" , pm .Name , len (packages ), duration )
334+ }
335+
336+ // Additional PMs (snap, flatpak) — coexist with system PM
337+ for _ , mgr := range sysPkgDetector .DetectAdditionalManagers (ctx ) {
338+ mgr := mgr
339+ log .Progress (" Found: %s v%s at %s" , mgr .Name , mgr .Version , mgr .Path )
340+ start := time .Now ()
341+ var packages []model.SystemPackage
342+ switch mgr .Name {
343+ case "snap" :
344+ packages = sysPkgDetector .ListSnapPackages (ctx )
345+ case "flatpak" :
346+ packages = sysPkgDetector .ListFlatpakPackages (ctx )
347+ }
348+ duration := time .Since (start ).Milliseconds ()
349+ if packages == nil {
350+ packages = []model.SystemPackage {}
351+ }
352+ systemPackageScans = append (systemPackageScans , model.SystemPackageScanResult {
353+ ScanType : mgr .Name ,
354+ PackageManager : & mgr ,
355+ Packages : packages ,
356+ PackagesCount : len (packages ),
357+ ScanDurationMs : duration ,
358+ })
359+ log .Progress (" %s: %d packages in %dms" , mgr .Name , len (packages ), duration )
360+ }
361+
362+ if len (systemPackageScans ) == 0 {
363+ log .Progress (" No system package managers found" )
364+ }
365+ fmt .Fprintln (os .Stderr )
366+ } else {
367+ log .Progress ("System package scanning: skipped (non-Linux)" )
368+ fmt .Fprintln (os .Stderr )
369+ }
370+
308371 // Node.js scanning
309372 npmEnabled := true
310373 if cfg .EnableNPMScan != nil {
@@ -363,6 +426,9 @@ func Run(exec executor.Executor, log *progress.Logger, cfg *cli.Config) error {
363426 if pythonProjects == nil {
364427 pythonProjects = []model.ProjectInfo {}
365428 }
429+ if systemPackageScans == nil {
430+ systemPackageScans = []model.SystemPackageScanResult {}
431+ }
366432
367433 // Finalize execution logs before building payload
368434 execLogsBase64 := capture .Finalize ()
@@ -391,6 +457,7 @@ func Run(exec executor.Executor, log *progress.Logger, cfg *cli.Config) error {
391457 PythonPkgManagers : pythonPkgManagers ,
392458 PythonGlobalPackages : pythonGlobalPkgs ,
393459 PythonProjects : pythonProjects ,
460+ SystemPackageScans : systemPackageScans ,
394461 AIAgents : allAI ,
395462 MCPConfigs : mcpConfigs ,
396463
@@ -411,6 +478,7 @@ func Run(exec executor.Executor, log *progress.Logger, cfg *cli.Config) error {
411478 BrewCasksCount : brewCasksCount (brewScans ),
412479 PythonGlobalPkgsCount : len (pythonGlobalPkgs ),
413480 PythonProjectsCount : len (pythonProjects ),
481+ SystemPackagesCount : totalSystemPackagesCount (systemPackageScans ),
414482 },
415483 }
416484
@@ -443,6 +511,14 @@ func brewCasksCount(scans []model.BrewScanResult) int {
443511 return 0
444512}
445513
514+ func totalSystemPackagesCount (scans []model.SystemPackageScanResult ) int {
515+ total := 0
516+ for _ , s := range scans {
517+ total += s .PackagesCount
518+ }
519+ return total
520+ }
521+
446522func uploadToS3 (ctx context.Context , log * progress.Logger , payload * Payload ) error {
447523 payloadJSON , err := json .Marshal (payload )
448524 if err != nil {
0 commit comments