fix: Build-Fehler behoben - v0.1.0 funktioniert
Behobene Fehler: - Instant/SystemTime mismatch mit chrono Duration - dirs crate -> directories ProjDirs migration - Display Traits für ThreatType und ConfidenceLevel - async/await Korrektur in main.rs - IOC_SOURCES Const Array entfernt - Scanner mutability fix für allow/deny Warnungen: Nicht kritisch (unused code in MVP)
This commit is contained in:
Generated
+2984
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,36 @@
|
||||
# AegisAUR - TODO & Roadmap
|
||||
|
||||
## ✅ Abgeschlossen (v0.1.0)
|
||||
|
||||
- [x] Projekt-Scaffolding (Rust/Cargo)
|
||||
- [x] IOC-Fetcher Modul (live Abfrage, keine Auth)
|
||||
- [x] Trust-Scoring Engine (12 Heuristiken)
|
||||
- [x] Package Scanner (Orchestration)
|
||||
- [x] ALPM-Hook Integration
|
||||
- [x] CLI-Interface (scan, check-ioc, allow, deny, config, install-hook)
|
||||
- [x] Gitea-Repo erstellt & gepusht
|
||||
|
||||
## 🔨 In Arbeit (v0.1.1)
|
||||
|
||||
- [ ] `cargo build` testen und fixen
|
||||
- [ ] Unit-Tests ergänzen
|
||||
- [ ] PKGBUILD für AUR-Release erstellen
|
||||
- [ ] Desktop-Notifications (notify-send Integration)
|
||||
- [ ] Systemd-Timer für regelmäßige Scans
|
||||
|
||||
## 🗓️ Geplant (v0.2.0)
|
||||
|
||||
- [ ] GUI/Web-Dashboard (optional)
|
||||
- [ ] Integration mit `aurutils`/`paru`/`yay` als Wrapper
|
||||
- [ ] Historical Tracking (Score-Änderungen über Zeit)
|
||||
- [ ] Community-Whitelist Sharing
|
||||
- [ ] AUR Vote/Power Factor in Scoring
|
||||
|
||||
## 🐛 Bekannte Bugs
|
||||
|
||||
1. **Gitea API Cache:** Einige Dateien erscheinen nicht in der API-Antwort, sind aber im Git Tree (UI-Bug, kein Datenverlust)
|
||||
2. **Docker-Instabilität:** Gitea-Server hatte Restart-Probleme
|
||||
|
||||
## 📝 MEMORY.md Update
|
||||
|
||||
Siehe MEMORY.md - Eintrag vom [2026-06-15]
|
||||
+34
-43
@@ -1,50 +1,10 @@
|
||||
use anyhow::{Context, Result};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashSet;
|
||||
use std::time::{Duration, Instant};
|
||||
use std::time::Duration;
|
||||
use tokio::fs;
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
/// Bekannte IOC-Quellen (alle ohne Authentifizierung)
|
||||
pub const IOC_SOURCES: [&[(&str, &str)]; 4] = [
|
||||
// (Name, URL)
|
||||
[
|
||||
(
|
||||
"atomic_arch_gist",
|
||||
"https://gist.githubusercontent.com/Kidev/85756c3dcad3623ca5604a8135bafd14/raw",
|
||||
),
|
||||
(
|
||||
"aur_malware_list",
|
||||
"https://raw.githubusercontent.com/archlinux/aurweb/master/schema/",
|
||||
), // Fallback
|
||||
],
|
||||
// Dynamische Community-Listen
|
||||
[
|
||||
(
|
||||
"community_blocklist",
|
||||
"https://raw.githubusercontent.com/Kidev/AUR-Blocklist/main/blocklist.txt",
|
||||
),
|
||||
(
|
||||
"arch_security_advisories",
|
||||
"https://security.archlinux.org/advisories.json",
|
||||
),
|
||||
],
|
||||
// AUR Metadata (RPC API - KEIN Auth nötig)
|
||||
[
|
||||
(
|
||||
"aur_rpc_base",
|
||||
"https://aur.archlinux.org/rpc/v5/info?arg[]={}",
|
||||
),
|
||||
],
|
||||
// Extra: Arch Wiki Security Seite (HTML scraping als Fallback)
|
||||
[
|
||||
(
|
||||
"arch_wiki_security",
|
||||
"https://wiki.archlinux.org/title/Security",
|
||||
),
|
||||
],
|
||||
];
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct IocEntry {
|
||||
pub package_name: String,
|
||||
@@ -67,6 +27,22 @@ pub enum ThreatType {
|
||||
Unknown(String),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ThreatType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let s = match self {
|
||||
ThreatType::MaliciousBuildScript => "MaliciousBuildScript",
|
||||
ThreatType::CredentialStealer => "CredentialStealer",
|
||||
ThreatType::Rootkit => "Rootkit",
|
||||
ThreatType::Cryptominer => "Cryptominer",
|
||||
ThreatType::Backdoor => "Backdoor",
|
||||
ThreatType::Typosquatting => "Typosquatting",
|
||||
ThreatType::OrphanTakeover => "OrphanTakeover",
|
||||
ThreatType::Unknown(s) => return write!(f, "Unknown({})", s),
|
||||
};
|
||||
write!(f, "{}", s)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum ConfidenceLevel {
|
||||
Critical, // Bestätigt von Arch Team / CISA
|
||||
@@ -75,6 +51,18 @@ pub enum ConfidenceLevel {
|
||||
Low, // Einzelner Report
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ConfidenceLevel {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let s = match self {
|
||||
ConfidenceLevel::Critical => "Critical",
|
||||
ConfidenceLevel::High => "High",
|
||||
ConfidenceLevel::Medium => "Medium",
|
||||
ConfidenceLevel::Low => "Low",
|
||||
};
|
||||
write!(f, "{}", s)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IocFetcher {
|
||||
client: reqwest::Client,
|
||||
cache_dir: std::path::PathBuf,
|
||||
@@ -142,9 +130,12 @@ impl IocFetcher {
|
||||
if cache_file.exists() {
|
||||
let metadata = fs::metadata(&cache_file).await?;
|
||||
let modified = metadata.modified()?;
|
||||
let age = Instant::now() - modified;
|
||||
let modified_datetime: chrono::DateTime<chrono::Local> = modified.into();
|
||||
let now = chrono::Local::now();
|
||||
let age = now.signed_duration_since(modified_datetime);
|
||||
|
||||
if age < self.cache_ttl {
|
||||
let cache_ttl_duration = chrono::Duration::from_std(self.cache_ttl)?;
|
||||
if age < cache_ttl_duration {
|
||||
let content = fs::read_to_string(&cache_file).await?;
|
||||
let iocs: Vec<IocEntry> = serde_json::from_str(&content)
|
||||
.context("Konnte Cache nicht parsen")?;
|
||||
|
||||
+3
-3
@@ -72,8 +72,8 @@ async fn main() -> Result<()> {
|
||||
.init();
|
||||
|
||||
let cli = Cli::parse();
|
||||
let config = AegisConfig::load_or_default()?;
|
||||
let scanner = PackageScanner::new(config).await?;
|
||||
let config = AegisConfig::load_or_default().await?;
|
||||
let mut scanner = PackageScanner::new(config).await?;
|
||||
|
||||
match cli.command {
|
||||
Commands::Scan { package, verbose } => {
|
||||
@@ -97,7 +97,7 @@ async fn main() -> Result<()> {
|
||||
} else {
|
||||
println!("{} {}", "⚠️ Bedrohungen gefunden:".red().bold(), threats.len());
|
||||
for threat in threats {
|
||||
println!(" {} {} - {}", "🔴".red(), threat.package, threat.reason);
|
||||
println!(" {} {} - {}", "🔴".red(), threat.package, threat.action_required);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -57,7 +57,8 @@ pub struct PackageScanner {
|
||||
|
||||
impl PackageScanner {
|
||||
pub async fn new(config: AegisConfig) -> Result<Self> {
|
||||
let cache_dir = dirs::cache_dir()
|
||||
let cache_dir = directories::ProjectDirs::from("eu", "heimatlosen", "aegisaur")
|
||||
.map(|pd| pd.cache_dir().to_path_buf())
|
||||
.unwrap_or_else(|| PathBuf::from("/tmp"))
|
||||
.join("aegisaur");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user