fix: Build-Fehler behoben - v0.1.0 funktioniert
Rust CI / Test (push) Failing after 2s
Rust CI / Release (x86_64-unknown-linux-gnu) (push) Has been skipped
Rust CI / Release (x86_64-unknown-linux-musl) (push) Has been skipped

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:
Thuumate 👻
2026-06-15 17:50:00 +02:00
parent 5190aca72c
commit aedf6676e8
5 changed files with 3059 additions and 47 deletions
Generated
+2984
View File
File diff suppressed because it is too large Load Diff
+36
View File
@@ -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
View File
@@ -1,50 +1,10 @@
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashSet; use std::collections::HashSet;
use std::time::{Duration, Instant}; use std::time::Duration;
use tokio::fs; use tokio::fs;
use tracing::{debug, info, warn}; 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)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IocEntry { pub struct IocEntry {
pub package_name: String, pub package_name: String,
@@ -67,6 +27,22 @@ pub enum ThreatType {
Unknown(String), 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)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ConfidenceLevel { pub enum ConfidenceLevel {
Critical, // Bestätigt von Arch Team / CISA Critical, // Bestätigt von Arch Team / CISA
@@ -75,6 +51,18 @@ pub enum ConfidenceLevel {
Low, // Einzelner Report 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 { pub struct IocFetcher {
client: reqwest::Client, client: reqwest::Client,
cache_dir: std::path::PathBuf, cache_dir: std::path::PathBuf,
@@ -142,9 +130,12 @@ impl IocFetcher {
if cache_file.exists() { if cache_file.exists() {
let metadata = fs::metadata(&cache_file).await?; let metadata = fs::metadata(&cache_file).await?;
let modified = metadata.modified()?; 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 content = fs::read_to_string(&cache_file).await?;
let iocs: Vec<IocEntry> = serde_json::from_str(&content) let iocs: Vec<IocEntry> = serde_json::from_str(&content)
.context("Konnte Cache nicht parsen")?; .context("Konnte Cache nicht parsen")?;
+3 -3
View File
@@ -72,8 +72,8 @@ async fn main() -> Result<()> {
.init(); .init();
let cli = Cli::parse(); let cli = Cli::parse();
let config = AegisConfig::load_or_default()?; let config = AegisConfig::load_or_default().await?;
let scanner = PackageScanner::new(config).await?; let mut scanner = PackageScanner::new(config).await?;
match cli.command { match cli.command {
Commands::Scan { package, verbose } => { Commands::Scan { package, verbose } => {
@@ -97,7 +97,7 @@ async fn main() -> Result<()> {
} else { } else {
println!("{} {}", "⚠️ Bedrohungen gefunden:".red().bold(), threats.len()); println!("{} {}", "⚠️ Bedrohungen gefunden:".red().bold(), threats.len());
for threat in threats { for threat in threats {
println!(" {} {} - {}", "🔴".red(), threat.package, threat.reason); println!(" {} {} - {}", "🔴".red(), threat.package, threat.action_required);
} }
} }
} }
+2 -1
View File
@@ -57,7 +57,8 @@ pub struct PackageScanner {
impl PackageScanner { impl PackageScanner {
pub async fn new(config: AegisConfig) -> Result<Self> { 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")) .unwrap_or_else(|| PathBuf::from("/tmp"))
.join("aegisaur"); .join("aegisaur");