{"id":50248330,"url":"https://github.com/stecrin/legiontrap-ti","last_synced_at":"2026-05-27T00:02:20.132Z","repository":{"id":321297950,"uuid":"1085301578","full_name":"stecrin/legiontrap-ti","owner":"stecrin","description":"Modular, edge-ready honeynet with privacy-by-design, ATT\u0026CK/Sigma exports, and a clean UI.","archived":false,"fork":false,"pushed_at":"2026-05-22T20:16:18.000Z","size":232,"stargazers_count":0,"open_issues_count":7,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-22T22:51:29.709Z","etag":null,"topics":["docker","fastapi","honeypot","mitre-attack","security","threat-intelligence"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stecrin.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"docs/SECURITY_AUDIT.md","support":null,"governance":null,"roadmap":"docs/ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-28T21:16:01.000Z","updated_at":"2026-05-22T20:16:24.000Z","dependencies_parsed_at":"2026-05-22T22:01:13.628Z","dependency_job_id":null,"html_url":"https://github.com/stecrin/legiontrap-ti","commit_stats":null,"previous_names":["stecrin/legiontrap-ti"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/stecrin/legiontrap-ti","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stecrin%2Flegiontrap-ti","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stecrin%2Flegiontrap-ti/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stecrin%2Flegiontrap-ti/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stecrin%2Flegiontrap-ti/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stecrin","download_url":"https://codeload.github.com/stecrin/legiontrap-ti/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stecrin%2Flegiontrap-ti/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33543974,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"ssl_error","status_checked_at":"2026-05-26T15:22:15.568Z","response_time":63,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","fastapi","honeypot","mitre-attack","security","threat-intelligence"],"created_at":"2026-05-27T00:02:15.412Z","updated_at":"2026-05-27T00:02:20.099Z","avatar_url":"https://github.com/stecrin.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# LegionTrap TI\n\n## Table of Contents\n- [Vision](#-vision)\n- [Roadmap](#-roadmap)\n- [Tech Stack](#-tech-stack)\n- [Architecture Overview](#-architecture-overview)\n- [Quick Start](#quick-start-local)\n- [API Endpoints](#api-endpoints)\n- [Database Operations](#database-operations)\n- [Environment Configuration](#environment-configuration)\n- [Privacy \u0026 Anonymization](#privacy--anonymization)\n- [Tests \u0026 CI](#tests--ci)\n- [Troubleshooting](#troubleshooting)\n- [Release Automation](#-release-automation)\n- [Contributing](#contributing)\n- [License](#license)\n\n\n## 🚀 Roadmap\n\n| Phase | Focus Area | Status |\n|-------|-------------|--------|\n| **Phase 0** | Security \u0026 Infrastructure Hygiene | ✅ Complete |\n| **Phase 1** | SQLite Storage Foundation | ✅ Complete |\n| **Phase 2** | HTTP Ingestion API | ✅ Complete |\n| **Phase 3** | GeoIP Enrichment \u0026 Intelligence Exports | ✅ Complete |\n| **Phase 4** | Campaign Intelligence \u0026 Export Maturity | ✅ Complete |\n| **Phase 5** | AI Integration | ✅ Complete |\n| **Phase 6** | Async AI, Output Persistence \u0026 Brief UI | ⏳ Next |\n| **Phase 7** | Privacy-Preserving Federation | ⏳ Planned |\n\nEach phase builds on the previous. See [docs/ROADMAP.md](docs/ROADMAP.md) for full detail.\n\n---\n\n## 💡 Vision\n\nLegionTrap TI was born from a simple idea: to turn raw hacker noise into real, understandable insight.\nIt's not just another honeypot... it's a living system that listens, learns, and reacts.\nEvery IP that touches your network leaves a trace, and LegionTrap TI captures it, cleans it, and turns it into something you can actually use.\n\nThe goal is independence.\nYou don't need a massive enterprise setup or cloud subscription to understand who's targeting you; you can host your own private threat-intelligence environment, built with open tools and transparent logic.\nStep by step, LegionTrap TI is evolving into a smart, self-sustaining platform that detects, analyzes, and reports attacks in real time, helping you stay one step ahead without relying on anyone else's system.\n\n*Pleased to stand among those securing humanity's future in the digital age.\nEvery small defense matters in securing humanity's future.*\n\n**— Stefan Cringusi**\n\n\n## 🧠 Tech Stack\n\n![Python](https://img.shields.io/badge/Python-3.11-blue?logo=python\u0026logoColor=white)\n![FastAPI](https://img.shields.io/badge/FastAPI-Framework-009688?logo=fastapi\u0026logoColor=white)\n![SQLite](https://img.shields.io/badge/SQLite-WAL%20Mode-003B57?logo=sqlite\u0026logoColor=white)\n![Docker](https://img.shields.io/badge/Docker-Containerized-2496ED?logo=docker\u0026logoColor=white)\n![GitHub Actions](https://img.shields.io/badge/GitHub%20Actions-CI%2FCD-2088FF?logo=githubactions\u0026logoColor=white)\n![Semantic Release](https://img.shields.io/badge/Semantic%20Release-Automated%20Versioning-blueviolet?logo=semanticrelease\u0026logoColor=white)\n![MIT License](https://img.shields.io/badge/License-MIT-green.svg)\n\n---\n\n## 🏗️ Architecture Overview\n\nEvents arrive via `POST /api/ingest`, are validated and normalized, and are stored in SQLite. All dashboard and IOC queries run SQL via `EventRepository`.\n\n```\nHoneypot sensors (Cowrie, Dionaea, ...)\n         │\n         │  POST /api/ingest  (x-api-key)\n         ▼\n    FastAPI Backend (app/)\n         │  Pydantic validation → normalization → deduplication\n         │  GeoIP enrichment (country, city, ASN) via geoip2\n         ▼\n    storage/legiontrap.db  (SQLite, primary store)\n         │  INSERT raw_events + events + UPSERT source_ips\n         │  INSERT audit_log\n         │\n    Read path: SQL queries via EventRepository\n         │\n         ├── GET /api/stats, /api/events         → Browser dashboard\n         ├── GET /api/iocs/pf.conf, /ufw.txt     → Firewall scripts\n         ├── GET /api/intelligence/*             → Intelligence panels\n         └── GET /api/exports/*                 → External TI tools\n```\n\nSee [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the full component map.\n\n---\n\n## Quick Start (local)\n\n```bash\n# 1. Copy and populate required environment variables\ncp .env.example .env\n# Edit .env: set API_KEY, FEED_SALT, DASH_USER, DASH_PASS (bcrypt hash)\n\n# 2. Install dependencies\npip install -r requirements.txt\n\n# 3. Apply database migrations\nmake db-migrate\n\n# 4. Start the API\nmake run\n\n# 5. Health check\ncurl -s http://127.0.0.1:8088/api/health | python -m json.tool\n\n# 6. Ingest a test event\nH='x-api-key: \u003cyour-API_KEY\u003e'\ncurl -s -H \"$H\" -H 'Content-Type: application/json' \\\n  -d '{\"events\":[{\"ts\":\"2025-10-28T18:31:08+00:00\",\"source\":\"cowrie\",\"type\":\"cowrie.login.failed\",\"data\":{\"ip\":\"1.2.3.4\",\"username\":\"root\",\"password\":\"bad\"}}]}' \\\n  http://127.0.0.1:8088/api/ingest | python -m json.tool\n\n# 7. Stats and IOC exports\ncurl -s -H \"$H\" http://127.0.0.1:8088/api/stats | python -m json.tool\ncurl -s -H \"$H\" http://127.0.0.1:8088/api/iocs/ufw.txt\ncurl -s -H \"$H\" http://127.0.0.1:8088/api/iocs/pf.conf\n```\n\n---\n\n## API Endpoints\n\n| Method | Path                              | Auth    | Description                              |\n|-------:|-----------------------------------|:-------:|------------------------------------------|\n| GET    | `/api/health`                     | No      | Liveness check                           |\n| POST   | `/api/login`                      | No      | Dashboard login → JWT token              |\n| POST   | `/api/ingest`                     | API key | Batch event ingest (up to 500)           |\n| GET    | `/api/stats`                      | Yes     | Total events, unique IPs, last-24h       |\n| GET    | `/api/events`                     | Yes     | Recent events (newest first)             |\n| GET    | `/api/iocs/ufw.txt`               | Yes     | UFW deny list (privacy-aware)            |\n| GET    | `/api/iocs/pf.conf`               | Yes     | PF table config (privacy-aware)          |\n| GET    | `/api/intelligence/ips`           | Yes     | Top source IPs with reputation scores    |\n| GET    | `/api/intelligence/ips/{ip}`      | Yes     | Detail record for a single IP            |\n| GET    | `/api/intelligence/top-countries` | Yes     | Top countries by event count             |\n| GET    | `/api/intelligence/top-asns`      | Yes     | Top ASNs by event count                  |\n| GET    | `/api/exports/attack-navigator`   | Yes     | ATT\u0026CK Navigator layer JSON              |\n| GET    | `/api/exports/stix`               | Yes     | STIX 2.1 Indicator bundle (blocked when `PRIVACY_MODE=on`) |\n| GET    | `/api/campaigns`                  | Yes     | Campaign list (paginated, sorted by last_seen DESC) |\n| GET    | `/api/campaigns/{id}`             | Yes     | Campaign detail with members and observations |\n| POST   | `/api/campaigns/{id}/summary`     | Yes     | AI-assisted campaign summary (operator-triggered) |\n| POST   | `/api/campaigns/brief`            | Yes     | AI-assisted multi-campaign threat brief  |\n\n**Auth options:**\n- API key header: `x-api-key: \u003cAPI_KEY\u003e`\n- JWT bearer (dashboard): `Authorization: Bearer \u003ctoken\u003e`\n\n---\n\n## Database Operations\n\n```bash\n# Apply all pending migrations (run once after first deploy and after each new migration)\nmake db-migrate\n\n# Check current migration revision\nmake db-status\n\n# Show migration history\nmake db-pending\n\n# Roll back one migration step (use with caution)\nmake db-rollback\n\n# Prune events older than a cutoff date\nmake db-prune PRUNE_BEFORE=2025-01-01T00:00:00+00:00\n\n# Import existing JSONL data\nmake import-jsonl JSONL_FILES=\"storage/events.jsonl\"\n\n# Verify migration correctness (tables, indexes, revision)\nmake db-validate\n```\n\n---\n\n## Environment Configuration\n\n| Variable           | Required | Description                                                      |\n| ------------------ | :------: | ---------------------------------------------------------------- |\n| `API_KEY`          | Yes      | Required header for protected endpoints (`x-api-key`).          |\n| `FEED_SALT`        | Yes      | HMAC salt for privacy-mode IP hashing.                           |\n| `DASH_USER`        | Yes      | Dashboard login username.                                        |\n| `DASH_PASS`        | Yes      | Dashboard password as a bcrypt hash.                             |\n| `PRIVACY_MODE`     | No       | Set `on` to enable privacy masking on IOC exports and block STIX export (default off). |\n| `CORS_ORIGINS`     | No       | Comma-separated allowed origins (default: localhost variants).   |\n| `DB_PATH`          | No       | SQLite file path (default: `storage/legiontrap.db`).             |\n| `LOGIN_RATE_LIMIT` | No       | Rate limit for `/api/login` (default: `5/minute`).               |\n| `AI_BACKEND`       | No       | AI inference backend: `none` (default), `claude`, or `ollama`.   |\n| `ANTHROPIC_API_KEY`| No       | Required when `AI_BACKEND=claude`.                               |\n| `AI_MODEL`         | No       | Model name override for Claude or Ollama (sensible defaults apply). |\n| `OLLAMA_HOST`      | No       | Ollama API endpoint (default: `http://localhost:11434`).         |\n| `AI_TIMEOUT_SECONDS` | No     | Timeout for AI backend requests in seconds (default: 30).        |\n\nCopy `.env.example` for a template with all required variables.\n\n---\n\n## Privacy \u0026 Anonymization\n\nIOC exports support two privacy strategies controlled by `PRIVACY_MODE` and `FEED_SALT`:\n\n**`PRIVACY_MODE=off`** (default): Full IPs exported as-is.\n```\n8.8.8.8\n```\n\n**`PRIVACY_MODE=on`, no `FEED_SALT`**: Last octet masked.\n```\n8.8.8.x\n```\n\n**`PRIVACY_MODE=on`, `FEED_SALT` set**: Deterministic HMAC token (same IP + salt = same token).\n```\nip-a3b4c5d6e7f8\n```\n\nPrivate, loopback, link-local, and reserved IPs are always filtered from exports regardless of privacy mode.\n\n---\n\n## Tests \u0026 CI\n\n```bash\n# Full test suite\npytest -q\n\n# With coverage\npytest -q --cov=app\n\n# Lint checks (must pass before commit)\nblack --check .\nruff check .\n```\n\nCI runs on every push and PR: lint → tests → `pip-audit` → `bandit`. See `.github/workflows/ci.yml`.\n\n---\n\n## Troubleshooting\n\n**`401 Unauthorized`**\nSet the `x-api-key` header matching `API_KEY` in your `.env`.\n\n**Empty IOC output**\nIngest at least one event with a routable public IP via `POST /api/ingest`. Private IPs (`RFC1918`, loopback, link-local) are stored as `src_ip=NULL` and never appear in exports.\n\n**Database not found / no tables**\nRun `make db-migrate` to create the schema. The application does not auto-migrate on startup.\n\n**Port already in use**\nFree port 8088 or set `PORT=\u003cother\u003e` when calling `make run`.\n\n---\n\n## 🚀 Release Automation\n\nThis repository uses **semantic-release** to automatically handle versioning, tagging, and changelog updates.\n\nEach time a commit is pushed to `main`:\n\n1. GitHub Actions runs the **Auto Version \u0026 Release** workflow.\n2. Based on commit messages, it determines the correct semantic version bump.\n3. It generates or updates `CHANGELOG.md`.\n4. It creates and publishes a new GitHub Release.\n\n### Conventional Commit Examples\n\n| Commit type | Example                             | Effect                    |\n| ----------- | ----------------------------------- | ------------------------- |\n| **fix:**    | `fix: resolve missing IOC export`   | Patch release (x.x.+1)   |\n| **feat:**   | `feat: add new dashboard API route` | Minor release (x.+1.0)   |\n| **perf!:**  | `perf!: refactor ingestion engine`  | Major release (+1.0.0)   |\n\n---\n\n## Contributing\n\nPRs welcome. Run linters and tests locally before pushing:\n\n```bash\nruff check --fix .\nblack .\npytest -q\n```\n\n---\n\n## 🧾 Changelog \u0026 Release History\n\n[![GitHub release](https://img.shields.io/github/v/release/stecrin/legiontrap-ti?label=Current%20Version\u0026color=blue)](https://github.com/stecrin/legiontrap-ti/releases/latest)\n\n[View CHANGELOG.md →](https://github.com/stecrin/legiontrap-ti/blob/main/CHANGELOG.md)\n\n---\n\n## License\n\nLicensed under the **MIT License** © 2025 **Stefan Cringusi**.\nSee the full text in [`LICENSE`](LICENSE).\n\n**SPDX-License-Identifier:** MIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstecrin%2Flegiontrap-ti","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstecrin%2Flegiontrap-ti","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstecrin%2Flegiontrap-ti/lists"}