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 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
@@ -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
@@ -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");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user