87 lines
2.7 KiB
Python
87 lines
2.7 KiB
Python
from app import create_app
|
|
|
|
|
|
def test_dynamic_responses_have_security_headers(client):
|
|
response = client.get("/")
|
|
|
|
assert response.headers["Cache-Control"] == "no-store"
|
|
assert response.headers["X-Content-Type-Options"] == "nosniff"
|
|
assert response.headers["X-Frame-Options"] == "DENY"
|
|
assert response.headers["Referrer-Policy"] == "strict-origin-when-cross-origin"
|
|
policy = response.headers["Content-Security-Policy"]
|
|
assert "default-src 'self'" in policy
|
|
assert "frame-ancestors 'none'" in policy
|
|
assert "'unsafe-inline'" not in policy
|
|
|
|
|
|
def test_static_assets_have_bounded_public_cache(client):
|
|
response = client.get("/static/css/style.css")
|
|
|
|
assert response.status_code == 200
|
|
assert response.headers["Cache-Control"] == "public, max-age=3600"
|
|
|
|
|
|
def test_production_hsts_is_https_only():
|
|
app = create_app(
|
|
"production",
|
|
{
|
|
"SECRET_KEY": "production-test-only",
|
|
"SQLALCHEMY_DATABASE_URI": "sqlite:///:memory:",
|
|
},
|
|
)
|
|
client = app.test_client()
|
|
|
|
secure = client.get("/", base_url="https://steady.example")
|
|
insecure = client.get("/", base_url="http://steady.example")
|
|
|
|
assert "Strict-Transport-Security" in secure.headers
|
|
assert "Strict-Transport-Security" not in insecure.headers
|
|
|
|
|
|
def test_trusted_proxy_marks_forwarded_request_secure():
|
|
app = create_app(
|
|
"production",
|
|
{
|
|
"SECRET_KEY": "production-test-only",
|
|
"SQLALCHEMY_DATABASE_URI": "sqlite:///:memory:",
|
|
"TRUST_PROXY_HEADERS": True,
|
|
},
|
|
)
|
|
client = app.test_client()
|
|
|
|
response = client.get(
|
|
"/health",
|
|
headers={"X-Forwarded-Proto": "https", "X-Forwarded-Host": "steady.example"},
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
assert "Strict-Transport-Security" in response.headers
|
|
|
|
|
|
def test_trusted_hosts_reject_unknown_host():
|
|
app = create_app(
|
|
"testing",
|
|
{"TRUSTED_HOSTS": ["steady.example"]},
|
|
)
|
|
client = app.test_client()
|
|
|
|
assert client.get("/", base_url="http://steady.example").status_code == 200
|
|
assert client.get("/", base_url="http://attacker.example").status_code == 400
|
|
|
|
|
|
def test_friendly_not_found_and_upload_limit(client, app):
|
|
missing = client.get("/missing-page")
|
|
assert missing.status_code == 404
|
|
assert b"That page is not here" in missing.data
|
|
|
|
original_limit = app.config["MAX_CONTENT_LENGTH"]
|
|
app.config["MAX_CONTENT_LENGTH"] = 32
|
|
try:
|
|
too_large = client.post(
|
|
"/auth/register",
|
|
data={"username": "x" * 100},
|
|
)
|
|
finally:
|
|
app.config["MAX_CONTENT_LENGTH"] = original_limit
|
|
assert too_large.status_code == 413
|
|
assert b"That file is too large" in too_large.data
|