Files
Redflag/aggregator-agent/internal/scanner/apt.go
Fimeg 55b7d03010 Session 4 complete - RedFlag update management platform
🚩 Private development - version retention only

 Complete web dashboard (React + TypeScript + TailwindCSS)
 Production-ready server backend (Go + Gin + PostgreSQL)
 Linux agent with APT + Docker scanning + local CLI tools
 JWT authentication and REST API
 Update discovery and approval workflow

🚧 Status: Alpha software - active development
📦 Purpose: Version retention during development
⚠️  Not for public use or deployment
2025-10-13 16:46:31 -04:00

91 lines
2.2 KiB
Go

package scanner
import (
"bufio"
"bytes"
"fmt"
"os/exec"
"regexp"
"strings"
"github.com/aggregator-project/aggregator-agent/internal/client"
)
// APTScanner scans for APT package updates
type APTScanner struct{}
// NewAPTScanner creates a new APT scanner
func NewAPTScanner() *APTScanner {
return &APTScanner{}
}
// IsAvailable checks if APT is available on this system
func (s *APTScanner) IsAvailable() bool {
_, err := exec.LookPath("apt")
return err == nil
}
// Scan scans for available APT updates
func (s *APTScanner) Scan() ([]client.UpdateReportItem, error) {
// Update package cache (sudo may be required, but try anyway)
updateCmd := exec.Command("apt-get", "update")
updateCmd.Run() // Ignore errors since we might not have sudo
// Get upgradable packages
cmd := exec.Command("apt", "list", "--upgradable")
output, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("failed to run apt list: %w", err)
}
return parseAPTOutput(output)
}
func parseAPTOutput(output []byte) ([]client.UpdateReportItem, error) {
var updates []client.UpdateReportItem
scanner := bufio.NewScanner(bytes.NewReader(output))
// Regex to parse apt output:
// package/repo version arch [upgradable from: old_version]
re := regexp.MustCompile(`^([^\s/]+)/([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+\[upgradable from:\s+([^\]]+)\]`)
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "Listing...") {
continue
}
matches := re.FindStringSubmatch(line)
if len(matches) < 6 {
continue
}
packageName := matches[1]
repository := matches[2]
newVersion := matches[3]
oldVersion := matches[5]
// Determine severity (simplified - in production, query Ubuntu Security Advisories)
severity := "moderate"
if strings.Contains(repository, "security") {
severity = "important"
}
update := client.UpdateReportItem{
PackageType: "apt",
PackageName: packageName,
CurrentVersion: oldVersion,
AvailableVersion: newVersion,
Severity: severity,
RepositorySource: repository,
Metadata: map[string]interface{}{
"architecture": matches[4],
},
}
updates = append(updates, update)
}
return updates, nil
}