Testing, Security Hardening and Deployment
Testing with pytest
# tests/conftest.py
import pytest
from app import create_app
from app.extensions import db
@pytest.fixture
def app():
app = create_app("app.config.TestingConfig")
with app.app_context():
db.create_all()
yield app
db.drop_all()
@pytest.fixture
def client(app):
return app.test_client()
def test_home(client):
assert client.get("/").status_code == 200
def test_cannot_edit_someone_elses_project(client, make_user, make_project, login):
owner, other = make_user("a@x.com"), make_user("b@x.com")
project = make_project(owner=owner)
login(client, other)
assert client.post(f"/projects/{project.id}/edit", data={"title": "x"}).status_code == 404
Test: every page loads (a smoke test over all GET routes), permissions for each role, ownership, form validation and payment webhooks.
Security hardening checklist
- [ ]
SECRET_KEYlong, random and from the environment - [ ] CSRF on all forms; POST for every state change
- [ ] Rate limits on login, sign-up, contact and API endpoints (Redis storage when running several workers)
- [ ] Secure cookie flags:
Secure,HttpOnly,SameSite=Lax - [ ] Security headers: HSTS,
X-Content-Type-Options,Referrer-Policy, a Content Security Policy, frame protection - [ ] Ownership checks on every object; admin pages return 404 to non-staff
- [ ] Uploads validated and stored outside
static/ - [ ] Dependencies audited (
pip-audit) and updated regularly - [ ] Two-factor authentication for admin accounts
@app.after_request
def security_headers(resp):
resp.headers["X-Content-Type-Options"] = "nosniff"
resp.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
resp.headers["X-Frame-Options"] = "DENY"
resp.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains"
return resp
Deploying
# wsgi.py
from app import create_app
app = create_app("app.config.ProductionConfig")
Start command: gunicorn wsgi:app -c gunicorn.conf.py; build: install requirements and run flask db upgrade. See Web App Deployment and Deploy to Render for the full walk-through.
Final project
Build a "client portal" app: registration and login with rate limits; projects owned by users with tags; file uploads per project; an admin area (404 for non-admins) listing all users; Stripe Checkout for a paid plan with access granted by webhook; full pytest suite including permissions; deployed to a PaaS with PostgreSQL, HTTPS and monitoring. This is exactly the kind of app small businesses hire developers to build.
Check yourself
- What should a smoke test cover?
- Why do rate limits need Redis with several workers?
- Which config class does production use, and what does it change?
Ваш прогресс сохраняется только в этом браузере.
Отправить на проверку (10 баллов)