Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ python-dotenv==0.20.0
# Runtime dependencies
gunicorn==20.1.0
honcho==1.1.0
flask-talisman==0.7.0
flask-cors==5.0.1

# Code quality
pylint==2.14.0
Expand Down
5 changes: 5 additions & 0 deletions service/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@
from flask import Flask
from service import config
from service.common import log_handlers
from flask_talisman import Talisman
from flask_cors import CORS

# Create Flask application
app = Flask(__name__)
app.config.from_object(config)

talisman = Talisman(app)
CORS(app)

# Import the routes After the Flask app is created
# pylint: disable=wrong-import-position, cyclic-import, wrong-import-order
from service import routes, models # noqa: F401 E402
Expand Down
25 changes: 24 additions & 1 deletion tests/test_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
from service.common import status # HTTP Status Codes
from service.models import db, Account, init_db
from service.routes import app
from service import talisman

DATABASE_URI = os.getenv(
"DATABASE_URI", "postgresql://postgres:postgres@localhost:5432/postgres"
)

BASE_URL = "/accounts"
HTTPS_ENVIRON = {'wsgi.url_scheme': 'https'}


######################################################################
Expand All @@ -34,6 +36,7 @@ def setUpClass(cls):
app.config["SQLALCHEMY_DATABASE_URI"] = DATABASE_URI
app.logger.setLevel(logging.CRITICAL)
init_db(app)
talisman.force_https = False

@classmethod
def tearDownClass(cls):
Expand Down Expand Up @@ -172,4 +175,24 @@ def test_delete_account(self):
def test_method_not_allowed(self):
"""It should not allow an illegal method call"""
resp = self.client.delete(BASE_URL)
self.assertEqual(resp.status_code, status.HTTP_405_METHOD_NOT_ALLOWED)
self.assertEqual(resp.status_code, status.HTTP_405_METHOD_NOT_ALLOWED)

def test_security_headers(self):
"""It should return security headers"""
response = self.client.get('/', environ_overrides=HTTPS_ENVIRON)
self.assertEqual(response.status_code, status.HTTP_200_OK)
headers = {
'X-Frame-Options': 'SAMEORIGIN',
'X-Content-Type-Options': 'nosniff',
'Content-Security-Policy': 'default-src \'self\'',
'Referrer-Policy': 'strict-origin-when-cross-origin'
}
for key, value in headers.items():
self.assertEqual(response.headers.get(key), value)

def test_cors_security(self):
"""It should return a CORS header"""
response = self.client.get('/', environ_overrides=HTTPS_ENVIRON)
self.assertEqual(response.status_code, status.HTTP_200_OK)
# Check for the CORS header
self.assertEqual(response.headers.get('Access-Control-Allow-Origin'), '*')