93 lines
3.1 KiB
Python
93 lines
3.1 KiB
Python
import os
|
|
import sys
|
|
import json
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
# Add project root to sys.path
|
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")))
|
|
|
|
from app.main import app
|
|
|
|
client = TestClient(app)
|
|
VALID_KEY = "skyheal_secure_api_key_2026"
|
|
|
|
|
|
def test_reject_unauthenticated_request():
|
|
"""1. Reject Unauthenticated Request (401)"""
|
|
res = client.post("/v1/onboarding/start", json={"patient": {"id": "P1"}})
|
|
assert res.status_code == 401
|
|
|
|
|
|
def test_authenticated_session_creation():
|
|
"""2. Authenticated Session Creation (200)"""
|
|
res = client.post(
|
|
"/v1/onboarding/start",
|
|
json={
|
|
"patient": {"id": "PAT-PROD-01", "name": "Prod Patient", "age": 32, "gender": "female"},
|
|
"category": {"type": "general", "code": "general_medicine", "name": "General Medicine"}
|
|
},
|
|
headers={"Authorization": "Bearer test_token_PAT-PROD-01"}
|
|
)
|
|
assert res.status_code == 200
|
|
data = res.json()
|
|
assert data.get("session_id") is not None
|
|
|
|
|
|
def test_idor_prevention_cross_session_access():
|
|
"""3. IDOR Prevention Cross-Session Access (403)"""
|
|
# Create session as PAT-PROD-01
|
|
start_res = client.post(
|
|
"/v1/onboarding/start",
|
|
json={
|
|
"patient": {"id": "PAT-PROD-01", "name": "Prod Patient", "age": 32, "gender": "female"},
|
|
"category": {"type": "general", "code": "general_medicine", "name": "General Medicine"}
|
|
},
|
|
headers={"Authorization": "Bearer test_token_PAT-PROD-01"}
|
|
)
|
|
s_id = start_res.json().get("session_id")
|
|
assert s_id is not None
|
|
|
|
# Attempt access as PAT-PROD-02
|
|
msg_res = client.post(
|
|
f"/v1/onboarding/{s_id}/message",
|
|
json={"message": "Unauthorized message"},
|
|
headers={"Authorization": "Bearer test_token_PAT-PROD-02"}
|
|
)
|
|
assert msg_res.status_code == 403
|
|
|
|
|
|
def test_security_headers_and_request_id():
|
|
"""4. Security Headers & X-Request-ID Correlation"""
|
|
res = client.get("/health")
|
|
assert res.status_code == 200
|
|
assert "X-Request-ID" in res.headers
|
|
assert res.headers.get("X-Content-Type-Options") == "nosniff"
|
|
assert res.headers.get("X-Frame-Options") == "DENY"
|
|
|
|
|
|
def test_schema_validation_negative_age_rejection():
|
|
"""5. Schema Validation Negative Age Rejection (422)"""
|
|
res = client.post(
|
|
"/v1/onboarding/start",
|
|
json={
|
|
"patient": {"id": "PAT-NEG", "name": "Invalid Age", "age": -10, "gender": "female"},
|
|
"category": {"type": "general", "code": "general_medicine", "name": "General Medicine"}
|
|
},
|
|
headers={"Authorization": f"Bearer {VALID_KEY}"}
|
|
)
|
|
assert res.status_code == 422
|
|
|
|
|
|
def run_automated_production_tests():
|
|
test_reject_unauthenticated_request()
|
|
test_authenticated_session_creation()
|
|
test_idor_prevention_cross_session_access()
|
|
test_security_headers_and_request_id()
|
|
test_schema_validation_negative_age_rejection()
|
|
print("ALL PRODUCTION SECURITY TESTS PASSED SUCCESSFULLY!")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
run_automated_production_tests()
|