Complete Phase 2 with comprehensive testing and documentation suite. Testing: - Reviewed existing test suite: 100 test functions, 1,825 lines of test code - All tests passing across 6 test files - Coverage: service layer, API endpoints, authentication, background jobs, error handling Documentation Created: - API_REFERENCE.md (17KB): Complete REST API documentation with examples * All 5 scan endpoints documented * Settings API reference * Authentication flow examples * Request/response examples with curl commands * Error handling and status codes - PHASE2_COMPLETE.md (29KB): Comprehensive Phase 2 summary * All success criteria met (100%) * Deliverables by step (7 steps completed) * Code metrics: 34 files created, ~7,500+ lines * Technical implementation details * Lessons learned and key accomplishments - MANUAL_TESTING.md (24KB): Manual testing checklist * 38 comprehensive tests across 10 categories * Step-by-step test procedures * Expected results for each test * Critical tests highlighted - README.md: Major update with Phase 2 features * Quick start for web application * Complete web application section * API endpoints reference * Deployment instructions * Development section with testing guide - ROADMAP.md: Updated with Phase 2 completion * Marked Phase 2 as COMPLETE ✅ * Updated progress overview * Phase 2 success criteria achieved * Changelog updated Phase 2 Final Metrics: - Files Created: 34 - Lines of Code: ~7,500+ - Test Functions: 100 (all passing) - Documentation: 2,000+ lines across 5 documents Features Delivered: - REST API (5 scan endpoints, 3 settings endpoints) - Background job queue with APScheduler - Session-based authentication - Web UI (dashboard, scans, login, error pages) - Comprehensive error handling and logging - Docker deployment with healthcheck - Complete documentation suite Status: Phase 2 COMPLETE ✅ - Production ready Next: Phase 3 - Dashboard & Scheduling 🤖 Generated with SneakyScanner Development Tools
767 lines
17 KiB
Markdown
767 lines
17 KiB
Markdown
# SneakyScanner Web API Reference
|
|
|
|
**Version:** 2.0 (Phase 2)
|
|
**Base URL:** `http://localhost:5000`
|
|
**Authentication:** Session-based (Flask-Login)
|
|
|
|
## Table of Contents
|
|
|
|
1. [Authentication](#authentication)
|
|
2. [Scans API](#scans-api)
|
|
3. [Settings API](#settings-api)
|
|
4. [Error Handling](#error-handling)
|
|
5. [Status Codes](#status-codes)
|
|
6. [Request/Response Examples](#request-response-examples)
|
|
|
|
---
|
|
|
|
## Authentication
|
|
|
|
SneakyScanner uses session-based authentication with Flask-Login. All API endpoints (except login) require authentication.
|
|
|
|
### Login
|
|
|
|
Authenticate and create a session.
|
|
|
|
**Endpoint:** `POST /auth/login`
|
|
|
|
**Request Body:**
|
|
```json
|
|
{
|
|
"password": "your-password-here"
|
|
}
|
|
```
|
|
|
|
**Success Response (200 OK):**
|
|
```json
|
|
{
|
|
"message": "Login successful",
|
|
"redirect": "/dashboard"
|
|
}
|
|
```
|
|
|
|
**Error Response (401 Unauthorized):**
|
|
```json
|
|
{
|
|
"error": "Invalid password"
|
|
}
|
|
```
|
|
|
|
**Usage Example:**
|
|
```bash
|
|
# Login and save session cookie
|
|
curl -X POST http://localhost:5000/auth/login \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"password":"yourpassword"}' \
|
|
-c cookies.txt
|
|
|
|
# Use session cookie for subsequent requests
|
|
curl -X GET http://localhost:5000/api/scans \
|
|
-b cookies.txt
|
|
```
|
|
|
|
### Logout
|
|
|
|
Destroy the current session.
|
|
|
|
**Endpoint:** `GET /auth/logout`
|
|
|
|
**Success Response:** Redirects to login page (302)
|
|
|
|
---
|
|
|
|
## Scans API
|
|
|
|
Manage network scans: trigger, list, view, and delete.
|
|
|
|
### Trigger Scan
|
|
|
|
Start a new background scan.
|
|
|
|
**Endpoint:** `POST /api/scans`
|
|
|
|
**Authentication:** Required
|
|
|
|
**Request Body:**
|
|
```json
|
|
{
|
|
"config_file": "/app/configs/example-site.yaml"
|
|
}
|
|
```
|
|
|
|
**Success Response (201 Created):**
|
|
```json
|
|
{
|
|
"scan_id": 42,
|
|
"status": "running",
|
|
"message": "Scan queued successfully"
|
|
}
|
|
```
|
|
|
|
**Error Responses:**
|
|
|
|
*400 Bad Request* - Invalid config file:
|
|
```json
|
|
{
|
|
"error": "Invalid config file",
|
|
"message": "Config file does not exist or is not valid YAML"
|
|
}
|
|
```
|
|
|
|
*500 Internal Server Error* - Scan queue failure:
|
|
```json
|
|
{
|
|
"error": "Failed to queue scan",
|
|
"message": "Internal server error"
|
|
}
|
|
```
|
|
|
|
**Usage Example:**
|
|
```bash
|
|
curl -X POST http://localhost:5000/api/scans \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"config_file":"/app/configs/production.yaml"}' \
|
|
-b cookies.txt
|
|
```
|
|
|
|
### List Scans
|
|
|
|
Retrieve a paginated list of scans with optional status filtering.
|
|
|
|
**Endpoint:** `GET /api/scans`
|
|
|
|
**Authentication:** Required
|
|
|
|
**Query Parameters:**
|
|
|
|
| Parameter | Type | Required | Default | Description |
|
|
|-----------|------|----------|---------|-------------|
|
|
| `page` | integer | No | 1 | Page number (1-indexed) |
|
|
| `per_page` | integer | No | 20 | Items per page (1-100) |
|
|
| `status` | string | No | - | Filter by status: `running`, `completed`, `failed` |
|
|
|
|
**Success Response (200 OK):**
|
|
```json
|
|
{
|
|
"scans": [
|
|
{
|
|
"id": 42,
|
|
"timestamp": "2025-11-14T10:30:00Z",
|
|
"duration": 125.5,
|
|
"status": "completed",
|
|
"title": "Production Network Scan",
|
|
"config_file": "/app/configs/production.yaml",
|
|
"triggered_by": "manual",
|
|
"started_at": "2025-11-14T10:30:00Z",
|
|
"completed_at": "2025-11-14T10:32:05Z"
|
|
},
|
|
{
|
|
"id": 41,
|
|
"timestamp": "2025-11-13T15:00:00Z",
|
|
"duration": 98.2,
|
|
"status": "completed",
|
|
"title": "Development Network Scan",
|
|
"config_file": "/app/configs/dev.yaml",
|
|
"triggered_by": "scheduled",
|
|
"started_at": "2025-11-13T15:00:00Z",
|
|
"completed_at": "2025-11-13T15:01:38Z"
|
|
}
|
|
],
|
|
"total": 42,
|
|
"page": 1,
|
|
"per_page": 20,
|
|
"pages": 3
|
|
}
|
|
```
|
|
|
|
**Error Responses:**
|
|
|
|
*400 Bad Request* - Invalid parameters:
|
|
```json
|
|
{
|
|
"error": "Invalid pagination parameters",
|
|
"message": "Page and per_page must be positive integers"
|
|
}
|
|
```
|
|
|
|
**Usage Examples:**
|
|
```bash
|
|
# List first page (default 20 items)
|
|
curl -X GET http://localhost:5000/api/scans \
|
|
-b cookies.txt
|
|
|
|
# List page 2 with 50 items per page
|
|
curl -X GET "http://localhost:5000/api/scans?page=2&per_page=50" \
|
|
-b cookies.txt
|
|
|
|
# List only running scans
|
|
curl -X GET "http://localhost:5000/api/scans?status=running" \
|
|
-b cookies.txt
|
|
```
|
|
|
|
### Get Scan Details
|
|
|
|
Retrieve complete details for a specific scan, including all sites, IPs, ports, services, certificates, and TLS versions.
|
|
|
|
**Endpoint:** `GET /api/scans/{id}`
|
|
|
|
**Authentication:** Required
|
|
|
|
**Path Parameters:**
|
|
|
|
| Parameter | Type | Required | Description |
|
|
|-----------|------|----------|-------------|
|
|
| `id` | integer | Yes | Scan ID |
|
|
|
|
**Success Response (200 OK):**
|
|
```json
|
|
{
|
|
"id": 42,
|
|
"timestamp": "2025-11-14T10:30:00Z",
|
|
"duration": 125.5,
|
|
"status": "completed",
|
|
"title": "Production Network Scan",
|
|
"config_file": "/app/configs/production.yaml",
|
|
"json_path": "/app/output/scan_report_20251114_103000.json",
|
|
"html_path": "/app/output/scan_report_20251114_103000.html",
|
|
"zip_path": "/app/output/scan_report_20251114_103000.zip",
|
|
"screenshot_dir": "/app/output/scan_report_20251114_103000_screenshots",
|
|
"triggered_by": "manual",
|
|
"started_at": "2025-11-14T10:30:00Z",
|
|
"completed_at": "2025-11-14T10:32:05Z",
|
|
"error_message": null,
|
|
"sites": [
|
|
{
|
|
"id": 101,
|
|
"site_name": "Production Web Servers",
|
|
"ips": [
|
|
{
|
|
"id": 201,
|
|
"ip_address": "192.168.1.10",
|
|
"ping_expected": true,
|
|
"ping_actual": true,
|
|
"ports": [
|
|
{
|
|
"id": 301,
|
|
"port": 443,
|
|
"protocol": "tcp",
|
|
"expected": true,
|
|
"state": "open",
|
|
"services": [
|
|
{
|
|
"id": 401,
|
|
"service_name": "https",
|
|
"product": "nginx",
|
|
"version": "1.24.0",
|
|
"extrainfo": null,
|
|
"ostype": "Linux",
|
|
"http_protocol": "https",
|
|
"screenshot_path": "scan_report_20251114_103000_screenshots/192_168_1_10_443.png",
|
|
"certificates": [
|
|
{
|
|
"id": 501,
|
|
"subject": "CN=example.com",
|
|
"issuer": "CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US",
|
|
"serial_number": "123456789012345678901234567890",
|
|
"not_valid_before": "2025-01-01T00:00:00+00:00",
|
|
"not_valid_after": "2025-04-01T23:59:59+00:00",
|
|
"days_until_expiry": 89,
|
|
"sans": "[\"example.com\", \"www.example.com\"]",
|
|
"is_self_signed": false,
|
|
"tls_versions": [
|
|
{
|
|
"id": 601,
|
|
"tls_version": "TLS 1.2",
|
|
"supported": true,
|
|
"cipher_suites": "[\"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384\", \"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256\"]"
|
|
},
|
|
{
|
|
"id": 602,
|
|
"tls_version": "TLS 1.3",
|
|
"supported": true,
|
|
"cipher_suites": "[\"TLS_AES_256_GCM_SHA384\", \"TLS_AES_128_GCM_SHA256\"]"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Error Responses:**
|
|
|
|
*404 Not Found* - Scan doesn't exist:
|
|
```json
|
|
{
|
|
"error": "Scan not found",
|
|
"message": "Scan with ID 42 does not exist"
|
|
}
|
|
```
|
|
|
|
**Usage Example:**
|
|
```bash
|
|
curl -X GET http://localhost:5000/api/scans/42 \
|
|
-b cookies.txt
|
|
```
|
|
|
|
### Get Scan Status
|
|
|
|
Poll the current status of a running scan. Use this endpoint to track scan progress.
|
|
|
|
**Endpoint:** `GET /api/scans/{id}/status`
|
|
|
|
**Authentication:** Required
|
|
|
|
**Path Parameters:**
|
|
|
|
| Parameter | Type | Required | Description |
|
|
|-----------|------|----------|-------------|
|
|
| `id` | integer | Yes | Scan ID |
|
|
|
|
**Success Response (200 OK):**
|
|
|
|
*Running scan:*
|
|
```json
|
|
{
|
|
"scan_id": 42,
|
|
"status": "running",
|
|
"started_at": "2025-11-14T10:30:00Z",
|
|
"completed_at": null,
|
|
"error_message": null
|
|
}
|
|
```
|
|
|
|
*Completed scan:*
|
|
```json
|
|
{
|
|
"scan_id": 42,
|
|
"status": "completed",
|
|
"started_at": "2025-11-14T10:30:00Z",
|
|
"completed_at": "2025-11-14T10:32:05Z",
|
|
"error_message": null
|
|
}
|
|
```
|
|
|
|
*Failed scan:*
|
|
```json
|
|
{
|
|
"scan_id": 42,
|
|
"status": "failed",
|
|
"started_at": "2025-11-14T10:30:00Z",
|
|
"completed_at": "2025-11-14T10:30:15Z",
|
|
"error_message": "Config file not found: /app/configs/missing.yaml"
|
|
}
|
|
```
|
|
|
|
**Error Responses:**
|
|
|
|
*404 Not Found* - Scan doesn't exist:
|
|
```json
|
|
{
|
|
"error": "Scan not found",
|
|
"message": "Scan with ID 42 does not exist"
|
|
}
|
|
```
|
|
|
|
**Usage Example:**
|
|
```bash
|
|
# Poll status every 5 seconds
|
|
while true; do
|
|
curl -X GET http://localhost:5000/api/scans/42/status -b cookies.txt
|
|
sleep 5
|
|
done
|
|
```
|
|
|
|
### Delete Scan
|
|
|
|
Delete a scan and all associated files (JSON, HTML, ZIP, screenshots).
|
|
|
|
**Endpoint:** `DELETE /api/scans/{id}`
|
|
|
|
**Authentication:** Required
|
|
|
|
**Path Parameters:**
|
|
|
|
| Parameter | Type | Required | Description |
|
|
|-----------|------|----------|-------------|
|
|
| `id` | integer | Yes | Scan ID |
|
|
|
|
**Success Response (200 OK):**
|
|
```json
|
|
{
|
|
"message": "Scan 42 deleted successfully"
|
|
}
|
|
```
|
|
|
|
**Error Responses:**
|
|
|
|
*404 Not Found* - Scan doesn't exist:
|
|
```json
|
|
{
|
|
"error": "Scan not found",
|
|
"message": "Scan with ID 42 does not exist"
|
|
}
|
|
```
|
|
|
|
**Usage Example:**
|
|
```bash
|
|
curl -X DELETE http://localhost:5000/api/scans/42 \
|
|
-b cookies.txt
|
|
```
|
|
|
|
---
|
|
|
|
## Settings API
|
|
|
|
Manage application settings including SMTP configuration, encryption keys, and preferences.
|
|
|
|
### Get All Settings
|
|
|
|
Retrieve all application settings. Sensitive values (passwords, keys) are masked.
|
|
|
|
**Endpoint:** `GET /api/settings`
|
|
|
|
**Authentication:** Required
|
|
|
|
**Success Response (200 OK):**
|
|
```json
|
|
{
|
|
"smtp_server": "smtp.gmail.com",
|
|
"smtp_port": 587,
|
|
"smtp_username": "alerts@example.com",
|
|
"smtp_password": "********",
|
|
"smtp_from_email": "alerts@example.com",
|
|
"smtp_to_emails": "[\"admin@example.com\"]",
|
|
"retention_days": 90,
|
|
"app_password": "********"
|
|
}
|
|
```
|
|
|
|
**Usage Example:**
|
|
```bash
|
|
curl -X GET http://localhost:5000/api/settings \
|
|
-b cookies.txt
|
|
```
|
|
|
|
### Update Setting
|
|
|
|
Update a specific setting value.
|
|
|
|
**Endpoint:** `PUT /api/settings/{key}`
|
|
|
|
**Authentication:** Required
|
|
|
|
**Path Parameters:**
|
|
|
|
| Parameter | Type | Required | Description |
|
|
|-----------|------|----------|-------------|
|
|
| `key` | string | Yes | Setting key (e.g., `smtp_server`) |
|
|
|
|
**Request Body:**
|
|
```json
|
|
{
|
|
"value": "smtp.example.com"
|
|
}
|
|
```
|
|
|
|
**Success Response (200 OK):**
|
|
```json
|
|
{
|
|
"message": "Setting updated successfully",
|
|
"key": "smtp_server",
|
|
"value": "smtp.example.com"
|
|
}
|
|
```
|
|
|
|
**Error Responses:**
|
|
|
|
*400 Bad Request* - Missing value:
|
|
```json
|
|
{
|
|
"error": "Missing required field: value"
|
|
}
|
|
```
|
|
|
|
**Usage Example:**
|
|
```bash
|
|
curl -X PUT http://localhost:5000/api/settings/smtp_server \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"value":"smtp.example.com"}' \
|
|
-b cookies.txt
|
|
```
|
|
|
|
### Health Check
|
|
|
|
Check if the API is running and database is accessible.
|
|
|
|
**Endpoint:** `GET /api/settings/health`
|
|
|
|
**Authentication:** Not required
|
|
|
|
**Success Response (200 OK):**
|
|
```json
|
|
{
|
|
"status": "healthy",
|
|
"database": "connected"
|
|
}
|
|
```
|
|
|
|
**Error Response (500 Internal Server Error):**
|
|
```json
|
|
{
|
|
"status": "unhealthy",
|
|
"database": "disconnected",
|
|
"error": "Connection error details"
|
|
}
|
|
```
|
|
|
|
**Usage Example:**
|
|
```bash
|
|
curl -X GET http://localhost:5000/api/settings/health
|
|
```
|
|
|
|
---
|
|
|
|
## Error Handling
|
|
|
|
### Error Response Format
|
|
|
|
All error responses follow a consistent JSON format:
|
|
|
|
```json
|
|
{
|
|
"error": "Brief error type",
|
|
"message": "Detailed error message for debugging"
|
|
}
|
|
```
|
|
|
|
### Content Negotiation
|
|
|
|
The API supports content negotiation based on the request:
|
|
|
|
- **API Requests** (Accept: application/json or /api/* path): Returns JSON errors
|
|
- **Web Requests** (Accept: text/html): Returns HTML error pages
|
|
|
|
**Example:**
|
|
```bash
|
|
# JSON error response
|
|
curl -X GET http://localhost:5000/api/scans/999 \
|
|
-H "Accept: application/json" \
|
|
-b cookies.txt
|
|
|
|
# HTML error page
|
|
curl -X GET http://localhost:5000/scans/999 \
|
|
-H "Accept: text/html" \
|
|
-b cookies.txt
|
|
```
|
|
|
|
### Request ID Tracking
|
|
|
|
Every request receives a unique request ID for tracking and debugging:
|
|
|
|
**Response Headers:**
|
|
```
|
|
X-Request-ID: a1b2c3d4
|
|
X-Request-Duration-Ms: 125
|
|
```
|
|
|
|
Check application logs for detailed error information using the request ID:
|
|
```
|
|
2025-11-14 10:30:15 INFO [a1b2c3d4] GET /api/scans 200 125ms
|
|
```
|
|
|
|
---
|
|
|
|
## Status Codes
|
|
|
|
### Success Codes
|
|
|
|
| Code | Meaning | Usage |
|
|
|------|---------|-------|
|
|
| 200 | OK | Successful GET, PUT, DELETE requests |
|
|
| 201 | Created | Successful POST request that creates a resource |
|
|
| 302 | Found | Redirect (used for logout, login success) |
|
|
|
|
### Client Error Codes
|
|
|
|
| Code | Meaning | Usage |
|
|
|------|---------|-------|
|
|
| 400 | Bad Request | Invalid request parameters or body |
|
|
| 401 | Unauthorized | Authentication required or failed |
|
|
| 403 | Forbidden | Authenticated but not authorized |
|
|
| 404 | Not Found | Resource doesn't exist |
|
|
| 405 | Method Not Allowed | HTTP method not supported for endpoint |
|
|
|
|
### Server Error Codes
|
|
|
|
| Code | Meaning | Usage |
|
|
|------|---------|-------|
|
|
| 500 | Internal Server Error | Unexpected server error |
|
|
|
|
---
|
|
|
|
## Request/Response Examples
|
|
|
|
### Complete Workflow: Trigger and Monitor Scan
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
|
|
# 1. Login and save session
|
|
curl -X POST http://localhost:5000/auth/login \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"password":"yourpassword"}' \
|
|
-c cookies.txt
|
|
|
|
# 2. Trigger a new scan
|
|
RESPONSE=$(curl -s -X POST http://localhost:5000/api/scans \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"config_file":"/app/configs/production.yaml"}' \
|
|
-b cookies.txt)
|
|
|
|
# Extract scan ID from response
|
|
SCAN_ID=$(echo $RESPONSE | jq -r '.scan_id')
|
|
echo "Scan ID: $SCAN_ID"
|
|
|
|
# 3. Poll status every 5 seconds until complete
|
|
while true; do
|
|
STATUS=$(curl -s -X GET http://localhost:5000/api/scans/$SCAN_ID/status \
|
|
-b cookies.txt | jq -r '.status')
|
|
|
|
echo "Status: $STATUS"
|
|
|
|
if [ "$STATUS" == "completed" ] || [ "$STATUS" == "failed" ]; then
|
|
break
|
|
fi
|
|
|
|
sleep 5
|
|
done
|
|
|
|
# 4. Get full scan results
|
|
curl -X GET http://localhost:5000/api/scans/$SCAN_ID \
|
|
-b cookies.txt | jq '.'
|
|
|
|
# 5. Logout
|
|
curl -X GET http://localhost:5000/auth/logout \
|
|
-b cookies.txt
|
|
```
|
|
|
|
### Pagination Example
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
|
|
# Get total number of scans
|
|
TOTAL=$(curl -s -X GET "http://localhost:5000/api/scans?per_page=1" \
|
|
-b cookies.txt | jq -r '.total')
|
|
|
|
echo "Total scans: $TOTAL"
|
|
|
|
# Calculate number of pages (50 items per page)
|
|
PER_PAGE=50
|
|
PAGES=$(( ($TOTAL + $PER_PAGE - 1) / $PER_PAGE ))
|
|
|
|
echo "Total pages: $PAGES"
|
|
|
|
# Fetch all pages
|
|
for PAGE in $(seq 1 $PAGES); do
|
|
echo "Fetching page $PAGE..."
|
|
curl -s -X GET "http://localhost:5000/api/scans?page=$PAGE&per_page=$PER_PAGE" \
|
|
-b cookies.txt | jq '.scans[] | {id, timestamp, title, status}'
|
|
done
|
|
```
|
|
|
|
### Filter by Status
|
|
|
|
```bash
|
|
# Get all running scans
|
|
curl -X GET "http://localhost:5000/api/scans?status=running" \
|
|
-b cookies.txt | jq '.scans[] | {id, title, started_at}'
|
|
|
|
# Get all failed scans
|
|
curl -X GET "http://localhost:5000/api/scans?status=failed" \
|
|
-b cookies.txt | jq '.scans[] | {id, title, error_message}'
|
|
|
|
# Get all completed scans from last 24 hours
|
|
curl -X GET "http://localhost:5000/api/scans?status=completed" \
|
|
-b cookies.txt | jq '.scans[] | select(.completed_at > (now - 86400 | todate)) | {id, title, duration}'
|
|
```
|
|
|
|
---
|
|
|
|
## Rate Limiting
|
|
|
|
Currently no rate limiting is implemented. For production deployments, consider:
|
|
|
|
- Adding nginx rate limiting
|
|
- Implementing application-level rate limiting with Flask-Limiter
|
|
- Setting connection limits in Gunicorn configuration
|
|
|
|
---
|
|
|
|
## Security Considerations
|
|
|
|
### Authentication
|
|
|
|
- All API endpoints (except `/auth/login` and `/api/settings/health`) require authentication
|
|
- Session cookies are httpOnly and secure (in production with HTTPS)
|
|
- Passwords are hashed with bcrypt (cost factor 12)
|
|
- Sensitive settings values are encrypted at rest
|
|
|
|
### CORS
|
|
|
|
CORS is configured via environment variable `CORS_ORIGINS`. Default: `*` (allow all).
|
|
|
|
For production, set to specific origins:
|
|
```bash
|
|
CORS_ORIGINS=https://scanner.example.com,https://admin.example.com
|
|
```
|
|
|
|
### HTTPS
|
|
|
|
For production deployments:
|
|
1. Use HTTPS (TLS/SSL) for all requests
|
|
2. Set `SESSION_COOKIE_SECURE=True` in Flask config
|
|
3. Consider using a reverse proxy (nginx) with SSL termination
|
|
|
|
### Input Validation
|
|
|
|
All inputs are validated:
|
|
- Config file paths are checked for existence and valid YAML
|
|
- Pagination parameters are sanitized (positive integers, max per_page: 100)
|
|
- Scan IDs are validated as integers
|
|
- Setting values are type-checked
|
|
|
|
---
|
|
|
|
## Versioning
|
|
|
|
**Current Version:** 2.0 (Phase 2)
|
|
|
|
API versioning will be implemented in Phase 5. For now, the API is considered unstable and may change between phases.
|
|
|
|
**Breaking Changes:**
|
|
- Phase 2 → Phase 3: Possible schema changes for scan comparison
|
|
- Phase 3 → Phase 4: Possible authentication changes (token auth)
|
|
|
|
---
|
|
|
|
## Support
|
|
|
|
For issues, questions, or feature requests:
|
|
- GitHub Issues: https://github.com/anthropics/sneakyscanner/issues
|
|
- Documentation: `/docs/ai/` directory in repository
|
|
|
|
---
|
|
|
|
**Last Updated:** 2025-11-14
|
|
**Phase:** 2 - Flask Web App Core
|
|
**Next Update:** Phase 3 - Dashboard & Scheduling
|