Skip to content

Commit

Permalink
feat: implement HTTP security response headers using Talisman
Browse files Browse the repository at this point in the history
  • Loading branch information
xenophonf committed Dec 13, 2023
1 parent f6a08f0 commit b4d4d01
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 6 deletions.
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ classifiers = [
]
dependencies = [
"flask",
"flask-talisman",
"flask-wtf",
"gunicorn",
"lethbridge",
Expand Down Expand Up @@ -54,6 +55,7 @@ test = [
"pytest",
"pytest-cov",
"pytest-emoji",
"pytest-flask",
"pytest-md",
"pytest-order",
"pytest-reportlog",
Expand Down
9 changes: 8 additions & 1 deletion src/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@
import pkgutil

from flask import Blueprint, Flask
from flask_talisman import Talisman

from . import __app_name__, __path__

# configure module-level logging
logger = logging.getLogger(__name__)

# create Flask extension objects
talisman = Talisman()

def create_app(test_config=None):

def create_app(test_config=None) -> Flask:
# create and configure the web app
app = Flask(__app_name__, instance_relative_config=True)
app.config.from_mapping(SECRET_KEY="dev")
Expand All @@ -36,6 +40,9 @@ def create_app(test_config=None):
else:
app.config.from_pyfile("config.py", silent=True)

# load extensions
talisman.init_app(app)

# load blueprints from submodules
[
(lambda bp: app.register_blueprint(bp) if isinstance(bp, Blueprint) else None)(
Expand Down
27 changes: 27 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# stuart, web front end for Elite: Dangerous game data collated by lethbridge
# Copyright (C) 2023 Matthew X. Economou
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License along with this program. If not, see
# <https://www.gnu.org/licenses/>.

from flask import Flask
from pytest import fixture

from stuart.app import create_app


@fixture
def app() -> Flask:
app = create_app()
return app
41 changes: 36 additions & 5 deletions tests/test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,41 @@
# License along with this program. If not, see
# <https://www.gnu.org/licenses/>.

from stuart.app import create_app
from pytest import mark


def test_app():
with create_app().test_client() as test_client:
response = test_client.get("/")
assert response.status_code == 200
@mark.order("first")
@mark.smoke
def test_app(client):
response = client.get("/")
assert 200 <= response.status_code < 400


@mark.order("first")
@mark.smoke
def test_https_redirect(client):
response = client.get(
"/",
environ_overrides={"wsgi.url_scheme": "http"},
)
assert response.status_code == 302
assert response.location.startswith("https://")


@mark.order("first")
@mark.smoke
def test_security_headers(client):
response = client.get(
"/",
environ_overrides={"wsgi.url_scheme": "https"},
)
assert response.status_code == 200
for security_header in [
"X-Content-Type-Options",
"Content-Security-Policy",
"Referrer-Policy",
"Permissions-Policy",
"Strict-Transport-Security",
"X-Frame-Options",
]:
assert security_header in response.headers

0 comments on commit b4d4d01

Please sign in to comment.