diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..402351d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,32 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +env: + CARGO_TERM_COLOR: always + +jobs: + rust: + strategy: + fail-fast: false + matrix: + toolchain: ["1.85.0", stable] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.toolchain }} + components: rustfmt, clippy + - name: Check formatting + run: cargo fmt --check + - name: Check all targets + run: cargo check --locked --all-targets + - name: Clippy all targets + run: cargo clippy --locked --all-targets -- -D warnings + - name: Tests + run: cargo test --locked diff --git a/Cargo.lock b/Cargo.lock index 225cfdf..b8158bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -138,9 +138,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" diff --git a/Cargo.toml b/Cargo.toml index 680a274..76707f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ name = "rust_hound" version = "0.1.0" edition = "2021" +rust-version = "1.85" [[bin]] name = "rusthound" diff --git a/README.md b/README.md index ee0fd12..f92316c 100644 --- a/README.md +++ b/README.md @@ -1,157 +1,53 @@ -# 🐕 RustHound: Gerçek Zamanlı Log Analiz ve İzleme Aracı +# RustHound -[![Rust](https://img.shields.io/badge/rust-1.83+-orange.svg)](https://www.rust-lang.org) -[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE) -[![Build Status](https://img.shields.io/badge/build-passing-brightgreen.svg)]() -[![Version](https://img.shields.io/badge/version-0.1.0-blue.svg)]() +RustHound is a Rust command-line log analyzer. It reads a log file, applies configured string and regular-expression rules, and can add frequency and correlation detections to console or JSON output. -**RustHound**, Rust ile geliştirilmiş yüksek performanslı, açık kaynaklı gerçek zamanlı log analiz ve izleme aracıdır. Sistem yöneticileri, DevOps mühendisleri ve geliştiriciler için tasarlanmış bu araç, log verilerinizi sürekli olarak izleyerek kritik olayları anında tespit eder. +This is a pre-1.0 portfolio project. The README describes the behavior verified in this repository; it does not claim universal platform support, release artifacts, or benchmark numbers. -## 🎯 Neden RustHound? +## Implemented behavior -- **⚡ Yüksek Performans**: Rust'ın bellek güvenliği ve hızından yararlanır -- **🔍 Akıllı Analiz**: Regex ve pattern matching ile gelişmiş log analizi -- **📊 Gerçek Zamanlı İzleme**: Canlı log takibi ve anında uyarılar -- **🛠️ Kolay Yapılandırma**: TOML tabanlı basit konfigürasyon sistemi -- **🌐 Çapraz Platform**: Linux, macOS ve Windows desteği +- Streaming line-by-line analysis for one file or a directory of `.log` files. +- TOML rules for string patterns, regex patterns, frequency thresholds, and correlated events. +- Console, JSON, and combined output modes. +- Optional follow mode for newly appended log lines. +- Minimum-severity filtering and a default configuration generator. +- Analyzer unit tests for rule precedence, frequency tracking, correlation, and TOML parsing. -## İçindekiler +## Requirements and build -- [Özellikler](#-özellikler) -- [Kurulum](#-kurulum) -- [Kullanım](#-kullanım) -- [Yapılandırma](#-yapılandırma) -- [Katkıda Bulunma](#-katkıda-bulunma) -- [Lisans](#-lisans) +- Rust 1.85 or newer (edition 2021). +- A log file and a TOML rules file for a meaningful run. -## ✨ Özellikler - -* **Gerçek Zamanlı Log İzleme:** Belirtilen log dosyalarını gerçek zamanlı olarak izler ve yeni girişleri anında işler. -* **Kural Tabanlı Desen Eşleştirme:** Yapılandırılabilir kurallar (`rules.toml`) kullanarak log girişlerinde belirli metin desenlerini veya regex ifadelerini eşleştirir. -* **Frekans Analizi:** Tanımlanan desenlerin belirli zaman aralıklarında ne sıklıkta ortaya çıktığını izler ve eşik değerleri aşıldığında uyarı verir. -* **Esnek Çıktı Seçenekleri:** Analiz sonuçlarını konsola yazdırabilir veya yapılandırılabilir JSON dosyalarına kaydedebilir. -* **Çapraz Platform Uyumluluğu:** Linux, macOS ve Windows'ta sorunsuz çalışır. - -## 🚀 Kurulum - -### Sistem Gereksinimleri - -- **Rust 1.83+** (edition 2021) - [rustup.rs](https://rustup.rs/) üzerinden yükleyebilirsiniz -- **Git** (kaynak koddan kurulum için) -- **Minimum 50MB disk alanı** - -### Hızlı Kurulum - -#### Cargo ile (Önerilen) -```bash -# Crates.io'dan direkt kurulum (yakında) -cargo install rust_hound -``` - -#### Kaynak Koddan Kurulum -```bash -# 1. Depoyu klonlayın +~~~bash git clone https://github.com/rustfuture/RustHound.git cd RustHound +cargo build --locked --release +~~~ -# 2. Bağımlılıkları yükleyin ve derleyin -cargo build --release - -# 3. Sistem genelinde kullanım için yükleyin -cargo install --path . -``` - -#### Doğrudan İkili Dosya İndirme -```bash -# GitHub Releases'den en son sürümü indirin -wget https://github.com/rustfuture/RustHound/releases/latest/download/rusthound-linux-x64.tar.gz -tar -xzf rusthound-linux-x64.tar.gz -sudo mv rusthound /usr/local/bin/ -``` - -### Kurulum Doğrulama -```bash -rusthound --version -rusthound --help -``` - -## 📖 Kullanım - -### Hızlı Başlangıç - -```bash -# Basit log dosyası analizi -rusthound --file /var/log/app.log - -# Dizin içindeki tüm log dosyalarını analiz et -rusthound --dir /var/log/ - -# Gerçek zamanlı izleme (tail -f benzeri) -rusthound --file /var/log/app.log --follow -``` - -### Komut Satırı Referansı - -| Parametre | Kısaltma | Açıklama | Varsayılan | -|-----------|----------|----------|------------| -| `--file ` | `-f` | Tek bir log dosyasının yolu | `sample.log` | -| `--dir ` | `-d` | Log dosyalarını içeren dizin | `.` | -| `--rules ` | `-r` | Kurallar dosyasının yolu | `rules.toml` | -| `--output ` | `-o` | Çıktı formatı (`console`, `json`, `both`) | `console` | -| `--follow` | `-F` | Gerçek zamanlı izleme modu | `false` | -| `--severity ` | `-s` | Minimum önem seviyesi | - | -| `--verbose` | `-v` | Detaylı çıktı | `false` | -| `--help` | `-h` | Yardım bilgilerini göster | - | -| `--version` | `-V` | Sürüm bilgilerini göster | - | +## Quick start -### Kullanım Örnekleri +The repository includes a small sample log and rules file: -#### Temel Log Analizi -```bash -# Tek dosya analizi -rusthound -f /var/log/nginx/access.log +~~~bash +cargo run --locked -- \ + --file sample.log \ + --rules rules.toml \ + --output console +~~~ -# Özel kurallar ile analiz -rusthound -f app.log -r custom_rules.toml -``` +The verified sample run emits eight detections with severity and source-line context. Generate a starter rules file with: -#### Gerçek Zamanlı İzleme -```bash -# Canlı log takibi -rusthound -f /var/log/syslog --follow +~~~bash +cargo run --locked -- --init-config +~~~ -# JSON çıktısı ile canlı takip -rusthound -d /var/log/ --follow -o json -``` +For JSON output, use `--output json`; for both console and JSON, use `--output both`. `--follow` monitors appended content. `--dir PATH` scans regular `.log` files in a directory. -#### Filtreleme ve Çıktı -```bash -# Sadece kritik seviye uyarılar -rusthound -f app.log -s critical +## Rule configuration -# Hem konsol hem JSON çıktısı -rusthound -f app.log -o both +The default `rules.toml` supports these sections: -# Detaylı hata ayıklama -rusthound -f app.log --verbose -``` - -#### Toplu İşleme -```bash -# Tüm log dizinini analiz et -rusthound -d /var/log/ -r production_rules.toml - -# Belirli pattern'ler için tarama -rusthound -d /home/user/logs/ -s high -o json -``` - -## ⚙️ Yapılandırma - -RustHound, esnek TOML tabanlı yapılandırma sistemi kullanır. Varsayılan olarak `rules.toml` dosyasını arar. - -### Temel Yapılandırma Dosyası (`rules.toml`) - -```toml +~~~toml [rules] error_patterns = ["ERROR", "FATAL", "Exception"] warning_patterns = ["WARN", "WARNING"] @@ -161,161 +57,40 @@ name = "authentication_failure" pattern = "authentication failure|Failed password for" severity = "high" -[[regex_rules]] -name = "Successful Login" -pattern = "(?i)successful login|session opened for user" -severity = "info" - [frequency_rules] max_same_errors_per_minute = 10 time_window_seconds = 60 +~~~ -[[correlated_rules]] -name = "Potential Brute-Force Attack" -severity = "critical" -description = "Çok sayıda başarısız giriş sonrası başarılı giriş" -time_window_seconds = 60 -followed_by = "Successful Login" - -[correlated_rules.trigger_on_rule] -name = "authentication_failure" -count = 10 -``` - -### Yapılandırma Seçenekleri - -Detaylı şema: `.cursor/skills/rusthound-rules-toml/SKILL.md` - -#### Pattern türleri -- **Basit string** (`[rules]`): Anahtar kelime eşleştirme -- **Regex** (`[[regex_rules]]`): Gelişmiş desenler -- **Frekans** (`[frequency_rules]`): Zaman penceresinde tekrar sayımı -- **Korelasyon** (`[[correlated_rules]]`): Ardışık olay zinciri - -#### Önem seviyeleri -`critical`, `high`, `warning`, `error`, `info` — CLI: `rusthound -f app.log -s high` - -### Örnek Yapılandırmalar +Correlated rules can model a sequence such as repeated authentication failures followed by a successful login. The checked-in examples are the source of truth for the accepted TOML schema. -#### Web sunucu -```toml -[[regex_rules]] -name = "HTTP 5xx Errors" -pattern = "HTTP/1\.\[01]" [5][0-9][0-9]" -severity = "high" -``` - -#### Korelasyon dosyası -`rusthound -f auth.log -r correlated_rules.toml` - -## Cursor Agent Skills - -RustHound includes Cursor skills under `.cursor/skills/`: - -- **Project skills** (`rusthound-*`) — architecture, TOML schema, dev workflow -- **Community skills** — Rust ([ZhangHanDong/rust-skills](https://github.com/ZhangHanDong/rust-skills)), verification ([bluriesophos/cursorskills](https://github.com/bluriesophos/cursorskills)), DevOps ([awesome-cursor-skills](https://github.com/spencerpauly/awesome-cursor-skills)) - -Install or refresh third-party skills: - -```bash -./scripts/install-cursor-skills.sh -``` - -See `.cursor/skills/README.md` for the full catalog. - -## 🤝 Katkıda Bulunma - -RustHound açık kaynak bir projedir ve katkılarınızı memnuniyetle karşılarız! - -### Nasıl Katkıda Bulunabilirsiniz? - -1. **🐛 Bug Raporları**: [Issues](https://github.com/rustfuture/RustHound/issues) sayfasından bug bildirin -2. **💡 Özellik İstekleri**: Yeni özellik önerilerinizi paylaşın -3. **📝 Dokümantasyon**: README, kod yorumları ve örnekleri iyileştirin -4. **🔧 Kod Katkıları**: Pull request gönderin - -### Geliştirme Ortamı Kurulumu - -```bash -# Projeyi fork edin ve klonlayın -git clone https://github.com/rustfuture/RustHound.git -cd RustHound +## Verification -# Geliştirme bağımlılıklarını yükleyin -cargo build - -# Testleri çalıştırın -cargo test - -# Kod formatını kontrol edin +~~~bash cargo fmt --check -cargo clippy -``` - -### Katkı Kuralları - -- Kod değişikliklerinden önce issue açın -- Commit mesajlarında [Conventional Commits](https://conventionalcommits.org/) kullanın -- Yeni özellikler için test yazın -- Dokümantasyonu güncel tutun - -## 📊 Performans - -- **Bellek Kullanımı**: ~10-50MB (dosya boyutuna bağlı) -- **İşleme Hızı**: ~100K satır/saniye -- **Desteklenen Dosya Boyutu**: Sınırsız (streaming işleme) -- **Eş Zamanlı Dosya**: 100+ dosya - -## 🔧 Sorun Giderme - -### Yaygın Sorunlar - -**Problem**: `Permission denied` hatası -```bash -# Çözüm: Dosya izinlerini kontrol edin -chmod +r /var/log/app.log -``` - -**Problem**: Yüksek bellek kullanımı -```bash -# Çözüm: Streaming mode kullanın -rusthound -f large_file.log --follow -``` - -**Problem**: Regex pattern çalışmıyor -```bash -# Çözüm: Pattern'i test edin -rusthound -f test.log --verbose -``` - -## 📜 Lisans - -Bu proje **Apache License 2.0** altında lisanslanmıştır. - -``` -Copyright 2024 RustHound Contributors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 +cargo check --locked --all-targets +cargo clippy --locked --all-targets -- -D warnings +cargo test --locked +cargo +1.85.0 check --locked --all-targets +~~~ -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -``` +The current local run passes 12 library tests, no duplicate binary test suite, and the doctest target. The sample CLI invocation above is a real file-processing smoke test, not a benchmark. -Detaylar için [LICENSE](LICENSE) dosyasına bakın. +## Scope and limitations ---- +- The normal path processes files in a streaming manner; no throughput or memory number is published without a controlled benchmark environment. +- Follow mode is a local file watcher, not a distributed ingestion service. +- Cross-platform behavior beyond the tested macOS environment and CI’s Linux environment requires separate validation. +- The repository has no release artifacts or `cargo install` package published by this portfolio milestone; the source build is the supported installation path. +- `scripts/install-cursor-skills.sh` is development tooling and is not part of the analyzer runtime. -
+## Architecture -**⭐ Projeyi beğendiyseniz yıldız vermeyi unutmayın!** +- `src/analyzer/` — pattern matching, frequency tracking, and correlation state. +- `src/config/` — TOML schema and rule loading. +- `src/watcher/` — file reading, offsets, and follow-mode notifications. +- `src/output/` — detection types, console rendering, and JSON writing. -[🐛 Bug Bildir](https://github.com/rustfuture/RustHound/issues) • [💡 Özellik İste](https://github.com/rustfuture/RustHound/issues) • [📖 Dokümantasyon](https://github.com/rustfuture/RustHound/wiki) +## License and attribution -
\ No newline at end of file +Apache-2.0. See [LICENSE](LICENSE). Third-party development helpers are not presented as product functionality. diff --git a/docs/validation/2026-09-06.md b/docs/validation/2026-09-06.md new file mode 100644 index 0000000..11bc622 --- /dev/null +++ b/docs/validation/2026-09-06.md @@ -0,0 +1,23 @@ +# RustHound validation — 2026-09-06 + +This is a local validation record for the provisional third Rust showcase candidate. It is evidence for the listed sample and environments, not a universal compatibility or performance claim. + +## Checks + +The following passed with the committed lockfile on macOS Apple Silicon: + +~~~bash +cargo fmt --check +cargo check --locked --all-targets +cargo clippy --locked --all-targets -- -D warnings +cargo test --locked +cargo +1.85.0 check --locked --all-targets +~~~ + +The lockfile was updated from `bytes 1.10.1` to patched `bytes 1.11.1` after GitHub Dependabot reported GHSA-434x-w66g-qw3r (integer overflow in `BytesMut::reserve`). + +The library suite reports 12 tests; the binary reuses the library modules and therefore has no duplicate test suite. The sample CLI invocation using `sample.log` and `rules.toml` produced eight console detections with source lines and severities. + +## Boundaries checked + +The sample proves a real file-processing path and the tests cover analyzer behavior. It does not prove Windows runtime behavior, release packaging, benchmark throughput, or production log-ingestion deployment. diff --git a/src/main.rs b/src/main.rs index 7995c59..8505c15 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,8 @@ use anyhow::Context; use clap::Parser; +use rust_hound::{analyzer, config, output, watcher}; use std::path::PathBuf; -mod analyzer; -mod config; -mod output; -mod watcher; - #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] struct Args { diff --git a/src/output/console.rs b/src/output/console.rs index 27a908a..3737e64 100644 --- a/src/output/console.rs +++ b/src/output/console.rs @@ -7,7 +7,7 @@ pub fn display_detections(detections: &mut Vec, min_severity: Option< detections.retain(|d| d.severity.meets_minimum(&minimum)); } - detections.sort_by(|a, b| a.line_number.cmp(&b.line_number)); + detections.sort_by_key(|detection| detection.line_number); for detection in detections { let colored_severity = match detection.severity { diff --git a/src/watcher/log_reader.rs b/src/watcher/log_reader.rs index b655f9f..03b9bd0 100644 --- a/src/watcher/log_reader.rs +++ b/src/watcher/log_reader.rs @@ -102,7 +102,7 @@ pub async fn read_file_from_offset( detections.push(detection.clone()); } - if (output_format == "json" || output_format == "both") && json_output_file.is_some() { + if output_format == "json" || output_format == "both" { let json_detection = crate::output::json_writer::AnomalyDetection { timestamp: chrono::Local::now().to_rfc3339(), severity: severity.to_string(), @@ -112,28 +112,27 @@ pub async fn read_file_from_offset( matched_line: line.clone(), pattern: pattern_name.to_string(), }; - crate::output::json_writer::write_json_output( - &json_detection, - json_output_file.as_mut().unwrap(), - )?; + if let Some(output_file) = json_output_file.as_mut() { + crate::output::json_writer::write_json_output(&json_detection, output_file)?; + } } if let Some(tracker) = &mut scan_state.frequency_tracker { if let Some(count) = tracker.track_event(pattern_name) { if output_format == "console" || output_format == "both" { - detections.push(create_frequency_detection( - pattern_name, - count, - frequency_rules.as_ref().unwrap().max_same_errors_per_minute, - frequency_rules.as_ref().unwrap().time_window_seconds, - file_path, - current_line_number, - &line, - )); + if let Some(rules) = frequency_rules.as_ref() { + detections.push(create_frequency_detection( + pattern_name, + count, + rules.max_same_errors_per_minute, + rules.time_window_seconds, + file_path, + current_line_number, + &line, + )); + } } - if (output_format == "json" || output_format == "both") - && json_output_file.is_some() - { + if output_format == "json" || output_format == "both" { let json_detection = crate::output::json_writer::AnomalyDetection { timestamp: chrono::Local::now().to_rfc3339(), severity: "frequency".to_string(), @@ -143,10 +142,12 @@ pub async fn read_file_from_offset( matched_line: line.clone(), pattern: pattern_name.to_string(), }; - crate::output::json_writer::write_json_output( - &json_detection, - json_output_file.as_mut().unwrap(), - )?; + if let Some(output_file) = json_output_file.as_mut() { + crate::output::json_writer::write_json_output( + &json_detection, + output_file, + )?; + } } } }