🚩 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
91 lines
2.2 KiB
Go
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
|
|
}
|