mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-05-26 16:20:19 -04:00
12
.github/workflows/checks.yml
vendored
12
.github/workflows/checks.yml
vendored
@@ -10,19 +10,9 @@ env:
|
||||
FLASK_APP: application.py
|
||||
FLASK_ENV: development
|
||||
WERKZEUG_DEBUG_PIN: off
|
||||
REDIS_URL: "redis://you-forgot-to-mock-a-redis-call-to"
|
||||
REDIS_ENABLED: True
|
||||
ANTIVIRUS_ENABLED: 0
|
||||
REDIS_ENABLED: 0
|
||||
NODE_VERSION: 16.15.1
|
||||
ADMIN_CLIENT_ID: notify-admin
|
||||
ADMIN_CLIENT_USERNAME: notify-admin
|
||||
ADMIN_CLIENT_SECRET: dev-notify-secret-key
|
||||
ADMIN_BASE_URL: http://localhost:6012
|
||||
API_HOST_NAME: http://localhost:6011
|
||||
DEV_API_HOST_NAME: http://localhost:6011
|
||||
AWS_REGION: us-west-2
|
||||
BASIC_AUTH_USERNAME: curiousabout
|
||||
BASIC_AUTH_PASSWORD: the10xnotifybeta
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
13
.github/workflows/daily_checks.yml
vendored
13
.github/workflows/daily_checks.yml
vendored
@@ -14,20 +14,9 @@ env:
|
||||
FLASK_APP: application.py
|
||||
FLASK_ENV: development
|
||||
WERKZEUG_DEBUG_PIN: off
|
||||
REDIS_URL: redis://adminredis:6379/0
|
||||
DEV_REDIS_URL: redis://adminredis:6379/0
|
||||
REDIS_ENABLED: False
|
||||
ANTIVIRUS_ENABLED: 0
|
||||
REDIS_ENABLED: 0
|
||||
NODE_VERSION: 16.15.1
|
||||
ADMIN_CLIENT_ID: notify-admin
|
||||
ADMIN_CLIENT_USERNAME: notify-admin
|
||||
ADMIN_CLIENT_SECRET: dev-notify-secret-key
|
||||
ADMIN_BASE_URL: http://localhost:6012
|
||||
API_HOST_NAME: http://localhost:6011
|
||||
DEV_API_HOST_NAME: http://localhost:6011
|
||||
AWS_REGION: us-west-2
|
||||
BASIC_AUTH_USERNAME: curiousabout
|
||||
BASIC_AUTH_PASSWORD: the10xnotifybeta
|
||||
|
||||
jobs:
|
||||
dependency-audits:
|
||||
|
||||
@@ -2,42 +2,30 @@ import json
|
||||
import os
|
||||
|
||||
|
||||
def find_by_service_name(services, service_name):
|
||||
for i in range(len(services)):
|
||||
if services[i]['name'] == service_name:
|
||||
return services[i]
|
||||
return None
|
||||
class CloudfoundryConfig:
|
||||
def __init__(self):
|
||||
self.parsed_services = json.loads(os.environ.get('VCAP_SERVICES') or '{}')
|
||||
buckets = self.parsed_services.get('s3') or []
|
||||
self.s3_buckets = {bucket['name']: bucket['credentials'] for bucket in buckets}
|
||||
self._empty_bucket_credentials = {
|
||||
'bucket': '',
|
||||
'access_key_id': '',
|
||||
'secret_access_key': '',
|
||||
'region': ''
|
||||
}
|
||||
|
||||
@property
|
||||
def redis_url(self):
|
||||
try:
|
||||
return self.parsed_services['aws-elasticache-redis'][0]['credentials']['uri'].replace(
|
||||
'redis://',
|
||||
'rediss://'
|
||||
)
|
||||
except KeyError:
|
||||
return os.environ.get('REDIS_URL')
|
||||
|
||||
def s3_credentials(self, service_name):
|
||||
return self.s3_buckets.get(service_name) or self._empty_bucket_credentials
|
||||
|
||||
|
||||
def extract_cloudfoundry_config():
|
||||
vcap_services = json.loads(os.environ['VCAP_SERVICES'])
|
||||
|
||||
# Redis config
|
||||
os.environ['REDIS_URL'] = vcap_services['aws-elasticache-redis'][0]['credentials']['uri'].replace('redis', 'rediss')
|
||||
|
||||
# CSV Upload Bucket Name
|
||||
bucket_service = find_by_service_name(
|
||||
vcap_services['s3'], f"notifications-api-csv-upload-bucket-{os.environ['DEPLOY_ENV']}")
|
||||
if bucket_service:
|
||||
os.environ['CSV_UPLOAD_BUCKET_NAME'] = bucket_service['credentials']['bucket']
|
||||
os.environ['CSV_UPLOAD_ACCESS_KEY'] = bucket_service['credentials']['access_key_id']
|
||||
os.environ['CSV_UPLOAD_SECRET_KEY'] = bucket_service['credentials']['secret_access_key']
|
||||
os.environ['CSV_UPLOAD_REGION'] = bucket_service['credentials']['region']
|
||||
|
||||
# Contact List Bucket Name
|
||||
bucket_service = find_by_service_name(
|
||||
vcap_services['s3'], f"notifications-api-contact-list-bucket-{os.environ['DEPLOY_ENV']}")
|
||||
if bucket_service:
|
||||
os.environ['CONTACT_LIST_BUCKET_NAME'] = bucket_service['credentials']['bucket']
|
||||
os.environ['CONTACT_LIST_ACCESS_KEY'] = bucket_service['credentials']['access_key_id']
|
||||
os.environ['CONTACT_LIST_SECRET_KEY'] = bucket_service['credentials']['secret_access_key']
|
||||
os.environ['CONTACT_LIST_REGION'] = bucket_service['credentials']['region']
|
||||
|
||||
# Logo Upload Bucket Name
|
||||
bucket_service = find_by_service_name(
|
||||
vcap_services['s3'], f"notifications-admin-logo-upload-bucket-{os.environ['DEPLOY_ENV']}")
|
||||
if bucket_service:
|
||||
os.environ['LOGO_UPLOAD_BUCKET_NAME'] = bucket_service['credentials']['bucket']
|
||||
os.environ['LOGO_UPLOAD_ACCESS_KEY'] = bucket_service['credentials']['access_key_id']
|
||||
os.environ['LOGO_UPLOAD_SECRET_KEY'] = bucket_service['credentials']['secret_access_key']
|
||||
os.environ['LOGO_UPLOAD_REGION'] = bucket_service['credentials']['region']
|
||||
cloud_config = CloudfoundryConfig()
|
||||
|
||||
269
app/config.py
269
app/config.py
@@ -1,47 +1,47 @@
|
||||
import json
|
||||
import os
|
||||
|
||||
if os.environ.get('VCAP_SERVICES'):
|
||||
# on cloudfoundry, config is a json blob in VCAP_SERVICES - unpack it, and populate
|
||||
# standard environment variables from it
|
||||
from app.cloudfoundry_config import extract_cloudfoundry_config
|
||||
extract_cloudfoundry_config()
|
||||
from app.cloudfoundry_config import cloud_config
|
||||
|
||||
|
||||
class Config(object):
|
||||
NOTIFY_APP_NAME = 'admin'
|
||||
NOTIFY_ENVIRONMENT = os.environ.get('NOTIFY_ENVIRONMENT', 'development')
|
||||
API_HOST_NAME = os.environ.get('API_HOST_NAME', 'localhost')
|
||||
ADMIN_BASE_URL = os.environ.get('ADMIN_BASE_URL', 'http://localhost:6012')
|
||||
HEADER_COLOUR = '#81878b' # mix(govuk-colour("dark-grey"), govuk-colour("mid-grey"))
|
||||
LOGO_CDN_DOMAIN = 'static-logos.notifications.service.gov.uk' # TODO use our own CDN
|
||||
ASSETS_DEBUG = False
|
||||
|
||||
# Credentials
|
||||
ADMIN_CLIENT_SECRET = os.environ.get('ADMIN_CLIENT_SECRET')
|
||||
ADMIN_CLIENT_USER_NAME = os.environ.get('ADMIN_CLIENT_USERNAME')
|
||||
API_HOST_NAME = os.environ.get('API_HOST_NAME', 'localhost')
|
||||
SECRET_KEY = os.environ.get('SECRET_KEY')
|
||||
DANGEROUS_SALT = os.environ.get('DANGEROUS_SALT')
|
||||
ZENDESK_API_KEY = os.environ.get('ZENDESK_API_KEY')
|
||||
# ZENDESK_API_KEY = os.environ.get('ZENDESK_API_KEY')
|
||||
ROUTE_SECRET_KEY_1 = os.environ.get('ROUTE_SECRET_KEY_1', 'dev-route-secret-key-1')
|
||||
ROUTE_SECRET_KEY_2 = os.environ.get('ROUTE_SECRET_KEY_2', 'dev-route-secret-key-2')
|
||||
BASIC_AUTH_USERNAME = os.environ.get('BASIC_AUTH_USERNAME')
|
||||
BASIC_AUTH_PASSWORD = os.environ.get('BASIC_AUTH_PASSWORD')
|
||||
|
||||
# if we're not on cloudfoundry, we can get to this app from localhost. but on cloudfoundry its different
|
||||
ADMIN_BASE_URL = os.environ.get('ADMIN_BASE_URL', 'http://localhost:6012')
|
||||
|
||||
TEMPLATE_PREVIEW_API_HOST = os.environ.get('TEMPLATE_PREVIEW_API_HOST', 'http://localhost:6013')
|
||||
TEMPLATE_PREVIEW_API_HOST = os.environ.get('TEMPLATE_PREVIEW_API_HOST', 'http://localhost:9999')
|
||||
TEMPLATE_PREVIEW_API_KEY = os.environ.get('TEMPLATE_PREVIEW_API_KEY', 'my-secret-key')
|
||||
ANTIVIRUS_API_HOST = os.environ.get('ANTIVIRUS_API_HOST', 'http://localhost:6016')
|
||||
ANTIVIRUS_API_KEY = os.environ.get('ANTIVIRUS_API_KEY', 'test-key')
|
||||
|
||||
# Logging
|
||||
DEBUG = False
|
||||
NOTIFY_LOG_LEVEL = os.environ.get('NOTIFY_LOG_LEVEL', 'INFO')
|
||||
NOTIFY_LOG_PATH = os.environ.get('NOTIFY_LOG_PATH', 'application.log')
|
||||
|
||||
ANTIVIRUS_API_HOST = os.environ.get('ANTIVIRUS_API_HOST')
|
||||
ANTIVIRUS_API_KEY = os.environ.get('ANTIVIRUS_API_KEY')
|
||||
|
||||
ASSETS_DEBUG = False
|
||||
AWS_REGION = os.environ.get('AWS_REGION')
|
||||
DEFAULT_SERVICE_LIMIT = 50
|
||||
|
||||
EMAIL_EXPIRY_SECONDS = 3600 # 1 hour
|
||||
INVITATION_EXPIRY_SECONDS = 3600 * 24 * 2 # 2 days - also set on api
|
||||
EMAIL_2FA_EXPIRY_SECONDS = 1800 # 30 Minutes
|
||||
HEADER_COLOUR = '#81878b' # mix(govuk-colour("dark-grey"), govuk-colour("mid-grey"))
|
||||
HTTP_PROTOCOL = 'http'
|
||||
NOTIFY_APP_NAME = 'admin'
|
||||
NOTIFY_LOG_LEVEL = os.environ.get('NOTIFY_LOG_LEVEL', 'INFO')
|
||||
PERMANENT_SESSION_LIFETIME = 20 * 60 * 60 # 20 hours
|
||||
SEND_FILE_MAX_AGE_DEFAULT = 365 * 24 * 60 * 60 # 1 year
|
||||
REPLY_TO_EMAIL_ADDRESS_VALIDATION_TIMEOUT = 45
|
||||
ACTIVITY_STATS_LIMIT_DAYS = 7
|
||||
SESSION_COOKIE_HTTPONLY = True
|
||||
SESSION_COOKIE_NAME = 'notify_admin_session'
|
||||
SESSION_COOKIE_SECURE = True
|
||||
@@ -51,39 +51,13 @@ class Config(object):
|
||||
SESSION_REFRESH_EACH_REQUEST = False
|
||||
WTF_CSRF_ENABLED = True
|
||||
WTF_CSRF_TIME_LIMIT = None
|
||||
CSV_UPLOAD_BUCKET_NAME = 'local-notifications-csv-upload'
|
||||
CSV_UPLOAD_ACCESS_KEY = os.environ.get('AWS_ACCESS_KEY_ID')
|
||||
CSV_UPLOAD_SECRET_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
|
||||
CSV_UPLOAD_REGION = os.environ.get('AWS_REGION')
|
||||
CONTACT_LIST_UPLOAD_BUCKET_NAME = 'local-contact-list'
|
||||
CONTACT_LIST_UPLOAD_ACCESS_KEY = os.environ.get('AWS_ACCESS_KEY_ID')
|
||||
CONTACT_LIST_UPLOAD_SECRET_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
|
||||
CONTACT_LIST_UPLOAD_REGION = os.environ.get('AWS_REGION')
|
||||
ACTIVITY_STATS_LIMIT_DAYS = 7
|
||||
|
||||
REPLY_TO_EMAIL_ADDRESS_VALIDATION_TIMEOUT = 45
|
||||
|
||||
NOTIFY_ENVIRONMENT = 'development'
|
||||
LOGO_UPLOAD_BUCKET_NAME = 'public-logos-local'
|
||||
LOGO_UPLOAD_ACCESS_KEY = os.environ.get('AWS_ACCESS_KEY_ID')
|
||||
LOGO_UPLOAD_SECRET_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
|
||||
LOGO_UPLOAD_REGION = os.environ.get('AWS_REGION')
|
||||
# MOU_BUCKET_NAME = 'local-mou'
|
||||
# TRANSIENT_UPLOADED_LETTERS = 'local-transient-uploaded-letters'
|
||||
ROUTE_SECRET_KEY_1 = os.environ.get('ROUTE_SECRET_KEY_1', 'dev-route-secret-key-1')
|
||||
ROUTE_SECRET_KEY_2 = os.environ.get('ROUTE_SECRET_KEY_2', 'dev-route-secret-key-2')
|
||||
CHECK_PROXY_HEADER = False
|
||||
ANTIVIRUS_ENABLED = True
|
||||
ANTIVIRUS_ENABLED = os.environ.get('ANTIVIRUS_ENABLED') == '1'
|
||||
|
||||
REDIS_URL = os.environ.get('REDIS_URL')
|
||||
REDIS_ENABLED = True
|
||||
AWS_REGION = os.environ.get('AWS_REGION')
|
||||
|
||||
BASIC_AUTH_USERNAME = os.environ.get('BASIC_AUTH_USERNAME')
|
||||
BASIC_AUTH_PASSWORD = os.environ.get('BASIC_AUTH_PASSWORD')
|
||||
BASIC_AUTH_FORCE = True
|
||||
|
||||
ASSET_DOMAIN = ''
|
||||
ASSET_PATH = '/static/'
|
||||
REDIS_URL = cloud_config.redis_url
|
||||
REDIS_ENABLED = os.environ.get('REDIS_ENABLED', '1') == '1'
|
||||
|
||||
# TODO: reassign this
|
||||
NOTIFY_SERVICE_ID = 'd6aa2c68-a2d9-4437-ab19-3ae8eb202553'
|
||||
@@ -102,168 +76,91 @@ class Config(object):
|
||||
}
|
||||
|
||||
|
||||
def _default_s3_credentials(bucket_name):
|
||||
return {
|
||||
'bucket': bucket_name,
|
||||
'access_key_id': os.environ.get('AWS_ACCESS_KEY_ID'),
|
||||
'secret_access_key': os.environ.get('AWS_SECRET_ACCESS_KEY'),
|
||||
'region': os.environ.get('AWS_REGION')
|
||||
}
|
||||
|
||||
|
||||
class Development(Config):
|
||||
ADMIN_BASE_URL = 'http://localhost:6012'
|
||||
BASIC_AUTH_FORCE = False
|
||||
NOTIFY_LOG_PATH = 'application.log'
|
||||
DEBUG = True
|
||||
SESSION_COOKIE_SECURE = False
|
||||
SESSION_PROTECTION = None
|
||||
|
||||
# Buckets
|
||||
CSV_UPLOAD_BUCKET_NAME = 'local-notifications-csv-upload' # created in gsa sandbox
|
||||
CONTACT_LIST_UPLOAD_BUCKET_NAME = 'local-contact-list' # created in gsa sandbox
|
||||
LOGO_UPLOAD_BUCKET_NAME = 'local-public-logos-tools' # created in gsa sandbox
|
||||
# MOU_BUCKET_NAME = 'local-notify-tools-mou' # created in gsa sandbox
|
||||
# TRANSIENT_UPLOADED_LETTERS = 'development-transient-uploaded-letters' # not created in gsa sandbox
|
||||
# PRECOMPILED_ORIGINALS_BACKUP_LETTERS =
|
||||
# 'development-letters-precompiled-originals-backup' # not created in sandbox
|
||||
|
||||
ADMIN_CLIENT_SECRET = os.environ.get('ADMIN_CLIENT_SECRET')
|
||||
# check for local compose orchestration variable
|
||||
API_HOST_NAME = os.environ.get('DEV_API_HOST_NAME', 'http://dev:6011')
|
||||
DANGEROUS_SALT = 'dev-notify-salt'
|
||||
SECRET_KEY = 'dev-notify-secret-key' # nosec B105 - only used in development
|
||||
ANTIVIRUS_API_HOST = 'http://localhost:6016'
|
||||
ANTIVIRUS_API_KEY = 'test-key'
|
||||
ANTIVIRUS_ENABLED = os.environ.get('ANTIVIRUS_ENABLED') == '1'
|
||||
|
||||
ASSET_PATH = '/static/'
|
||||
LOGO_CDN_DOMAIN = 'static-logos.notify.tools' # replace with our own CDN
|
||||
|
||||
|
||||
class Test(Development):
|
||||
BASIC_AUTH_FORCE = False
|
||||
DEBUG = True
|
||||
TESTING = True
|
||||
WTF_CSRF_ENABLED = False
|
||||
CSV_UPLOAD_BUCKET_NAME = 'test-notifications-csv-upload'
|
||||
CONTACT_LIST_UPLOAD_BUCKET_NAME = 'test-contact-list'
|
||||
LOGO_UPLOAD_BUCKET_NAME = 'public-logos-test'
|
||||
LOGO_CDN_DOMAIN = 'static-logos.test.com'
|
||||
# MOU_BUCKET_NAME = 'test-mou'
|
||||
# TRANSIENT_UPLOADED_LETTERS = 'test-transient-uploaded-letters'
|
||||
# PRECOMPILED_ORIGINALS_BACKUP_LETTERS = 'test-letters-precompiled-originals-backup'
|
||||
NOTIFY_ENVIRONMENT = 'test'
|
||||
API_HOST_NAME = 'http://you-forgot-to-mock-an-api-call-to'
|
||||
REDIS_URL = 'redis://you-forgot-to-mock-a-redis-call-to'
|
||||
TEMPLATE_PREVIEW_API_HOST = 'http://localhost:9999'
|
||||
ANTIVIRUS_API_HOST = 'https://test-antivirus'
|
||||
ANTIVIRUS_API_KEY = 'test-antivirus-secret'
|
||||
ANTIVIRUS_ENABLED = True
|
||||
|
||||
ASSET_DOMAIN = 'static.example.com'
|
||||
ASSET_PATH = 'https://static.example.com/'
|
||||
|
||||
|
||||
class Scanning(Test):
|
||||
BASIC_AUTH_FORCE = False
|
||||
API_HOST_NAME = 'https://notifications-api.app.cloud.gov/'
|
||||
NOTIFY_ENVIRONMENT = 'scanning'
|
||||
HTTP_PROTOCOL = 'http'
|
||||
ASSET_DOMAIN = ''
|
||||
ASSET_PATH = '/static/'
|
||||
|
||||
# Buckets
|
||||
CSV_UPLOAD_BUCKET = _default_s3_credentials('local-notifications-csv-upload')
|
||||
CONTACT_LIST_BUCKET = _default_s3_credentials('local-contact-list')
|
||||
LOGO_UPLOAD_BUCKET = _default_s3_credentials('local-public-logos-tools')
|
||||
|
||||
class Preview(Config):
|
||||
BASIC_AUTH_FORCE = True
|
||||
HTTP_PROTOCOL = 'https'
|
||||
HEADER_COLOUR = '#F499BE' # $baby-pink
|
||||
CSV_UPLOAD_BUCKET_NAME = 'preview-notifications-csv-upload'
|
||||
CONTACT_LIST_UPLOAD_BUCKET_NAME = 'preview-contact-list'
|
||||
LOGO_UPLOAD_BUCKET_NAME = 'public-logos-preview'
|
||||
LOGO_CDN_DOMAIN = 'static-logos.notify.works'
|
||||
# MOU_BUCKET_NAME = 'notify.works-mou'
|
||||
# TRANSIENT_UPLOADED_LETTERS = 'preview-transient-uploaded-letters'
|
||||
# PRECOMPILED_ORIGINALS_BACKUP_LETTERS = 'preview-letters-precompiled-originals-backup'
|
||||
NOTIFY_ENVIRONMENT = 'preview'
|
||||
CHECK_PROXY_HEADER = False
|
||||
ASSET_DOMAIN = 'static.notify.works'
|
||||
ASSET_PATH = 'https://static.notify.works/'
|
||||
|
||||
# On preview, extend the validation timeout to allow more leniency when running functional tests
|
||||
REPLY_TO_EMAIL_ADDRESS_VALIDATION_TIMEOUT = 120
|
||||
# credential overrides
|
||||
DANGEROUS_SALT = 'dev-notify-salt'
|
||||
SECRET_KEY = 'dev-notify-secret-key' # nosec B105 - only used in development
|
||||
# ADMIN_CLIENT_USER_NAME is called ADMIN_CLIENT_ID in api repo, they should match
|
||||
ADMIN_CLIENT_USER_NAME = 'notify-admin'
|
||||
ADMIN_CLIENT_SECRET = 'dev-notify-secret-key' # nosec B105 - only used in development
|
||||
|
||||
|
||||
class Staging(Config):
|
||||
BASIC_AUTH_FORCE = True
|
||||
HTTP_PROTOCOL = 'https'
|
||||
HEADER_COLOUR = '#6F72AF' # $mauve
|
||||
CSV_UPLOAD_BUCKET_NAME = 'staging-notifications-csv-upload'
|
||||
CONTACT_LIST_UPLOAD_BUCKET_NAME = 'staging-contact-list'
|
||||
LOGO_UPLOAD_BUCKET_NAME = 'public-logos-staging'
|
||||
LOGO_CDN_DOMAIN = 'static-logos.staging-notify.works'
|
||||
# MOU_BUCKET_NAME = 'staging-notify.works-mou'
|
||||
# TRANSIENT_UPLOADED_LETTERS = 'staging-transient-uploaded-letters'
|
||||
# PRECOMPILED_ORIGINALS_BACKUP_LETTERS = 'staging-letters-precompiled-originals-backup'
|
||||
NOTIFY_ENVIRONMENT = 'staging'
|
||||
CHECK_PROXY_HEADER = False
|
||||
ASSET_DOMAIN = 'static.staging-notify.works'
|
||||
ASSET_PATH = 'https://static.staging-notify.works/'
|
||||
class Test(Development):
|
||||
TESTING = True
|
||||
WTF_CSRF_ENABLED = False
|
||||
ASSET_DOMAIN = 'static.example.com'
|
||||
ASSET_PATH = 'https://static.example.com/'
|
||||
|
||||
API_HOST_NAME = 'http://you-forgot-to-mock-an-api-call-to'
|
||||
REDIS_URL = 'redis://you-forgot-to-mock-a-redis-call-to'
|
||||
ANTIVIRUS_API_HOST = 'https://test-antivirus'
|
||||
ANTIVIRUS_API_KEY = 'test-antivirus-secret'
|
||||
ANTIVIRUS_ENABLED = True
|
||||
LOGO_CDN_DOMAIN = 'static-logos.test.com'
|
||||
|
||||
# Buckets
|
||||
CSV_UPLOAD_BUCKET = _default_s3_credentials('test-csv-upload')
|
||||
CONTACT_LIST_BUCKET = _default_s3_credentials('test-contact-list')
|
||||
LOGO_UPLOAD_BUCKET = _default_s3_credentials('test-logo-upload')
|
||||
|
||||
|
||||
class Live(Config):
|
||||
BASIC_AUTH_FORCE = True
|
||||
class Production(Config):
|
||||
HEADER_COLOUR = '#005EA5' # $govuk-blue
|
||||
HTTP_PROTOCOL = 'https'
|
||||
# buckets
|
||||
CSV_UPLOAD_BUCKET_NAME = os.environ.get(
|
||||
'CSV_UPLOAD_BUCKET_NAME', 'notifications-prototype-csv-upload') # created in gsa sandbox
|
||||
CSV_UPLOAD_ACCESS_KEY = os.environ.get('CSV_UPLOAD_ACCESS_KEY')
|
||||
CSV_UPLOAD_SECRET_KEY = os.environ.get('CSV_UPLOAD_SECRET_KEY')
|
||||
CSV_UPLOAD_REGION = os.environ.get('CSV_UPLOAD_REGION')
|
||||
CONTACT_LIST_UPLOAD_BUCKET_NAME = os.environ.get(
|
||||
'CONTACT_LIST_BUCKET_NAME', 'notifications-prototype-contact-list-upload') # created in gsa sandbox
|
||||
CONTACT_LIST_UPLOAD_ACCESS_KEY = os.environ.get('CONTACT_LIST_ACCESS_KEY')
|
||||
CONTACT_LIST_UPLOAD_SECRET_KEY = os.environ.get('CONTACT_LIST_SECRET_KEY')
|
||||
CONTACT_LIST_UPLOAD_REGION = os.environ.get('CONTACT_LIST_REGION')
|
||||
LOGO_UPLOAD_BUCKET_NAME = os.environ.get(
|
||||
'LOGO_UPLOAD_BUCKET_NAME', 'notifications-prototype-logo-upload') # created in gsa sandbox
|
||||
LOGO_UPLOAD_ACCESS_KEY = os.environ.get('LOGO_UPLOAD_ACCESS_KEY')
|
||||
LOGO_UPLOAD_SECRET_KEY = os.environ.get('LOGO_UPLOAD_SECRET_KEY')
|
||||
LOGO_UPLOAD_REGION = os.environ.get('LOGO_UPLOAD_REGION')
|
||||
# MOU_BUCKET_NAME = os.environ.get(
|
||||
# 'MOU_UPLOAD_BUCKET_NAME', 'notifications-prototype-mou') # created in gsa sandbox
|
||||
# TRANSIENT_UPLOADED_LETTERS = 'prototype-transient-uploaded-letters' # not created in gsa sandbox
|
||||
# PRECOMPILED_ORIGINALS_BACKUP_LETTERS = 'prototype-letters-precompiled-originals-backup' # not in sandbox
|
||||
|
||||
NOTIFY_ENVIRONMENT = 'live'
|
||||
CHECK_PROXY_HEADER = False
|
||||
# ASSET_DOMAIN = 'static.notifications.service.gov.uk'
|
||||
# ASSET_PATH = 'https://static.notifications.service.gov.uk/'
|
||||
BASIC_AUTH_FORCE = True
|
||||
ASSET_DOMAIN = '' # TODO use a CDN
|
||||
ASSET_PATH = '/static/' # TODO use a CDN
|
||||
LOGO_CDN_DOMAIN = 'static-logos.notifications.service.gov.uk' # TODO use our own CDN
|
||||
DEBUG = False
|
||||
|
||||
ADMIN_CLIENT_SECRET = os.environ.get('ADMIN_CLIENT_SECRET')
|
||||
ADMIN_CLIENT_USER_NAME = os.environ.get('ADMIN_CLIENT_USERNAME')
|
||||
API_HOST_NAME = os.environ.get('API_HOST_NAME')
|
||||
DANGEROUS_SALT = os.environ.get('DANGEROUS_SALT')
|
||||
SECRET_KEY = os.environ.get('SECRET_KEY')
|
||||
ANTIVIRUS_API_HOST = 'http://localhost:6016'
|
||||
ANTIVIRUS_API_KEY = 'test-key'
|
||||
ANTIVIRUS_ENABLED = False
|
||||
# buckets
|
||||
CSV_UPLOAD_BUCKET = cloud_config.s3_credentials(
|
||||
f"notifications-api-csv-upload-bucket-{os.environ['NOTIFY_ENVIRONMENT']}")
|
||||
CONTACT_LIST_BUCKET = cloud_config.s3_credentials(
|
||||
f"notifications-api-contact-list-bucket-{os.environ['NOTIFY_ENVIRONMENT']}")
|
||||
LOGO_UPLOAD_BUCKET = cloud_config.s3_credentials(
|
||||
f"notifications-admin-logo-upload-bucket-{os.environ['NOTIFY_ENVIRONMENT']}")
|
||||
|
||||
|
||||
class CloudFoundryConfig(Config):
|
||||
pass
|
||||
class Staging(Production):
|
||||
BASIC_AUTH_FORCE = True
|
||||
HEADER_COLOUR = '#6F72AF' # $mauve
|
||||
|
||||
|
||||
# CloudFoundry sandbox
|
||||
class Sandbox(CloudFoundryConfig):
|
||||
HTTP_PROTOCOL = 'https'
|
||||
HEADER_COLOUR = '#F499BE' # $baby-pink
|
||||
CSV_UPLOAD_BUCKET_NAME = 'cf-sandbox-notifications-csv-upload'
|
||||
LOGO_UPLOAD_BUCKET_NAME = 'cf-sandbox-notifications-logo-upload'
|
||||
NOTIFY_ENVIRONMENT = 'sandbox'
|
||||
class Scanning(Production):
|
||||
BASIC_AUTH_FORCE = False
|
||||
HTTP_PROTOCOL = 'http'
|
||||
API_HOST_NAME = 'https://notifications-api.app.cloud.gov/'
|
||||
SECRET_KEY = 'dev-notify-secret-key' # nosec B105 - only used in development
|
||||
ADMIN_CLIENT_USER_NAME = 'notify-admin'
|
||||
ADMIN_CLIENT_SECRET = 'dev-notify-secret-key' # nosec B105 - only used in development
|
||||
|
||||
|
||||
configs = {
|
||||
'development': Development,
|
||||
'test': Test,
|
||||
'scanning': Scanning,
|
||||
'preview': Preview,
|
||||
'staging': Staging,
|
||||
'live': Live,
|
||||
'production': Live,
|
||||
'sandbox': Sandbox
|
||||
'production': Production
|
||||
}
|
||||
|
||||
@@ -44,21 +44,25 @@ class ContactList(JSONModel):
|
||||
contact_list_id=contact_list_id,
|
||||
))
|
||||
|
||||
@staticmethod
|
||||
def get_bucket_credentials(key):
|
||||
return current_app.config['CONTACT_LIST_BUCKET'][key]
|
||||
|
||||
@staticmethod
|
||||
def get_bucket_name():
|
||||
return current_app.config['CONTACT_LIST_UPLOAD_BUCKET_NAME']
|
||||
return ContactList.get_bucket_credentials('bucket')
|
||||
|
||||
@staticmethod
|
||||
def get_access_key():
|
||||
return current_app.config['CONTACT_LIST_UPLOAD_ACCESS_KEY']
|
||||
return ContactList.get_bucket_credentials('access_key_id')
|
||||
|
||||
@staticmethod
|
||||
def get_secret_key():
|
||||
return current_app.config['CONTACT_LIST_UPLOAD_SECRET_KEY']
|
||||
return ContactList.get_bucket_credentials('secret_access_key')
|
||||
|
||||
@staticmethod
|
||||
def get_region():
|
||||
return current_app.config['CONTACT_LIST_UPLOAD_REGION']
|
||||
return ContactList.get_bucket_credentials('region')
|
||||
|
||||
@staticmethod
|
||||
def get_filename(service_id, upload_id):
|
||||
|
||||
@@ -15,11 +15,11 @@ FILE_LOCATION_STRUCTURE = 'service-{}-notify/{}.csv'
|
||||
|
||||
def get_csv_location(service_id, upload_id):
|
||||
return (
|
||||
current_app.config['CSV_UPLOAD_BUCKET_NAME'],
|
||||
current_app.config['CSV_UPLOAD_BUCKET']['bucket'],
|
||||
FILE_LOCATION_STRUCTURE.format(service_id, upload_id),
|
||||
current_app.config['CSV_UPLOAD_ACCESS_KEY'],
|
||||
current_app.config['CSV_UPLOAD_SECRET_KEY'],
|
||||
current_app.config['CSV_UPLOAD_REGION'],
|
||||
current_app.config['CSV_UPLOAD_BUCKET']['access_key_id'],
|
||||
current_app.config['CSV_UPLOAD_BUCKET']['secret_access_key'],
|
||||
current_app.config['CSV_UPLOAD_BUCKET']['region'],
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -15,14 +15,18 @@ LETTER_TEMP_LOGO_LOCATION = 'letters/static/images/letter-template/temp-{user_id
|
||||
|
||||
def get_logo_location(filename=None):
|
||||
return (
|
||||
current_app.config['LOGO_UPLOAD_BUCKET_NAME'],
|
||||
bucket_creds('bucket'),
|
||||
filename,
|
||||
current_app.config['LOGO_UPLOAD_ACCESS_KEY'],
|
||||
current_app.config['LOGO_UPLOAD_SECRET_KEY'],
|
||||
current_app.config['LOGO_UPLOAD_REGION'],
|
||||
bucket_creds('access_key_id'),
|
||||
bucket_creds('secret_access_key'),
|
||||
bucket_creds('region'),
|
||||
)
|
||||
|
||||
|
||||
def bucket_creds(key):
|
||||
return current_app.config['LOGO_UPLOAD_BUCKET'][key]
|
||||
|
||||
|
||||
def delete_s3_object(filename):
|
||||
get_s3_object(*get_logo_location(filename)).delete()
|
||||
|
||||
@@ -37,10 +41,10 @@ def persist_logo(old_name, new_name):
|
||||
|
||||
|
||||
def get_s3_objects_filter_by_prefix(prefix):
|
||||
bucket_name = current_app.config['LOGO_UPLOAD_BUCKET_NAME']
|
||||
session = Session(aws_access_key_id=current_app.config['LOGO_UPLOAD_ACCESS_KEY'],
|
||||
aws_secret_access_key=current_app.config['LOGO_UPLOAD_SECRET_KEY'],
|
||||
region_name=current_app.config['LOGO_UPLOAD_REGION'])
|
||||
bucket_name = bucket_creds('bucket')
|
||||
session = Session(aws_access_key_id=bucket_creds('access_key_id'),
|
||||
aws_secret_access_key=bucket_creds('secret_access_key'),
|
||||
region_name=bucket_creds('region'))
|
||||
s3 = session.resource('s3')
|
||||
return s3.Bucket(bucket_name).objects.filter(Prefix=prefix)
|
||||
|
||||
@@ -59,15 +63,15 @@ def upload_email_logo(filename, filedata, user_id):
|
||||
unique_id=str(uuid.uuid4()),
|
||||
filename=filename
|
||||
)
|
||||
bucket_name = current_app.config['LOGO_UPLOAD_BUCKET_NAME']
|
||||
bucket_name = bucket_creds('bucket')
|
||||
utils_s3upload(
|
||||
filedata=filedata,
|
||||
region=current_app.config['LOGO_UPLOAD_REGION'],
|
||||
region=bucket_creds('region'),
|
||||
bucket_name=bucket_name,
|
||||
file_location=upload_file_name,
|
||||
content_type='image/png',
|
||||
access_key=current_app.config['LOGO_UPLOAD_ACCESS_KEY'],
|
||||
secret_key=current_app.config['LOGO_UPLOAD_SECRET_KEY'],
|
||||
access_key=bucket_creds('access_key_id'),
|
||||
secret_key=bucket_creds('secret_access_key'),
|
||||
)
|
||||
|
||||
return upload_file_name
|
||||
@@ -79,15 +83,15 @@ def upload_letter_temp_logo(filename, filedata, user_id):
|
||||
unique_id=str(uuid.uuid4()),
|
||||
filename=filename
|
||||
)
|
||||
bucket_name = current_app.config['LOGO_UPLOAD_BUCKET_NAME']
|
||||
bucket_name = bucket_creds('bucket')
|
||||
utils_s3upload(
|
||||
filedata=filedata,
|
||||
region=current_app.config['LOGO_UPLOAD_REGION'],
|
||||
region=bucket_creds('region'),
|
||||
bucket_name=bucket_name,
|
||||
file_location=upload_filename,
|
||||
content_type='image/svg+xml',
|
||||
access_key=current_app.config['LOGO_UPLOAD_ACCESS_KEY'],
|
||||
secret_key=current_app.config['LOGO_UPLOAD_SECRET_KEY'],
|
||||
access_key=bucket_creds('access_key_id'),
|
||||
secret_key=bucket_creds('secret_access_key'),
|
||||
)
|
||||
|
||||
return upload_filename
|
||||
|
||||
@@ -10,9 +10,6 @@ applications:
|
||||
- route: notifications-admin.app.cloud.gov
|
||||
|
||||
services:
|
||||
# - logit-ssl-syslog-drain
|
||||
# - notify-prometheus
|
||||
# - notify-splunk
|
||||
- notifications-admin-redis-((env))
|
||||
- notifications-api-csv-upload-bucket-((env))
|
||||
- notifications-api-contact-list-bucket-((env))
|
||||
@@ -27,7 +24,7 @@ applications:
|
||||
DEPLOY_ENV: ((env))
|
||||
REDIS_ENABLED: ((REDIS_ENABLED))
|
||||
|
||||
NOTIFY_ENVIRONMENT: live
|
||||
NOTIFY_ENVIRONMENT: ((env))
|
||||
|
||||
# Credentials variables
|
||||
ADMIN_CLIENT_SECRET: ((ADMIN_CLIENT_SECRET))
|
||||
|
||||
21
sample.env
21
sample.env
@@ -5,33 +5,14 @@ FLASK_APP=application.py
|
||||
FLASK_ENV=development
|
||||
WERKZEUG_DEBUG_PIN=off
|
||||
|
||||
REDIS_URL=redis://adminredis:6379/0
|
||||
DEV_REDIS_URL=redis://adminredis:6379/0
|
||||
REDIS_ENABLED=True
|
||||
|
||||
SQLALCHEMY_DATABASE_URI=postgres://postgres:chummy@db:5432/notification_api
|
||||
|
||||
ANTIVIRUS_ENABLED=0
|
||||
NODE_VERSION=16.15.1
|
||||
|
||||
# ADMIN_CLIENT_USERNAME is called ADMIN_CLIENT_ID in api repo, they should match
|
||||
ADMIN_CLIENT_USERNAME=notify-admin
|
||||
ADMIN_CLIENT_SECRET=dev-notify-secret-key
|
||||
|
||||
# URL of admin app
|
||||
ADMIN_BASE_URL=http://admin:6012
|
||||
|
||||
# URL of api app (on AWS this is the internal api endpoint)
|
||||
API_HOST_NAME=http://dev:6011
|
||||
DEV_API_HOST_NAME=http://dev:6011
|
||||
REDIS_URL=redis://adminredis:6379/0
|
||||
|
||||
# AWS
|
||||
AWS_REGION=us-west-2
|
||||
AWS_ACCESS_KEY_ID="don't write secrets to the sample file"
|
||||
AWS_SECRET_ACCESS_KEY="don't write secrets to the sample file"
|
||||
|
||||
# beta protection
|
||||
BASIC_AUTH_USERNAME=username
|
||||
BASIC_AUTH_PASSWORD=password
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ from app.s3_client.s3_csv_client import set_metadata_on_csv_upload
|
||||
|
||||
|
||||
def test_sets_metadata(client_request, mocker):
|
||||
mocked_s3_object = Mock(bucket_name='test-notifications-csv-upload', key='service-1234-notify/5678.csv')
|
||||
mocked_s3_object = Mock(bucket_name='test-csv-upload', key='service-1234-notify/5678.csv')
|
||||
mocked_get_s3_object = mocker.patch(
|
||||
'app.s3_client.s3_csv_client.get_csv_upload',
|
||||
return_value=mocked_s3_object,
|
||||
@@ -14,7 +14,7 @@ def test_sets_metadata(client_request, mocker):
|
||||
|
||||
mocked_get_s3_object.assert_called_once_with('1234', '5678')
|
||||
mocked_s3_object.copy_from.assert_called_once_with(
|
||||
CopySource='test-notifications-csv-upload/service-1234-notify/5678.csv',
|
||||
CopySource='test-csv-upload/service-1234-notify/5678.csv',
|
||||
Metadata={'baz': 'True', 'foo': 'bar'},
|
||||
MetadataDirective='REPLACE',
|
||||
ServerSideEncryption='AES256',
|
||||
|
||||
@@ -21,6 +21,12 @@ from app.s3_client.s3_logo_client import (
|
||||
)
|
||||
|
||||
bucket = 'test_bucket'
|
||||
bucket_credentials = {
|
||||
'bucket': bucket,
|
||||
'access_key_id': default_access_key,
|
||||
'secret_access_key': default_secret_key,
|
||||
'region': default_region
|
||||
}
|
||||
data = {'data': 'some_data'}
|
||||
filename = 'test.png'
|
||||
svg_filename = 'test.svg'
|
||||
@@ -45,7 +51,7 @@ def letter_upload_filename(fake_uuid):
|
||||
|
||||
def test_upload_email_logo_calls_correct_args(client_request, mocker, fake_uuid, upload_filename):
|
||||
mocker.patch('uuid.uuid4', return_value=upload_id)
|
||||
mocker.patch.dict('flask.current_app.config', {'LOGO_UPLOAD_BUCKET_NAME': bucket})
|
||||
mocker.patch.dict('flask.current_app.config', {'LOGO_UPLOAD_BUCKET': bucket_credentials})
|
||||
mocked_s3_upload = mocker.patch('app.s3_client.s3_logo_client.utils_s3upload')
|
||||
|
||||
upload_email_logo(filename=filename, user_id=fake_uuid, filedata=data)
|
||||
@@ -63,7 +69,7 @@ def test_upload_email_logo_calls_correct_args(client_request, mocker, fake_uuid,
|
||||
|
||||
def test_upload_letter_temp_logo_calls_correct_args(mocker, fake_uuid, letter_upload_filename):
|
||||
mocker.patch('uuid.uuid4', return_value=upload_id)
|
||||
mocker.patch.dict('flask.current_app.config', {'LOGO_UPLOAD_BUCKET_NAME': bucket})
|
||||
mocker.patch.dict('flask.current_app.config', {'LOGO_UPLOAD_BUCKET': bucket_credentials})
|
||||
mocked_s3_upload = mocker.patch('app.s3_client.s3_logo_client.utils_s3upload')
|
||||
|
||||
new_filename = upload_letter_temp_logo(filename=svg_filename, user_id=fake_uuid, filedata=data)
|
||||
@@ -81,7 +87,7 @@ def test_upload_letter_temp_logo_calls_correct_args(mocker, fake_uuid, letter_up
|
||||
|
||||
|
||||
def test_persist_logo(client_request, mocker, fake_uuid, upload_filename):
|
||||
mocker.patch.dict('flask.current_app.config', {'LOGO_UPLOAD_BUCKET_NAME': bucket})
|
||||
mocker.patch.dict('flask.current_app.config', {'LOGO_UPLOAD_BUCKET': bucket_credentials})
|
||||
mocked_get_s3_object = mocker.patch('app.s3_client.s3_logo_client.get_s3_object')
|
||||
mocked_delete_s3_object = mocker.patch('app.s3_client.s3_logo_client.delete_s3_object')
|
||||
|
||||
|
||||
@@ -3,7 +3,14 @@ import os
|
||||
|
||||
import pytest
|
||||
|
||||
from app.cloudfoundry_config import extract_cloudfoundry_config
|
||||
from app.cloudfoundry_config import CloudfoundryConfig
|
||||
|
||||
bucket_credentials = {
|
||||
'access_key_id': 'contact-list-access',
|
||||
'bucket': 'contact-list-bucket',
|
||||
'region': 'us-gov-west-1',
|
||||
'secret_access_key': 'contact-list-secret'
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -26,22 +33,39 @@ def vcap_services():
|
||||
},
|
||||
{
|
||||
'name': 'notifications-api-contact-list-bucket-test',
|
||||
'credentials': {
|
||||
'access_key_id': 'contact-list-access',
|
||||
'bucket': 'contact-list-bucket',
|
||||
'region': 'us-gov-west-1',
|
||||
'secret_access_key': 'contact-list-secret'
|
||||
}
|
||||
'credentials': bucket_credentials
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def test_extract_cloudfoundry_config_populates_other_vars(os_environ, vcap_services):
|
||||
os.environ['DEPLOY_ENV'] = 'test'
|
||||
def test_redis_url(vcap_services):
|
||||
os.environ['VCAP_SERVICES'] = json.dumps(vcap_services)
|
||||
extract_cloudfoundry_config()
|
||||
|
||||
assert os.environ['REDIS_URL'] == 'rediss://xxx:6379'
|
||||
assert os.environ['CSV_UPLOAD_BUCKET_NAME'] == 'csv-upload-bucket'
|
||||
assert os.environ['CONTACT_LIST_BUCKET_NAME'] == 'contact-list-bucket'
|
||||
assert CloudfoundryConfig().redis_url == 'rediss://xxx:6379'
|
||||
|
||||
|
||||
def test_redis_url_falls_back_to_REDIS_URL():
|
||||
expected = 'rediss://yyy:6379'
|
||||
os.environ['REDIS_URL'] = expected
|
||||
os.environ['VCAP_SERVICES'] = ""
|
||||
|
||||
assert CloudfoundryConfig().redis_url == expected
|
||||
|
||||
|
||||
def test_s3_bucket_credentials(vcap_services):
|
||||
os.environ['VCAP_SERVICES'] = json.dumps(vcap_services)
|
||||
|
||||
assert CloudfoundryConfig().s3_credentials('notifications-api-contact-list-bucket-test') == bucket_credentials
|
||||
|
||||
|
||||
def test_s3_bucket_credentials_falls_back_to_empty_creds():
|
||||
os.environ['VCAP_SERVICES'] = ""
|
||||
expected = {
|
||||
'bucket': '',
|
||||
'access_key_id': '',
|
||||
'secret_access_key': '',
|
||||
'region': ''
|
||||
}
|
||||
|
||||
assert CloudfoundryConfig().s3_credentials('bucket') == expected
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
import importlib
|
||||
import os
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
|
||||
from app import config
|
||||
|
||||
|
||||
def cf_conf():
|
||||
os.environ['REDIS_URL'] = 'rediss://xxx:6379'
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def reload_config(os_environ):
|
||||
"""
|
||||
Reset config, by simply re-running config.py from a fresh environment
|
||||
"""
|
||||
old_env = os.environ.copy()
|
||||
os.environ.clear()
|
||||
|
||||
yield
|
||||
|
||||
os.environ.clear()
|
||||
for k, v in old_env.items():
|
||||
os.environ[k] = v
|
||||
importlib.reload(config)
|
||||
|
||||
|
||||
def test_load_cloudfoundry_config_if_available(reload_config):
|
||||
os.environ['REDIS_URL'] = 'some uri'
|
||||
os.environ['VCAP_SERVICES'] = 'some json blob'
|
||||
|
||||
with mock.patch('app.cloudfoundry_config.extract_cloudfoundry_config', side_effect=cf_conf):
|
||||
# reload config so that its module level code (ie: all of it) is re-instantiated
|
||||
importlib.reload(config)
|
||||
|
||||
assert os.environ['REDIS_URL'] == 'rediss://xxx:6379'
|
||||
assert config.Config.REDIS_URL == 'rediss://xxx:6379'
|
||||
|
||||
|
||||
def test_load_config_if_cloudfoundry_not_available(reload_config):
|
||||
os.environ['REDIS_URL'] = 'redis://xxx:6379'
|
||||
os.environ.pop('VCAP_SERVICES', None)
|
||||
|
||||
with mock.patch('app.cloudfoundry_config.extract_cloudfoundry_config') as cf_config:
|
||||
# reload config so that its module level code (ie: all of it) is re-instantiated
|
||||
importlib.reload(config)
|
||||
|
||||
assert not cf_config.called
|
||||
|
||||
assert os.environ['REDIS_URL'] == 'redis://xxx:6379'
|
||||
assert config.Config.REDIS_URL == 'redis://xxx:6379'
|
||||
Reference in New Issue
Block a user