Development Guide ================= Guide for developers contributing to VulnerabilityHub. Development Setup ----------------- Prerequisites ~~~~~~~~~~~~~ - Python 3.9+ - Node.js 16+ and npm - Docker and Docker Compose - Git - MySQL/MariaDB client tools Local Development Environment ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1. Clone and Setup ^^^^^^^^^^^^^^^^^^ .. code-block:: bash git clone cd vulnerability-scanner # Create virtual environment python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate # Install backend dependencies cd backend pip install -r requirements.txt pip install -r requirements-dev.txt # Development dependencies # Install frontend dependencies cd ../frontend/app npm install 2. Database Setup ^^^^^^^^^^^^^^^^^ .. code-block:: bash # Start database only docker-compose up -d db # Initialize schema (password is in secrets/db_root_password.txt) mariadb -h 127.0.0.1 -P 3306 -u root -p$(cat secrets/db_root_password.txt) vulnerabilityhub < src/database/vulnerability_scanner.sql 3. Environment Configuration ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Create ``backend/.env``: .. code-block:: bash ENV=development SECRET_KEY=dev-secret-key SMTP_SERVER=localhost SMTP_PORT=1025 SMTP_SENDER=VulnerabilityHub BACKEND_URL=http://localhost:8000 # Database (defaults are usually fine for local docker db) DB_HOST=127.0.0.1 DB_PORT=3306 DB_USER=appuser DB_PASSWORD=appuser_password_from_secret .. note:: Ensure ``DB_PASSWORD`` matches ``secrets/db_password.txt``. 4. Run Development Servers ^^^^^^^^^^^^^^^^^^^^^^^^^^ **Backend**: .. code-block:: bash cd backend uvicorn main:app --reload --host 0.0.0.0 --port 8000 **Frontend**: .. code-block:: bash cd frontend/app npm run dev Access: - Frontend: http://localhost:5173 (Vite dev server) - Backend API: http://localhost:8000 - API Docs: http://localhost:8000/docs Project Structure ----------------- .. code-block:: bash vulnerability-scanner/ ├── backend/ # Python FastAPI backend │ ├── core/ # Core utilities (DB, config, email) │ ├── crud/ # Database operations │ ├── models/ # SQLAlchemy models │ ├── routes/ # API endpoints │ ├── schemas/ # Pydantic schemas │ ├── services/ # Business logic │ ├── importers/ # Pluggable import system │ ├── main.py # Application entry point │ └── requirements.txt # Python dependencies ├── frontend/app/ # Vue 3 frontend │ ├── src/ │ │ ├── components/ # Vue components │ │ ├── views/ # Page components │ │ ├── stores/ # Pinia stores │ │ ├── router.ts # Vue Router config │ │ └── main.ts # App entry point │ ├── package.json # Node dependencies │ └── vite.config.ts # Vite configuration ├── database/ # SQL schemas ├── grafana/ # Grafana dashboards ├── docs/ # Documentation └── docker-compose.yml # Docker services Backend Development ------------------- Adding a New API Endpoint ~~~~~~~~~~~~~~~~~~~~~~~~~ 1. **Create Route** (``backend/routes/my_feature.py``): .. code-block:: python from fastapi import APIRouter, Depends from sqlalchemy.orm import Session from core.db import get_db from routes.auth import get_current_admin_user router = APIRouter() @router.get("/my-feature") def get_my_feature( db: Session = Depends(get_db), current_user = Depends(get_current_admin_user) ): return {"message": "Hello from my feature"} 2. **Register Router** (``backend/main.py``): .. code-block:: python from routes import my_feature app.include_router(my_feature.router) 3. **Test**: .. code-block:: bash curl http://localhost:8000/my-feature \ -H "Authorization: Bearer $TOKEN" Adding a Database Model ~~~~~~~~~~~~~~~~~~~~~~~ 1. **Create Model** (``backend/models/my_model.py``): .. code-block:: python from sqlalchemy import Column, Integer, String from core.db import Base class MyModel(Base): __tablename__ = "my_table" id = Column(Integer, primary_key=True, index=True) name = Column(String(255), nullable=False) 2. **Create Schema** (``backend/schemas/my_model.py``): .. code-block:: python from pydantic import BaseModel class MyModelBase(BaseModel): name: str class MyModelCreate(MyModelBase): pass class MyModel(MyModelBase): id: int class Config: from_attributes = True 3. **Create CRUD** (``backend/crud/my_model.py``): .. code-block:: python from sqlalchemy.orm import Session from models.my_model import MyModel from schemas.my_model import MyModelCreate def create_my_model(db: Session, data: MyModelCreate): db_obj = MyModel(**data.dict()) db.add(db_obj) db.commit() db.refresh(db_obj) return db_obj 4. **Update Database**: .. code-block:: sql -- Add to database/vulnerability_scanner.sql CREATE TABLE IF NOT EXISTS my_table ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL ); Testing ~~~~~~~ Unit Tests ^^^^^^^^^^ .. code-block:: bash cd backend pytest tests/ Integration Tests ^^^^^^^^^^^^^^^^^ .. code-block:: bash pytest tests/integration/ Test Coverage ^^^^^^^^^^^^^ .. code-block:: bash pytest --cov=. --cov-report=html Frontend Development -------------------- Adding a New Component ~~~~~~~~~~~~~~~~~~~~~~ 1. **Create Component** (``frontend/app/src/components/MyComponent.vue``): .. code-block:: vue 2. **Use Component**: .. code-block:: vue Adding a New Route ~~~~~~~~~~~~~~~~~~ 1. **Create View** (``frontend/app/src/views/MyView.vue``) 2. **Register Route** (``frontend/app/src/router.ts``): .. code-block:: typescript { path: '/my-view', component: () => import('./views/MyView.vue'), meta: { requiresAuth: true } } State Management with Pinia ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1. **Create Store** (``frontend/app/src/stores/myStore.ts``): .. code-block:: typescript import { defineStore } from 'pinia'; import axios from 'axios'; export const useMyStore = defineStore('myStore', { state: () => ({ items: [] as any[], loading: false }), actions: { async fetchItems() { this.loading = true; try { const response = await axios.get('/api/items'); this.items = response.data; } finally { this.loading = false; } } } }); 2. **Use Store**: .. code-block:: vue Code Style Guidelines --------------------- Python (Backend) ~~~~~~~~~~~~~~~~ - Follow PEP 8 - Use type hints - Maximum line length: 100 characters - Use docstrings for functions and classes .. code-block:: python def process_scan( db: Session, scan_id: int, options: Optional[Dict[str, Any]] = None ) -> Scan: """ Process a vulnerability scan. Args: db: Database session scan_id: ID of scan to process options: Optional processing options Returns: Processed scan object """ # Implementation pass TypeScript/Vue (Frontend) ~~~~~~~~~~~~~~~~~~~~~~~~~ - Use TypeScript for type safety - Composition API for Vue components - Use ``