// SPDX-License-Identifier: GPL-3.0-or-later // Package provenance answers "is this file shipped by an installed package?". // Ownership raises confidence that a binary is legitimate; it never proves // safety, so callers use it to suppress or rank alerts, not to delete evidence. package provenance import ( "context" "os/exec" "strings" "sync" "time" ) var ( mu sync.Mutex tool *string cache = map[string]bool{} ) func packageTool() string { if tool != nil { return *tool } found := "" for _, name := range []string{"pacman", "dpkg", "rpm"} { if _, err := exec.LookPath(name); err == nil { found = name break } } tool = &found return found } func query(name, path string) bool { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() switch name { case "pacman": output, err := exec.CommandContext(ctx, "pacman", "-Qo", path).Output() return err == nil && strings.Contains(string(output), "owned by") case "dpkg": output, err := exec.CommandContext(ctx, "dpkg", "-S", path).Output() return err == nil && strings.Contains(string(output), ":") case "rpm": output, err := exec.CommandContext(ctx, "rpm", "-qf", path).Output() return err == nil && !strings.Contains(string(output), "not owned") } return false } // IsPackageOwned reports whether path belongs to an installed package. // Results are cached because package ownership is stable within a sweep run. func IsPackageOwned(path string) bool { if path == "" || path == "(deleted)" { return false } path = strings.ReplaceAll(path, " (deleted)", "") mu.Lock() defer mu.Unlock() if owned, seen := cache[path]; seen { return owned } name := packageTool() owned := name != "" && query(name, path) cache[path] = owned return owned }