diff --git a/securedrop/journalist_app/__init__.py b/securedrop/journalist_app/__init__.py
index 23e8fcf3ec..e476346b0e 100644
--- a/securedrop/journalist_app/__init__.py
+++ b/securedrop/journalist_app/__init__.py
@@ -3,6 +3,7 @@
from typing import Any, Optional, Tuple, Union
import i18n
+import server_os
import template_filters
import version
from db import db
@@ -54,6 +55,11 @@ def create_app(config: SecureDropConfig) -> Flask:
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["SQLALCHEMY_DATABASE_URI"] = config.DATABASE_URI
+
+ # Check if the server OS is past EOL; if so, we'll display banners
+ app.config["OS_PAST_EOL"] = server_os.is_os_past_eol()
+ app.config["OS_NEEDS_MIGRATION_FIXES"] = server_os.needs_migration_fixes()
+
db.init_app(app)
class JSONEncoder(json.JSONEncoder):
@@ -109,6 +115,8 @@ def setup_g() -> Optional[Response]:
"""Store commonly used values in Flask's special g object"""
i18n.set_locale(config)
+ g.show_os_past_eol_warning = app.config["OS_PAST_EOL"]
+ g.show_os_needs_migration_fixes = app.config["OS_NEEDS_MIGRATION_FIXES"]
if InstanceConfig.get_default().organization_name:
g.organization_name = ( # pylint: disable=assigning-non-slot
diff --git a/securedrop/journalist_templates/base.html b/securedrop/journalist_templates/base.html
index ef8e7834b0..38bb034c2e 100644
--- a/securedrop/journalist_templates/base.html
+++ b/securedrop/journalist_templates/base.html
@@ -18,6 +18,15 @@
{% if session.logged_in() %}
+ {% if g.show_os_past_eol_warning %}
+
+ {{ gettext('Critical: The operating system used by your SecureDrop servers has reached its end-of-life. A manual update is required to re-enable the Source Interface and remain safe. Please contact your administrator. Learn More') }}
+
+ {% elif g.show_os_needs_migration_fixes %}
+
+ {{ gettext('Important: Your SecureDrop server needs manual attention to resolve issues blocking automatic upgrade to the next operating system. Please contact your adminstrator. Learn More') }}
+