Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions backend/secuscan/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
In-memory cache helpers for API responses.
"""

import json
from typing import Any, Optional, Dict
import time
from typing import Any, Dict, Optional

from .config import settings

Expand Down
13 changes: 6 additions & 7 deletions backend/secuscan/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,24 @@
SecuScan CLI - Command line interface for running security scans
"""

import asyncio
import argparse
import asyncio
import json
import sys
import os
from datetime import datetime
from pathlib import Path
from typing import Optional, Dict, Any
from typing import Optional

# Add the parent directory to sys.path to allow absolute imports
sys.path.append(str(Path(__file__).resolve().parents[2]))

from backend.secuscan.executor import executor
from backend.secuscan.database import init_db, get_db
from backend.secuscan.cache import init_cache
from backend.secuscan.config import settings
from backend.secuscan.plugins import init_plugins, get_plugin_manager
from backend.secuscan.database import get_db, init_db
from backend.secuscan.executor import executor
from backend.secuscan.plugins import get_plugin_manager, init_plugins
from backend.secuscan.reporting import reporting


async def run_scan(target: str, plugin_id: str, output_format: str, output_file: Optional[str] = None):
"""Initialize components and execute a scan task."""

Expand Down
5 changes: 3 additions & 2 deletions backend/secuscan/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
Configuration management for SecuScan backend
"""

import base64
import hashlib
from pathlib import Path
from typing import Any, List, Optional

from pydantic import field_validator
from pydantic_settings import BaseSettings
import base64
import hashlib

PROJECT_ROOT = Path(__file__).resolve().parent.parent

Expand Down
5 changes: 2 additions & 3 deletions backend/secuscan/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@
SQLite database access for SecuScan.
"""

import asyncio
import json
import sqlite3
from pathlib import Path
from typing import Any, Optional, List, Dict
from typing import Dict, List, Optional

import aiosqlite

from .config import settings


Expand Down
29 changes: 19 additions & 10 deletions backend/secuscan/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,29 @@
"""

import asyncio
from asyncio import subprocess
import uuid
import json
import time
from pathlib import Path
from datetime import datetime
from typing import Optional, Dict, Any, List
import logging
import re
import time
import uuid
from asyncio import subprocess
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional

from .redaction import redact
from .cache import get_cache
from .config import settings
from .database import get_db
from .plugins import get_plugin_manager
from .models import TaskStatus
from .plugins import get_plugin_manager
from .ratelimit import concurrent_limiter
from .ratelimit import concurrent_limiter
from .redaction import redact

# Modular Scanners
from .scanners.port_scanner import PortScanner
from .scanners.web_scanner import WebScanner
from .scanners.recon_scanner import ReconScanner
from .scanners.web_scanner import WebScanner
from .validation import validate_timeout

MODULAR_SCANNERS = {
"port_scanner": PortScanner,
Expand Down Expand Up @@ -107,6 +107,15 @@ async def create_task(
# Merge preset with user inputs (user inputs take precedence)
inputs = {**preset_values, **inputs}

# Validate timeout if provided and supported
if "timeout" in inputs and plugin.timeout_config:
timeout_val = int(inputs["timeout"])
min_t = plugin.timeout_config.get("min", 10)
max_t = plugin.timeout_config.get("max", 3600)
is_valid, err = validate_timeout(timeout_val, min_t, max_t)
if not is_valid:
raise ValueError(err)

# Store task in database
db = await get_db()
await db.execute(
Expand Down
12 changes: 6 additions & 6 deletions backend/secuscan/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,23 @@
"""

import logging
import sys
import shutil
from pathlib import Path
import sys
from contextlib import asynccontextmanager
from pathlib import Path

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles

from .cache import cache as global_cache
from .cache import init_cache
from .config import settings
from .cache import init_cache, cache as global_cache
from .database import init_db, db as global_db
from .database import db as global_db
from .database import init_db
from .plugins import init_plugins
from .routes import router
from .workflows import scheduler


# Configure logging
logging.basicConfig(
level=getattr(logging, settings.log_level),
Expand Down
10 changes: 8 additions & 2 deletions backend/secuscan/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
Pydantic models for API requests and responses
"""

from typing import Optional, Dict, Any, List
from datetime import datetime
from pydantic import BaseModel, Field
from enum import Enum
from typing import Any, Dict, List, Optional

from pydantic import BaseModel, Field


class SafetyLevel(str, Enum):
Expand Down Expand Up @@ -66,6 +67,11 @@ class PluginMetadata(BaseModel):
fields: List[PluginField]
presets: Dict[str, Dict[str, Any]]

timeout_config: Optional[Dict[str, Any]] = Field(
default=None,
description="Configuration for timeout behavior: { 'enabled': bool, 'min': int, 'max': int, 'default': int }"
)

output: Dict[str, Any]
safety: Dict[str, Any]
learning: Optional[Dict[str, Any]] = None
Expand Down
12 changes: 6 additions & 6 deletions backend/secuscan/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@
Plugin loader and management system
"""

import hashlib
import hmac
import json
import logging
import os
import re
from pathlib import Path
from typing import Any, Dict, Optional, List
import logging
import shutil
import hashlib
import hmac
from pathlib import Path
from typing import Any, Dict, List, Optional

from .models import PluginMetadata
from .config import settings
from .models import PluginMetadata

logger = logging.getLogger(__name__)

Expand Down
4 changes: 2 additions & 2 deletions backend/secuscan/ratelimit.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
Rate limiting for task execution
"""

import asyncio
from collections import defaultdict
from datetime import datetime, timedelta
from typing import Tuple, Dict, List
import asyncio
from typing import Dict, List, Tuple


class RateLimiter:
Expand Down
2 changes: 1 addition & 1 deletion backend/secuscan/redaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
finding while the secret value itself is hidden.
"""

import re
import logging
import re
from typing import Any

logger = logging.getLogger(__name__)
Expand Down
3 changes: 2 additions & 1 deletion backend/secuscan/reporting.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
import io
import json
import re
from .redaction import redact, redact_dict
from datetime import datetime
from functools import lru_cache
from typing import Any, Dict, List

from PIL import Image, ImageDraw
from xhtml2pdf import pisa

from .redaction import redact, redact_dict


class ReportGenerator:
"""Handles PDF, HTML, and CSV generation for security audits."""
Expand Down
29 changes: 15 additions & 14 deletions backend/secuscan/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@
API routes for SecuScan backend
"""

from fastapi import APIRouter, HTTPException, BackgroundTasks, Response, Request
from fastapi.responses import JSONResponse
from typing import Any, Optional, List, Dict, Callable
import asyncio
import json
import logging
import re
import os
import shutil
import uuid
import asyncio
from pathlib import Path
from typing import Any, Dict, List, Optional
from urllib.parse import urlparse

from fastapi import APIRouter, BackgroundTasks, HTTPException, Request, Response
from fastapi.responses import JSONResponse


def parse_json_fields(rows: List[Dict], fields: List[str]) -> List[Dict]:
"""Helper to parse stringified JSON fields from SQLite."""
parsed = []
Expand Down Expand Up @@ -62,23 +63,23 @@ def build_report_filename(task: Dict[str, Any], extension: str) -> str:

logger = logging.getLogger(__name__)

from sse_starlette.sse import EventSourceResponse

from .cache import get_cache
from .models import (
TaskCreateRequest, TaskResponse, TaskResult,
PluginListResponse, ErrorResponse
)
from .config import settings
from .database import get_db
from .plugins import get_plugin_manager, init_plugins
from .executor import executor
from .ratelimit import rate_limiter, concurrent_limiter
from .validation import validate_target, validate_task_start_payload
from .models import (
PluginListResponse,
TaskCreateRequest,
)
from .plugins import get_plugin_manager, init_plugins
from .ratelimit import concurrent_limiter, rate_limiter
from .reporting import reporting
from .validation import validate_target, validate_task_start_payload
from .vault import VaultCrypto
from .workflows import scheduler

from sse_starlette.sse import EventSourceResponse

router = APIRouter(prefix="/api/v1")


Expand Down
4 changes: 2 additions & 2 deletions backend/secuscan/scanners/base.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging
from abc import ABC, abstractmethod
from typing import Dict, Any, List, Optional
from datetime import datetime
import logging
from typing import Any, Dict

logger = logging.getLogger(__name__)

Expand Down
10 changes: 4 additions & 6 deletions backend/secuscan/scanners/port_scanner.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import asyncio
import json
import re
from typing import Dict, Any, List
from .base import BaseScanner
from typing import Any, Dict, List

from ..plugins import get_plugin_manager
from ..config import settings
from datetime import datetime
from .base import BaseScanner


class PortScanner(BaseScanner):
"""
Expand Down
10 changes: 4 additions & 6 deletions backend/secuscan/scanners/recon_scanner.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import asyncio
import json
import logging
import re
from typing import Dict, Any, List
from .base import BaseScanner
from typing import Any, Dict, List

from ..plugins import get_plugin_manager
from ..config import settings
import logging
from datetime import datetime
from .base import BaseScanner

logger = logging.getLogger(__name__)

Expand Down
10 changes: 4 additions & 6 deletions backend/secuscan/scanners/web_scanner.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import asyncio
import json
import re
from typing import Dict, Any, List
from .base import BaseScanner
from typing import Any, Dict, List

from ..plugins import get_plugin_manager
from ..config import settings
from datetime import datetime
from .base import BaseScanner


class WebScanner(BaseScanner):
"""
Expand Down
Loading
Loading