Merge branch 'main' of https://github.com/GSA/notifications-admin into 2135-send-message-flow-h1-changes

This commit is contained in:
Jonathan Bobel
2024-12-02 10:00:07 -05:00
12 changed files with 122 additions and 60 deletions

View File

@@ -161,7 +161,7 @@
"filename": "app/config.py",
"hashed_secret": "577a4c667e4af8682ca431857214b3a920883efc",
"is_verified": false,
"line_number": 125,
"line_number": 123,
"is_secret": false
}
],
@@ -684,5 +684,5 @@
}
]
},
"generated_at": "2024-11-14T15:53:44Z"
"generated_at": "2024-11-21T23:08:45Z"
}

View File

@@ -91,9 +91,7 @@ class Config(object):
getenv("FEATURE_BEST_PRACTICES_ENABLED", "false") == "true"
)
FEATURE_ABOUT_PAGE_ENABLED = (
getenv("FEATURE_ABOUT_PAGE_ENABLED", "false") == "true"
)
FEATURE_ABOUT_PAGE_ENABLED = getenv("FEATURE_ABOUT_PAGE_ENABLED", "false") == "true"
def _s3_credentials_from_env(bucket_prefix):

View File

@@ -30,15 +30,13 @@ from notifications_utils.url_safe_token import generate_token
# Hook to check for feature flags
@main.before_request
def check_feature_flags():
if (
request.path.startswith("/guides/best-practices")
and not current_app.config.get("FEATURE_BEST_PRACTICES_ENABLED", False)
if request.path.startswith("/guides/best-practices") and not current_app.config.get(
"FEATURE_BEST_PRACTICES_ENABLED", False
):
abort(404)
if (
request.path.startswith("/about")
and not current_app.config.get("FEATURE_ABOUT_PAGE_ENABLED", False)
if request.path.startswith("/about") and not current_app.config.get(
"FEATURE_ABOUT_PAGE_ENABLED", False
):
abort(404)
@@ -294,7 +292,6 @@ def benchmark_performance():
)
@main.route("/using-notify/guidance")
@main.route("/guides/using-notify/guidance")
@user_is_logged_in
def guidance_index():
@@ -315,6 +312,14 @@ def about_notify():
)
@main.route("/about/security")
def about_security():
return render_template(
"views/about/security.html",
navigation_links=about_notify_nav(),
)
@main.route("/about/why-text-messaging")
def why_text_messaging():
return render_template(

View File

@@ -1,3 +1,6 @@
from flask import current_app
def features_nav():
return [
{
@@ -22,46 +25,20 @@ def features_nav():
def using_notify_nav():
return [
{
"name": "Get started",
"link": "main.get_started",
},
{
"name": "Guides",
"link": "main.best_practices",
},
{
"name": "Trial mode",
"link": "main.trial_mode_new",
},
{
"name": "Tracking usage",
"link": "main.pricing",
},
{
"name": "Delivery status",
"link": "main.message_status",
},
{
"name": "Guidance",
"link": "main.guidance_index",
# "sub_navigation_items": [
# {
# "name": "Formatting",
# "link": "main.edit_and_format_messages",
# },
# {
# "name": "Send files by email",
# "link": "main.send_files_by_email",
# },
# ]
# {
# "name": "API documentation",
# "link": "main.documentation",
# },
},
nav_items = [
{"name": "Get started", "link": "main.get_started"},
{"name": "Guides", "link": "main.best_practices"},
{"name": "Trial mode", "link": "main.trial_mode_new"},
{"name": "Tracking usage", "link": "main.pricing"},
{"name": "Delivery Status", "link": "main.message_status"},
{"name": "Guidance", "link": "main.guidance_index"},
]
if not current_app.config.get("FEATURE_BEST_PRACTICES_ENABLED"):
nav_items = [
item for item in nav_items if item["link"] != "main.best_practices"
]
return nav_items
def best_practices_nav():
@@ -131,6 +108,10 @@ def about_notify_nav():
},
],
},
{
"name": "Security",
"link": "main.about_security",
},
],
},
]

View File

@@ -53,7 +53,7 @@ class HeaderNavigation(Navigation):
"establish_trust",
"write_for_action",
"multiple_languages",
"benchmark_performance"
"benchmark_performance",
},
"using_notify": {
"get_started",

View File

@@ -0,0 +1,66 @@
{% extends "base.html" %}
{% set page_title = "Security" %}
{% block per_page_title %}
{{page_title}}
{% endblock %}
{% block content_column_content %}
<!-- {% with title=page_title %}{% include "components/best-practices/nav_breadcrumb.html" %}{% endwith %} -->
<section class="usa-prose">
<h1>{{page_title}}</h1>
<p class="font-sans-lg text-base">Notify.gov is built for the needs of government agencies with fundamental system
security processes in place to:
</p>
<ul>
<li>protect user data</li>
<li>keep systems secure</li>
<li>manage risks around information</li>
</ul>
<p>
Notify.gov operates under a full three-year <a class="use-link usa-link--external"
href="https://digital.gov/resources/an-introduction-to-ato/" target="_blank">Authority-to-Operate (ATO)</a>. This
federal security authorization process leverages security
controls provided by National Institute of Standards and Technology (NIST).
</p>
<p>
Our infrastructure runs on <a class="use-link usa-link--external" href="https://www.cloud.gov/"
target="_blank">cloud.gov</a> and utilizes several
services through Amazon Web
Services (AWS), including <a class="use-link usa-link--external" href="https://aws.amazon.com/sns/" target="_blank">
AWS SNS </a> for sending SMS
messages.
</p>
<p>For more information about the Notify.gov infrastructure, contact us at <a
href="mailto:notify-support@gsa.gov">notify-support@gsa.gov</a>.</p>
<h2>Data</h2>
<p>
On Notify.gov, data is encrypted both in transit and at rest. To send a message, agencies upload a spreadsheet of
phone numbers and other necessary data from their existing data management system.
</p>
<p>
Notify.gov is not a system of record, so it does not have a System of Records Notice (SORN). Agencies are
responsible for managing their data outside of Notify.gov.
</p>
<h3>Data retention</h3>
<p>
Any data uploads that have recipient data are held for seven calendar days; personally identifiable information
(PII) is never stored in Notifys database.
</p>
<h2>Multi-Factor Authentication</h2>
<p>
Notify.gov uses <a class="use-link usa-link--external" href="https://login.gov/what-is-login/"
target="_blank">Login.gov</a> for enhanced security.
Login.gov is an extra layer of security created by the government that uses multi-factor authentication and stronger
passwords to protect your account.
</p>
<p>
To access Notify.gov, users will use a Login.gov account associated with their agency (.gov) email with one of the
<a class="use-link usa-link--external" href="https://login.gov/help/get-started/authentication-methods/"
target="_blank">multi-factor authentication
methods</a> offered through Login.gov.
</p>
</section>
{% endblock %}

View File

@@ -103,6 +103,7 @@ def generate_notifications_csv(**kwargs):
"Carrier Response",
"Status",
"Time",
"Carrier",
]
for header in original_column_headers:
if header.lower() != "phone number":
@@ -118,6 +119,7 @@ def generate_notifications_csv(**kwargs):
"Carrier Response",
"Status",
"Time",
"Carrier",
]
yield ",".join(fieldnames) + "\n"
@@ -140,6 +142,7 @@ def generate_notifications_csv(**kwargs):
notification["provider_response"],
notification["status"],
preferred_tz_created_at,
notification["carrier"],
]
for header in original_column_headers:
if header.lower() != "phone number":
@@ -158,6 +161,7 @@ def generate_notifications_csv(**kwargs):
notification["provider_response"],
notification["status"],
preferred_tz_created_at,
notification["carrier"],
]
yield Spreadsheet.from_rows([map(str, values)]).as_csv_data

View File

@@ -1,6 +1,6 @@
env: production
instances: 2
memory: 1.5G
memory: 2G
command: newrelic-admin run-program gunicorn -c /home/vcap/app/gunicorn_config.py application
public_admin_route: beta.notify.gov
cloud_dot_gov_route: notify.app.cloud.gov

View File

@@ -18,6 +18,7 @@ EXCLUDED_ENDPOINTS = tuple(
Navigation.get_endpoint_with_blueprint,
{
"about_notify",
"about_security",
"accept_invite",
"accept_org_invite",
"accessibility_statement",

View File

@@ -58,6 +58,7 @@ def _get_notifications_csv(
"to": recipient,
"recipient": recipient,
"client_reference": "ref 1234",
"carrier": "AT&T Mobility",
}
for i in range(rows)
],
@@ -88,15 +89,15 @@ def get_notifications_csv_mock(
(
None,
[
"Phone Number,Template,Sent by,Batch File,Carrier Response,Status,Time\n",
"8005555555,foo,,,Did not like it,Delivered,1943-04-19 08:00:00 AM US/Eastern\r\n",
"Phone Number,Template,Sent by,Batch File,Carrier Response,Status,Time,Carrier\n",
"8005555555,foo,,,Did not like it,Delivered,1943-04-19 08:00:00 AM US/Eastern,AT&T Mobility\r\n",
],
),
(
"Anne Example",
[
"Phone Number,Template,Sent by,Batch File,Carrier Response,Status,Time\n",
"8005555555,foo,Anne Example,,Did not like it,Delivered,1943-04-19 08:00:00 AM US/Eastern\r\n", # noqa
"Phone Number,Template,Sent by,Batch File,Carrier Response,Status,Time,Carrier\n",
"8005555555,foo,Anne Example,,Did not like it,Delivered,1943-04-19 08:00:00 AM US/Eastern,AT&T Mobility\r\n", # noqa
],
),
],
@@ -135,6 +136,7 @@ def test_generate_notifications_csv_without_job(
"Carrier Response",
"Status",
"Time",
"Carrier",
],
[
"8005555555",
@@ -144,6 +146,7 @@ def test_generate_notifications_csv_without_job(
"Did not like it",
"Delivered",
"1943-04-19 08:00:00 AM US/Eastern",
"AT&T Mobility",
],
),
(
@@ -159,6 +162,7 @@ def test_generate_notifications_csv_without_job(
"Carrier Response",
"Status",
"Time",
"Carrier",
"a",
"b",
"c",
@@ -171,6 +175,7 @@ def test_generate_notifications_csv_without_job(
"Did not like it",
"Delivered",
"1943-04-19 08:00:00 AM US/Eastern",
"AT&T Mobility",
"🐜",
"🐝",
"🦀",
@@ -189,6 +194,7 @@ def test_generate_notifications_csv_without_job(
"Carrier Response",
"Status",
"Time",
"Carrier",
"a",
"b",
"c",
@@ -201,6 +207,7 @@ def test_generate_notifications_csv_without_job(
"Did not like it",
"Delivered",
"1943-04-19 08:00:00 AM US/Eastern",
"AT&T Mobility",
"🐜,🐜",
"🐝,🐝",
"🦀",

View File

@@ -11,7 +11,7 @@ E2E_TEST_URI = os.getenv("NOTIFY_E2E_TEST_URI")
def test_best_practices_side_menu(authenticated_page):
page = authenticated_page
page.goto(f"{E2E_TEST_URI}/best-practices")
page.goto(f"{E2E_TEST_URI}/guides/best-practices")
page.wait_for_load_state("domcontentloaded")
check_axe_report(page)
@@ -58,7 +58,7 @@ def test_best_practices_side_menu(authenticated_page):
def test_breadcrumbs_best_practices(authenticated_page):
page = authenticated_page
page.goto(f"{E2E_TEST_URI}/best-practices")
page.goto(f"{E2E_TEST_URI}/guides/best-practices")
page.wait_for_load_state("domcontentloaded")
check_axe_report(page)

View File

@@ -8,7 +8,7 @@ const sublinks = [
{ label: 'Trial Mode', path: '/using-notify/trial-mode' },
{ label: 'Pricing', path: '/using-notify/pricing' },
{ label: 'Delivery Status', path: '/using-notify/delivery-status' },
{ label: 'Guidance', path: '/using-notify/guidance' },
{ label: 'Guidance', path: '/guides/using-notify/guidance' },
{ label: 'Features', path: '/features' },
{ label: 'Roadmap', path: '/features/roadmap' },
{ label: 'Security', path: '/features/security' },