chore: import upstream snapshot with attribution
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,346 @@
|
||||
"""
|
||||
API Security Tests
|
||||
|
||||
Tests that verify API endpoints follow security best practices,
|
||||
based on OWASP API Security Top 10.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from tests.test_utils import add_src_to_path
|
||||
|
||||
add_src_to_path()
|
||||
|
||||
|
||||
class TestAPISecurityOWASPTop10:
|
||||
"""Test API security based on OWASP API Security Top 10 2023."""
|
||||
|
||||
@pytest.fixture
|
||||
def client(self):
|
||||
"""Create a test client."""
|
||||
from local_deep_research.web.app import create_app
|
||||
|
||||
app, _ = create_app() # Unpack tuple (app, socket_service)
|
||||
app.config["TESTING"] = True
|
||||
app.config["WTF_CSRF_ENABLED"] = False
|
||||
# Enable CORS for testing (tests expect open CORS)
|
||||
app.config["SECURITY_CORS_ALLOWED_ORIGINS"] = "*"
|
||||
return app.test_client()
|
||||
|
||||
# API1:2023 - Broken Object Level Authorization (BOLA)
|
||||
@pytest.mark.skip(reason="documentation/placeholder test - not implemented")
|
||||
def test_api1_broken_object_level_authorization(self, client):
|
||||
"""
|
||||
Test that users can only access their own objects.
|
||||
|
||||
BOLA/IDOR (Insecure Direct Object Reference):
|
||||
- User A tries to access User B's research by changing research_id
|
||||
- API should verify that user owns the requested object
|
||||
"""
|
||||
# Example vulnerable endpoint:
|
||||
# GET /api/v1/quick_summary/{research_id}
|
||||
# Without checking if current user owns research_id
|
||||
|
||||
# Test accessing research with different IDs
|
||||
# Should return 403 Forbidden if not owned by user
|
||||
# Should return 404 Not Found to avoid info leakage
|
||||
|
||||
# For LDR with per-user databases, this is mitigated by architecture
|
||||
assert True # Architecture-level protection
|
||||
|
||||
# API2:2023 - Broken Authentication
|
||||
def test_api2_broken_authentication(self, client):
|
||||
"""
|
||||
Test that API authentication is secure.
|
||||
|
||||
Common issues:
|
||||
- Weak password requirements
|
||||
- Credential stuffing
|
||||
- Missing rate limiting
|
||||
- Weak token generation
|
||||
"""
|
||||
# Test that protected API endpoints require authentication
|
||||
protected_endpoints = [
|
||||
"/api/v1/quick_summary",
|
||||
"/api/v1/settings",
|
||||
]
|
||||
|
||||
for endpoint in protected_endpoints:
|
||||
# Try accessing without authentication
|
||||
response = client.get(endpoint)
|
||||
# Should be one of the auth-block codes:
|
||||
# 401 Unauthorized, 403 Forbidden, 404 Not Found (route hidden),
|
||||
# 405 Method Not Allowed (endpoint only accepts POST).
|
||||
# MUST NOT be 200 — that would mean the endpoint is reachable
|
||||
# without authentication, which is what this OWASP API2 test
|
||||
# exists to catch.
|
||||
assert response.status_code in {401, 403, 404, 405}, (
|
||||
f"{endpoint} returned {response.status_code} without auth"
|
||||
)
|
||||
|
||||
# API4:2023 - Unrestricted Resource Consumption
|
||||
def test_api4_unrestricted_resource_consumption(self, client):
|
||||
"""
|
||||
Test protection against resource exhaustion attacks.
|
||||
|
||||
Attack vectors:
|
||||
- Extremely large requests
|
||||
- Too many simultaneous requests
|
||||
- Expensive operations without limits
|
||||
"""
|
||||
# Test large payload
|
||||
large_query = "test query " * 100000 # Very large query
|
||||
response = client.post(
|
||||
"/api/v1/quick_summary",
|
||||
json={"query": large_query},
|
||||
content_type="application/json",
|
||||
)
|
||||
|
||||
# Should have request size limit (413 Payload Too Large)
|
||||
# Or validate query length (400/422)
|
||||
# Current implementation may return 500 for edge cases
|
||||
assert response.status_code == 401, response.status_code
|
||||
|
||||
# Test rate limiting (if implemented)
|
||||
# Make many requests rapidly
|
||||
for i in range(100):
|
||||
response = client.get("/api/v1/health")
|
||||
# Should eventually rate limit (429 Too Many Requests)
|
||||
|
||||
# Rate limiting may not be enabled in development
|
||||
pass
|
||||
|
||||
# API5:2023 - Broken Function Level Authorization
|
||||
def test_api5_broken_function_level_authorization(self, client):
|
||||
"""
|
||||
Test that administrative functions require admin privileges.
|
||||
|
||||
Common issues:
|
||||
- Admin endpoints accessible to regular users
|
||||
- Missing authorization checks on sensitive functions
|
||||
"""
|
||||
# Admin functions that should require elevated privileges:
|
||||
admin_endpoints = [
|
||||
"/api/v1/admin/users",
|
||||
"/api/v1/admin/settings",
|
||||
"/api/v1/admin/logs",
|
||||
]
|
||||
|
||||
for endpoint in admin_endpoints:
|
||||
response = client.get(endpoint)
|
||||
# Should return 401 Unauthorized, 403 Forbidden, or 404 Not Found
|
||||
assert response.status_code == 404, response.status_code
|
||||
|
||||
# API6:2023 - Unrestricted Access to Sensitive Business Flows
|
||||
@pytest.mark.skip(reason="documentation/placeholder test - not implemented")
|
||||
def test_api6_unrestricted_sensitive_flows(self, client):
|
||||
"""
|
||||
Test protection of sensitive business logic flows.
|
||||
|
||||
Examples:
|
||||
- Account deletion without verification
|
||||
- Mass data export without limits
|
||||
- Automated scraping/abuse
|
||||
"""
|
||||
# For LDR, sensitive flows might include:
|
||||
# - Deleting all research history
|
||||
# - Exporting all data
|
||||
# - Automated research generation (resource intensive)
|
||||
|
||||
# These should have:
|
||||
# - Confirmation required
|
||||
# - Rate limiting
|
||||
# - CAPTCHA for automated abuse prevention
|
||||
|
||||
pass # Implementation-specific
|
||||
|
||||
# API8:2023 - Security Misconfiguration
|
||||
def test_api8_security_misconfiguration(self, client):
|
||||
"""
|
||||
Test for common security misconfigurations.
|
||||
|
||||
Common issues:
|
||||
- Debug mode enabled in production
|
||||
- Verbose error messages
|
||||
- Missing security headers
|
||||
- Default credentials
|
||||
"""
|
||||
# Test that debug mode is off
|
||||
response = client.get("/api/v1/health")
|
||||
data = response.get_json()
|
||||
|
||||
# Should not expose debug information
|
||||
assert "debug" not in str(data).lower() or not data.get("debug")
|
||||
|
||||
# Test error responses don't leak sensitive info
|
||||
response = client.get("/api/v1/nonexistent")
|
||||
# Should return generic error, not stack trace
|
||||
# 401 is also acceptable (auth guard rejects before routing)
|
||||
assert response.status_code == 404, response.status_code
|
||||
|
||||
# API9:2023 - Improper Inventory Management
|
||||
@pytest.mark.skip(reason="documentation/placeholder test - not implemented")
|
||||
def test_api9_improper_inventory_management(self):
|
||||
"""
|
||||
Test API documentation and version management.
|
||||
|
||||
Issues:
|
||||
- Undocumented API endpoints
|
||||
- Old API versions still accessible
|
||||
- Deprecated endpoints without sunset dates
|
||||
- Shadow APIs (forgotten endpoints)
|
||||
"""
|
||||
# This is primarily a documentation/process issue
|
||||
# Verify:
|
||||
# - API endpoints are documented
|
||||
# - Old versions are deprecated properly
|
||||
# - API versioning is clear (/api/v1/, /api/v2/)
|
||||
|
||||
assert True # Documentation/process test
|
||||
|
||||
# API10:2023 - Unsafe Consumption of APIs
|
||||
@pytest.mark.skip(reason="documentation/placeholder test - not implemented")
|
||||
def test_api10_unsafe_consumption_of_apis(self, client):
|
||||
"""
|
||||
Test secure consumption of external APIs.
|
||||
|
||||
LDR consumes external APIs:
|
||||
- Search engines
|
||||
- Wikipedia
|
||||
- Web scraping targets
|
||||
|
||||
Risks:
|
||||
- Malicious responses from external APIs
|
||||
- Injection attacks via external data
|
||||
- Excessive trust in external data
|
||||
"""
|
||||
# External API responses should be:
|
||||
# - Validated (schema/type checking)
|
||||
# - Sanitized (remove dangerous content)
|
||||
# - Size-limited (prevent memory exhaustion)
|
||||
# - Timeout-protected (prevent hanging)
|
||||
|
||||
assert True # Implementation-specific
|
||||
|
||||
|
||||
class TestAPIInputValidation:
|
||||
"""Test API input validation."""
|
||||
|
||||
@pytest.fixture
|
||||
def client(self):
|
||||
"""Create a test client."""
|
||||
from local_deep_research.web.app import create_app
|
||||
|
||||
app, _ = create_app() # Unpack tuple (app, socket_service)
|
||||
app.config["TESTING"] = True
|
||||
app.config["WTF_CSRF_ENABLED"] = False
|
||||
# Enable CORS for testing (tests expect open CORS)
|
||||
app.config["SECURITY_CORS_ALLOWED_ORIGINS"] = "*"
|
||||
return app.test_client()
|
||||
|
||||
def test_json_parsing_errors_handled(self, client):
|
||||
"""Test that malformed JSON is rejected gracefully."""
|
||||
# Send invalid JSON
|
||||
response = client.post(
|
||||
"/api/v1/quick_summary",
|
||||
data="{ invalid json }",
|
||||
content_type="application/json",
|
||||
)
|
||||
|
||||
# Should return 400 Bad Request (or 401 if auth guard rejects first)
|
||||
assert response.status_code == 401, response.status_code
|
||||
|
||||
def test_missing_required_fields_rejected(self, client):
|
||||
"""Test that requests with missing required fields are rejected."""
|
||||
# Send request without required field
|
||||
response = client.post(
|
||||
"/api/v1/quick_summary",
|
||||
json={}, # Missing 'query' field
|
||||
content_type="application/json",
|
||||
)
|
||||
|
||||
# Should return 400 Bad Request or 422 Unprocessable Entity
|
||||
# 401 is also valid (auth guard rejects unauthenticated requests)
|
||||
assert response.status_code == 401, response.status_code
|
||||
|
||||
def test_invalid_data_types_rejected(self, client):
|
||||
"""Test that invalid data types are rejected."""
|
||||
# Send wrong data type
|
||||
response = client.post(
|
||||
"/api/v1/quick_summary",
|
||||
json={"query": 12345}, # Should be string, not number
|
||||
content_type="application/json",
|
||||
)
|
||||
|
||||
# Should validate data types and reject non-string query
|
||||
# 401 is also valid (auth guard rejects unauthenticated requests)
|
||||
assert response.status_code == 401, response.status_code
|
||||
|
||||
def test_boundary_value_validation(self, client):
|
||||
"""Test validation of boundary values."""
|
||||
boundary_tests = [
|
||||
{"query": ""}, # Empty string
|
||||
{"query": "a" * 10000}, # Very long string
|
||||
{"query": None}, # Null value
|
||||
]
|
||||
|
||||
for test_data in boundary_tests:
|
||||
response = client.post(
|
||||
"/api/v1/quick_summary",
|
||||
json=test_data,
|
||||
content_type="application/json",
|
||||
)
|
||||
|
||||
# Should validate and reject invalid inputs (400/422)
|
||||
# 401 is also valid (auth guard rejects unauthenticated requests)
|
||||
assert response.status_code == 401, response.status_code
|
||||
|
||||
|
||||
class TestAPIRateLimiting:
|
||||
"""Test API rate limiting (if implemented)."""
|
||||
|
||||
@pytest.fixture
|
||||
def client(self):
|
||||
"""Create a test client."""
|
||||
from local_deep_research.web.app import create_app
|
||||
|
||||
app, _ = create_app() # Unpack tuple (app, socket_service)
|
||||
app.config["TESTING"] = True
|
||||
# Enable CORS for testing (tests expect open CORS)
|
||||
app.config["SECURITY_CORS_ALLOWED_ORIGINS"] = "*"
|
||||
return app.test_client()
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="documentation/placeholder test - not implemented")
|
||||
def test_api_security_documentation():
|
||||
"""
|
||||
Documentation test for API security best practices.
|
||||
|
||||
OWASP API Security Top 10 2023:
|
||||
1. Broken Object Level Authorization (BOLA)
|
||||
2. Broken Authentication
|
||||
3. Broken Object Property Level Authorization
|
||||
4. Unrestricted Resource Consumption
|
||||
5. Broken Function Level Authorization
|
||||
6. Unrestricted Access to Sensitive Business Flows
|
||||
7. Server Side Request Forgery (SSRF)
|
||||
8. Security Misconfiguration
|
||||
9. Improper Inventory Management
|
||||
10. Unsafe Consumption of APIs
|
||||
|
||||
LDR-Specific API Security Considerations:
|
||||
- Research API endpoints handle user queries
|
||||
- External data fetching (SSRF risk)
|
||||
- Resource-intensive operations (DoS risk)
|
||||
- Per-user database isolation (BOLA mitigation)
|
||||
|
||||
Recommended Security Controls:
|
||||
- Input validation on all API endpoints
|
||||
- Rate limiting on expensive operations
|
||||
- URL whitelist for external fetching
|
||||
- Request size limits
|
||||
- Proper error handling (no info leakage)
|
||||
- API versioning and documentation
|
||||
- Authentication on protected endpoints
|
||||
- Authorization checks on object access
|
||||
"""
|
||||
assert True # Documentation test
|
||||
Reference in New Issue
Block a user