Contributing¶
Getting Started¶
Prerequisites¶
- Python 3.13+
- Node.js 20+ (for frontend development)
- Git
Clone and Install¶
git clone https://github.com/Ap6pack/malwar.git
cd malwar
# Install in editable mode with dev dependencies
pip install -e ".[dev]"
# Initialize the database
malwar db init
Frontend Setup (Optional)¶
Environment Configuration¶
Project Structure¶
malwar/
+-- src/malwar/ # Main package
| +-- core/ # Core infrastructure (config, constants, exceptions)
| +-- scanner/ # Pipeline orchestration
| +-- detectors/ # Detection layers
| | +-- rule_engine/ # Layer 1: Pattern matching
| | +-- url_crawler/ # Layer 2: URL analysis
| | +-- llm_analyzer/ # Layer 3: LLM semantic analysis
| | +-- threat_intel/ # Layer 4: Threat intelligence
| +-- models/ # Pydantic data models
| +-- parsers/ # SKILL.md parsing
| +-- crawl/ # ClawHub registry crawler
| +-- cli/ # Command-line interface
| +-- api/ # REST API
| +-- storage/ # Database layer
| +-- notifications/ # Webhook dispatcher
+-- tests/ # Test suite
| +-- unit/ # Unit tests
| +-- integration/ # Integration tests
| +-- e2e/ # End-to-end tests
| +-- fixtures/ # Test fixture files
+-- web/ # React + TypeScript frontend
+-- docs/ # Documentation
How to Add a New Detection Rule¶
Step 1: Create the Rule Class¶
Create a new file in src/malwar/detectors/rule_engine/rules/ or add to an existing file:
# Copyright (c) 2026 Veritas Aequitas Holdings LLC. All rights reserved.
from malwar.core.constants import DetectorLayer, Severity, ThreatCategory
from malwar.detectors.rule_engine.base_rule import BaseRule
from malwar.detectors.rule_engine.registry import rule
from malwar.models.finding import Finding, Location
from malwar.models.skill import SkillContent
@rule
class MyNewRule(BaseRule):
rule_id = "MALWAR-NEW-001"
title = "Description of what this detects"
severity = Severity.HIGH
category = ThreatCategory.SUSPICIOUS_COMMAND
description = "Detailed description"
def check(self, skill: SkillContent) -> list[Finding]:
findings = []
for line_num, line in enumerate(skill.raw_content.splitlines(), 1):
# Pattern matching logic here
pass
return findings
Step 2: Register the Import¶
If you created a new file, add its import to the rule engine detector:
# src/malwar/detectors/rule_engine/detector.py
import malwar.detectors.rule_engine.rules.my_new_rules # noqa: F401
Step 3: Add Tests¶
def test_my_new_rule_detects_threat():
skill = parse_skill_content("---\nname: test\n---\n# Test\ntrigger-content")
rule = MyNewRule()
findings = rule.check(skill)
assert len(findings) >= 1
Rule Design Guidelines¶
- Use compiled regex for performance
- Set appropriate confidence (0.90+ for exact IOC matches, 0.60-0.80 for heuristics)
- Include evidence explaining what triggered the rule
- Break after first match per line to avoid duplicates
- Follow the naming convention
MALWAR-{CATEGORY}-{NUMBER}
How to Add a New API Endpoint¶
Step 1: Create a Route Module¶
# src/malwar/api/routes/my_feature.py
from fastapi import APIRouter, Depends
from malwar.api.auth import require_api_key
router = APIRouter()
@router.get("/my-endpoint")
async def my_endpoint(_api_key: str = Depends(require_api_key)):
return {"message": "Hello"}
Step 2: Register the Router¶
# In src/malwar/api/app.py create_app():
app.include_router(my_feature.router, prefix="/api/v1", tags=["my-feature"])
Testing¶
Running Tests¶
pytest # Run all tests
pytest -v # Verbose output
pytest tests/unit/ # Unit tests only
pytest tests/integration/ # Integration tests only
pytest --cov=malwar --cov-report=term-missing # With coverage
pytest --cov=malwar --cov-fail-under=85 # Coverage threshold
Test Organization¶
| Directory | Purpose |
|---|---|
tests/unit/ |
Unit tests for individual modules |
tests/integration/ |
Tests exercising multiple components |
tests/e2e/ |
End-to-end tests with real skill files |
tests/fixtures/ |
Test data files (SKILL.md samples) |
Linting and Formatting¶
ruff check src/ tests/ # Check for lint errors
ruff check --fix src/ tests/ # Auto-fix
ruff format src/ tests/ # Format code
mypy src/ # Type checking
Code Conventions¶
Copyright Headers¶
Every source file must include:
Imports¶
- Use
from __future__ import annotations - Organize: stdlib, third-party, first-party (
malwar.*)
Data Models¶
- Use Pydantic
BaseModelfor all data models - Use
Field()with descriptions for API-facing models - Use Python
StrEnumfor enumerations
Async/Await¶
- All I/O operations are async
- The CLI uses
asyncio.run()to bridge sync Typer with async internals