Skip to content

Commit 63c3e2b

Browse files
authored
Merge branch 'main' into sm/feat/config
2 parents e5c3c65 + 21cb7cf commit 63c3e2b

2 files changed

Lines changed: 92 additions & 4 deletions

File tree

internal/model/model.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,18 @@ type PythonPackage struct {
149149
Version string `json:"version"`
150150
}
151151

152+
// SystemPackageScanResult holds parsed system package data for enterprise telemetry.
153+
// Unlike BrewScanResult (which sends raw base64), this sends pre-parsed packages
154+
// since syspkg.go already handles the format-specific parsing edge cases.
155+
type SystemPackageScanResult struct {
156+
ScanType string `json:"scan_type"` // "rpm", "dpkg", "pacman", "apk", "snap", "flatpak"
157+
PackageManager *PkgManager `json:"package_manager,omitempty"`
158+
Packages []SystemPackage `json:"packages"`
159+
PackagesCount int `json:"packages_count"`
160+
Error string `json:"error,omitempty"`
161+
ScanDurationMs int64 `json:"scan_duration_ms"`
162+
}
163+
152164
// BrewScanResult holds raw Homebrew scan output for enterprise telemetry.
153165
type BrewScanResult struct {
154166
ScanType string `json:"scan_type"` // "formulae" or "casks"

internal/telemetry/telemetry.go

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
446522
func uploadToS3(ctx context.Context, log *progress.Logger, payload *Payload) error {
447523
payloadJSON, err := json.Marshal(payload)
448524
if err != nil {

0 commit comments

Comments
 (0)