Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use LocalStack for local testing. #618

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
41 changes: 25 additions & 16 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,36 @@ DATABASE_SCHEMA=public
DATABASE_SSL_SELF=false
PUBLIC_FRONTEND_URL="http://localhost:5173" # Used for emails linking to the frontend

# AWS SES Settings
AWS_ACCESS_KEY_ID="EXAMPLE_KEY"
AWS_SECRET_ACCESS_KEY="EXAMPLE_SECRET"
AWS_REGION="eu-north-1"
## AWS LocalStack development endpoint
LOCALSTACK_ENDPOINT=http://127.0.0.1:4566

## AWS SES Settings

## These settings correspond to LocalStack system defaults
## https://docs.localstack.cloud/references/configuration/
AWS_ACCESS_KEY_ID="test"
AWS_SECRET_ACCESS_KEY="test"
AWS_REGION=us-east-1

# `MAIL_FROM` and `MAIL_REPLY_TO` variables will not take effect for emails sent by `user-permissions` Strapi plugin
# (f.e. reset password emails) as they are configured separately via Strapi UI in `Settings > Email Templates`.
MAIL_FROM="OpenVAA Voting Advice Application <[email protected]>"
MAIL_REPLY_TO="OpenVAA Admin <[email protected]>"
MAIL_FROM="[email protected]"
MAIL_REPLY_TO="[email protected]"

## AWS S3 settings

# Maildev settings (used only in dev)
MAILDEV_PORT=1080
AWS_S3_BUCKET=static.example.com

## AWS S3 settings for static content storage
AWS_S3_ACCESS_KEY_ID="EXAMPLE_KEY"
AWS_S3_ACCESS_SECRET="EXAMPLE_SECRET"
AWS_S3_REGION=eu-north-1
AWS_S3_BUCKET=static-example-com
## These settings correspond to LocalStack system defaults
## https://docs.localstack.cloud/references/configuration/
AWS_S3_ACCESS_KEY_ID="test"
AWS_S3_ACCESS_SECRET="test"
AWS_S3_REGION=us-east-1

## Will be used as the base URL for media content uploaded via Strapi's UI.
## Requires an existing CNAME DNS record for the corresponding subdomain which points to AWS S3 bucket where the content is stored.
STATIC_CONTENT_BASE_URL=https://static.example.com
## The base URL is used to access static content uploaded via Strapi's UI to AWS S3:
## - on production it uses a dedicated subdomain which is linked to an eponymous AWS S3 bucket via a CNAME DNS record
## - in development it points directly to LocalStack host and is appended by the S3 bucket name in Strapi's `plugin.ts`
STATIC_CONTENT_BASE_URL=http://localhost:4566
STATIC_MEDIA_CONTENT_PATH=public/media

# Point to a folder (relative to /backend/vaa-strapi) if you want to load data on initialise. This will only take place if the database contains no Election
Expand Down
43 changes: 28 additions & 15 deletions backend/vaa-strapi/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,34 @@ PUBLIC_FRONTEND_URL="http://localhost:5173" # Used for emails linking to the fro
GENERATE_MOCK_DATA_ON_INITIALISE=true # Set to true to enable mock data on an empty database
GENERATE_MOCK_DATA_ON_RESTART=false # Used only in development builds

AWS_ACCESS_KEY_ID="EXAMPLE_KEY"
AWS_SECRET_ACCESS_KEY="EXAMPLE_SECRET"
AWS_REGION="eu-north-1"
## AWS LocalStack development endpoint
LOCALSTACK_ENDPOINT=http://127.0.0.1:4566

## AWS SES Settings

## These settings correspond to LocalStack system defaults
## https://docs.localstack.cloud/references/configuration/
AWS_ACCESS_KEY_ID="test"
AWS_SECRET_ACCESS_KEY="test"
AWS_REGION=us-east-1

# `MAIL_FROM` and `MAIL_REPLY_TO` variables will not take effect for emails sent by `user-permissions` Strapi plugin
# (f.e. reset password emails) as they are configured separately via Strapi UI in `Settings > Email Templates`.
MAIL_FROM="OpenVAA Voting Advice Application <[email protected]>"
MAIL_REPLY_TO="OpenVAA Admin <[email protected]>"

## AWS S3 settings for static content storage
AWS_S3_ACCESS_KEY_ID="EXAMPLE_KEY"
AWS_S3_ACCESS_SECRET="EXAMPLE_SECRET"
AWS_S3_REGION=eu-north-1
AWS_S3_BUCKET=static-example-com

## Will be used as the base URL for media content uploaded via Strapi's UI.
## Requires an existing CNAME DNS record for the corresponding subdomain which points to AWS S3 bucket where the content is stored.
STATIC_CONTENT_BASE_URL=https://static.example.com
MAIL_FROM="[email protected]"
MAIL_REPLY_TO="[email protected]"

## AWS S3 settings

AWS_S3_BUCKET=static.example.com

## These settings correspond to LocalStack system defaults
## https://docs.localstack.cloud/references/configuration/
AWS_S3_ACCESS_KEY_ID="test"
AWS_S3_ACCESS_SECRET="test"
AWS_S3_REGION=us-east-1

## The base URL is used to access static content uploaded via Strapi's UI to AWS S3:
## - on production it uses a dedicated subdomain which is linked to an eponymous AWS S3 bucket via a CNAME DNS record
## - in development it points directly to LocalStack host and is appended by the S3 bucket name in Strapi's `plugin.ts`
STATIC_CONTENT_BASE_URL=http://localhost:4566
STATIC_MEDIA_CONTENT_PATH=public/media
21 changes: 0 additions & 21 deletions backend/vaa-strapi/config/env/development/plugins.ts

This file was deleted.

33 changes: 31 additions & 2 deletions backend/vaa-strapi/config/middlewares.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,36 @@
module.exports = [
module.exports = ({env}) => [
'strapi::logger',
'strapi::errors',
'strapi::security',
/*
* To enable AWS S3 support:
* https://github.com/strapi/strapi/tree/main/packages/providers/upload-aws-s3
**/
{
name: 'strapi::security',
config: {
contentSecurityPolicy: {
useDefaults: true,
directives: {
'connect-src': ["'self'", env('NODE_ENV') === 'development' ? 'http:' : 'https:'],
'img-src': [
"'self'",
'data:',
'blob:',
'market-assets.strapi.io',
`${env('STATIC_CONTENT_BASE_URL')}`
],
'media-src': [
"'self'",
'data:',
'blob:',
'market-assets.strapi.io',
`${env('STATIC_CONTENT_BASE_URL')}`
],
upgradeInsecureRequests: null
}
}
}
},
'strapi::cors',
'strapi::poweredBy',
'strapi::query',
Expand Down
58 changes: 33 additions & 25 deletions backend/vaa-strapi/config/plugins.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,8 @@
const aws = require('@aws-sdk/client-ses');

export default ({env}) => {
/**
* Strapi initilises nodemailer transporter only once using main plugin config.
* It allows to override only transporter specific (SMPT or SES) settings using [env]/plugins.ts, not the transporter type itself.
* So we have to make sure that for development we initilise the transporter as SMTP to be able to use maildev.
*/
const emailProviderOptions =
env('NODE_ENV') === 'development'
? undefined
: {
SES: {
ses: new aws.SES({
apiVersion: '2010-12-01',
region: env('AWS_REGION'),
credentials: {
accessKeyId: env('AWS_ACCESS_KEY_ID'),
secretAccessKey: env('AWS_SECRET_ACCESS_KEY')
}
}),
aws
},
// max 14 messages per second to comply with AWS SES
sendingRate: 14
};
const isDev = env('NODE_ENV') === 'development';

return {
'users-permissions': {
config: {
Expand All @@ -39,7 +18,20 @@ export default ({env}) => {
config: {
provider: 'nodemailer',
providerOptions: {
...emailProviderOptions
SES: {
ses: new aws.SES({
endpoint: env('LOCALSTACK_ENDPOINT'),
apiVersion: '2010-12-01',
region: env('AWS_REGION'),
credentials: {
accessKeyId: env('AWS_ACCESS_KEY_ID'),
secretAccessKey: env('AWS_SECRET_ACCESS_KEY')
}
}),
aws
},
// max 14 messages per second to comply with AWS SES
sendingRate: 14
},
settings: {
defaultFrom: env('MAIL_FROM'),
Expand All @@ -51,9 +43,25 @@ export default ({env}) => {
config: {
provider: 'aws-s3',
providerOptions: {
baseUrl: env('STATIC_CONTENT_BASE_URL'),
/*
* The base URL on production uses a dedicated subdomain which is linked to AWS S3 bucket via CNAME DNS record.
**/
baseUrl: isDev
? `${env('STATIC_CONTENT_BASE_URL')}/${env('AWS_S3_BUCKET')}`
: env('STATIC_CONTENT_BASE_URL'),
rootPath: env('STATIC_MEDIA_CONTENT_PATH'),
s3Options: {
/*
* In development we use local AWS - LocalStack.
**/
endpoint: isDev ? env('LOCALSTACK_ENDPOINT') : undefined,
/*
* In development we want to use "Path" style S3 URLs, since
* Docker services run locally are unable to resolve "Virtual-Hosted" style S3 URLs.
* https://docs.localstack.cloud/user-guide/aws/s3/#path-style-and-virtual-hosted-style-requests
*
**/
forcePathStyle: isDev,
credentials: {
accessKeyId: env('AWS_S3_ACCESS_KEY_ID'),
secretAccessKey: env('AWS_S3_ACCESS_SECRET')
Expand Down
26 changes: 26 additions & 0 deletions backend/vaa-strapi/docker-compose.dev.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,26 @@
services:
# LocalStack configuration: https://docs.localstack.cloud/references/configuration/
awslocal:
image: localstack/localstack
ports:
- '127.0.0.1:4566:4566'
environment:
DEBUG: 1
AWS_REGION: ${AWS_REGION}
MAIL_FROM: ${MAIL_FROM}
AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
AWS_S3_ACCESS_KEY_ID: ${AWS_S3_ACCESS_KEY_ID}
AWS_S3_ACCESS_SECRET: ${AWS_S3_ACCESS_SECRET}
AWS_S3_REGION: ${AWS_S3_REGION}
AWS_S3_BUCKET: ${AWS_S3_BUCKET}
volumes:
- awslocal:/var/lib/localstack
- ./localstack-init-aws.sh:/etc/localstack/init/ready.d/init-aws.sh
- ./localstack-s3-cors-policy.json:/etc/localstack/s3-cors-policy.json
# Mounting the Docker socket /var/run/docker.sock as a volume is required for some services
# that use Docker to provide the emulation, such as AWS Lambda.
- '/var/run/docker.sock:/var/run/docker.sock'
strapi:
build:
# Context includes the root of the repository so that we can expose shared/ module.
Expand All @@ -7,6 +29,8 @@ services:
target: development
ports:
- ${STRAPI_PORT}:${STRAPI_PORT}
depends_on:
- 'awslocal'
restart: always
environment:
STRAPI_HOST: ${STRAPI_HOST}
Expand Down Expand Up @@ -36,6 +60,7 @@ services:
AWS_S3_BUCKET: ${AWS_S3_BUCKET}
STATIC_CONTENT_BASE_URL: ${STATIC_CONTENT_BASE_URL}
STATIC_MEDIA_CONTENT_PATH: ${STATIC_MEDIA_CONTENT_PATH}
LOCALSTACK_ENDPOINT: http://awslocal:4566
volumes:
# Creating this volume will make Docker update changes from local automatically
# Note that this only applies to src/, where all the source code is anyway.
Expand Down Expand Up @@ -68,3 +93,4 @@ services:
volumes:
postgres:
strapi-uploads:
awslocal:
6 changes: 6 additions & 0 deletions backend/vaa-strapi/localstack-init-aws.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash
AWS_ACCESS_KEY_ID=$AWS_S3_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY=$AWS_S3_ACCESS_SECRET awslocal s3api create-bucket --bucket $AWS_S3_BUCKET --region $AWS_S3_REGION

AWS_ACCESS_KEY_ID=$AWS_S3_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY=$AWS_S3_ACCESS_SECRET awslocal s3api put-bucket-cors --bucket $AWS_S3_BUCKET --region $AWS_S3_REGION --cors-configuration file:///etc/localstack/s3-cors-policy.json

AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY awslocal ses verify-email-identity --email-address $MAIL_FROM --region $AWS_REGION
11 changes: 11 additions & 0 deletions backend/vaa-strapi/localstack-s3-cors-policy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"CORSRules": [
{
"AllowedHeaders": ["*"],
"AllowedMethods": ["GET", "HEAD"],
"AllowedOrigins": ["*"],
"ExposeHeaders": [],
"MaxAgeSeconds": 3000
}
]
}
2 changes: 1 addition & 1 deletion backend/vaa-strapi/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"@strapi/plugin-documentation": "^4.25.1",
"@strapi/plugin-i18n": "^4.25.1",
"@strapi/plugin-users-permissions": "^4.25.1",
"@strapi/provider-email-nodemailer": "^4.25.1",
"@strapi/provider-email-nodemailer": "^5.0.2",
"@strapi/provider-upload-aws-s3": "^5.0.1",
"@strapi/strapi": "^4.25.1",
"pg": "^8.12.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"name": "Apache 2.0",
"url": "https://www.apache.org/licenses/LICENSE-2.0.html"
},
"x-generation-date": "2024-09-10T08:41:53.329Z"
"x-generation-date": "2024-10-08T22:09:53.144Z"
},
"x-strapi-config": {
"path": "/documentation",
Expand Down
Loading
Loading