diff --git a/.github/mergify.yml b/.github/mergify.yml index abb7e6dda8..513294bcdb 100644 --- a/.github/mergify.yml +++ b/.github/mergify.yml @@ -11,7 +11,7 @@ pull_request_rules: - check-success~=CodeQL # CodeQL code scanning results - check-success~=GitGuardian - check-success~=Semantic Pull Request - - check-success~=Travis CI - Branch + - check-success~=build_deploy_application - check-success~=coverage/coveralls - check-success~=license/snyk - check-success~=security/snyk @@ -32,7 +32,7 @@ pull_request_rules: - check-success~=CodeQL # CodeQL code scanning results - check-success~=GitGuardian - check-success~=Semantic Pull Request - - check-success~=Travis CI - Branch + - check-success~=build_deploy_application - check-success~=coverage/coveralls - check-success~=license/snyk - check-success~=security/snyk diff --git a/.github/semantic.yml b/.github/semantic.yml new file mode 100644 index 0000000000..df365dc030 --- /dev/null +++ b/.github/semantic.yml @@ -0,0 +1,18 @@ +# Always validate the PR title, and ignore the commits +# since we only squash commits +titleOnly: true + +types: + - feat + - fix + - docs + - style + - refactor + # alias of refactor + - ref + - perf + - test + - build + - ci + - chore + - revert diff --git a/.github/workflows/deploy-eb.yml b/.github/workflows/deploy-eb.yml new file mode 100644 index 0000000000..d27e932649 --- /dev/null +++ b/.github/workflows/deploy-eb.yml @@ -0,0 +1,88 @@ +name: Deploy to AWS Elastic Beanstalk +on: + push: + branches: # There should be 4 environments in github actions secrets: release, staging, staging-alt, uat. This is different from the DEPLOY_ENV secret which corresponds to elastic beanstalk environment name + - release + - staging + - staging-alt + - uat + +jobs: + set_environment: + outputs: + current_env: ${{ steps.set-environment.outputs.current_env }} + runs-on: ubuntu-latest + steps: + - id: set-environment + run: echo "::set-output name=current_env::${{github.ref_name}}" + + build_deploy_application: + needs: set_environment + environment: + name: ${{ needs.set_environment.outputs.current_env }} + env: + IMAGE_TAG: github-actions-${{ github.sha }}-${{ github.run_id }}-${{github.run_attempt}} + BRANCH: ${{ needs.set_environment.outputs.current_env }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: '14' + cache: 'npm' + - name: Build + env: + NODE_OPTIONS: '--max-old-space-size=4096' + run: | + npm ci + set -e + npm_config_mode=yes npx lockfile-lint --type npm --path package.json --validate-https --allowed-hosts npm + npm run lint-ci + npm run build + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_DEFAULT_REGION }} + + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v1 + + - name: Build, tag, and push image to Amazon ECR + env: + ECR_REPOSITORY: ${{ secrets.ECR_REPO }} + run: | + docker build -f Dockerfile.production -t $ECR_REPOSITORY:$IMAGE_TAG . + docker tag $ECR_REPOSITORY:$IMAGE_TAG $ECR_REPOSITORY:$BRANCH + docker push -a $ECR_REPOSITORY + sed -i -e "s/@TAG/$IMAGE_TAG/g" Dockerrun.aws.json + zip -r "$IMAGE_TAG.zip" .ebextensions Dockerrun.aws.json + + - name: Copy to S3 + env: + BUCKET_NAME: ${{ secrets.BUCKET_NAME }} + run: | + aws s3 cp $IMAGE_TAG.zip s3://$BUCKET_NAME/$IMAGE_TAG.zip + + - name: Create application version + env: + BUCKET_NAME: ${{ secrets.BUCKET_NAME }} + APP_NAME: ${{ secrets.APP_NAME }} + run: | + aws elasticbeanstalk create-application-version --application-name $APP_NAME \ + --version-label $IMAGE_TAG \ + --source-bundle S3Bucket=$BUCKET_NAME,S3Key=$IMAGE_TAG.zip \ + --description "${{ github.event.head_commit.message }}" + + - name: Update EB environment + id: update-eb-1 + env: + APP_NAME: ${{ secrets.APP_NAME }} + DEPLOY_ENV: ${{ secrets.DEPLOY_ENV }} + run: | + aws elasticbeanstalk update-environment --application-name $APP_NAME \ + --environment-name $DEPLOY_ENV \ + --version-label $IMAGE_TAG diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index c9579ca61b..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,123 +0,0 @@ -os: linux -dist: xenial - -services: - - xvfb - -language: node_js -node_js: '14' -install: true # skip installation, perform in build stage. - -notifications: - email: - recipients: - # Please change to your own email recipient if you are forking this - # repository. - - formsg@data.gov.sg - on_success: always - on_failure: always - -jobs: - include: - - stage: Build application - install: npm ci - cache: - - npm - - pip - before_script: - - export NODE_OPTIONS=--max-old-space-size=4096 - script: - - set -e - - npm_config_mode=yes npx lockfile-lint --type npm --path package.json --validate-https --allowed-hosts npm - - npm run lint-ci - - npm run build - workspaces: - create: - name: build - paths: . - - stage: Deploy - services: - - docker - workspaces: - use: build - script: skip - before_deploy: - # Workaround to run before_deploy only once - - > - if ! [ "$TAG" ]; then - pip install --user awscli - # Put AWS in path - export PATH=$PATH:$HOME/.local/bin - # Login to AWS ECR, credentials defined in $AWS_ACCESS_KEY_ID and $AWS_SECRET_ACCESS_KEY - $(aws ecr get-login --no-include-email --region ap-southeast-1) - export TAG=travis-$TRAVIS_COMMIT-$TRAVIS_BUILD_NUMBER - docker build -f Dockerfile.production -t $REPO:$TAG . - docker tag $REPO:$TAG $REPO:$TRAVIS_BRANCH - docker push $REPO - # Add TAG to Dockerrun - sed -i -e "s/@TAG/$TAG/g" Dockerrun.aws.json - zip -r "$TAG.zip" .ebextensions Dockerrun.aws.json - fi - - export ELASTIC_BEANSTALK_LABEL="$TAG-$(env TZ=Asia/Singapore date "+%Y%m%d%H%M%S")" - deploy: - - provider: elasticbeanstalk - skip_cleanup: true - access_key_id: $AWS_ACCESS_KEY_ID - secret_access_key: $AWS_SECRET_ACCESS_KEY - region: $AWS_REGION - app: $STAGING_APP_NAME - env: $UAT_DEPLOY_ENV - bucket: $STAGING_BUCKET_NAME - zip_file: '$TAG.zip' - on: - branch: $UAT_BRANCH - - - provider: elasticbeanstalk - skip_cleanup: true - access_key_id: $AWS_ACCESS_KEY_ID - secret_access_key: $AWS_SECRET_ACCESS_KEY - region: $AWS_REGION - app: $STAGING_APP_NAME - env: $STAGING_DEPLOY_ENV - bucket: $STAGING_BUCKET_NAME - zip_file: '$TAG.zip' - on: - branch: $STAGING_BRANCH - - - provider: elasticbeanstalk - skip_cleanup: true - access_key_id: $AWS_ACCESS_KEY_ID - secret_access_key: $AWS_SECRET_ACCESS_KEY - region: $AWS_REGION - app: $STAGING_APP_NAME - env: $STAGING_ALT_DEPLOY_ENV - bucket: $STAGING_BUCKET_NAME - zip_file: '$TAG.zip' - on: - branch: $STAGING_ALT_BRANCH - - - provider: elasticbeanstalk - skip_cleanup: true - access_key_id: $AWS_ACCESS_KEY_ID - secret_access_key: $AWS_SECRET_ACCESS_KEY - region: $AWS_REGION - app: $PROD_APP_NAME - env: $PROD_DEPLOY_ENV - bucket: $PROD_BUCKET_NAME - zip_file: '$TAG.zip' - on: - branch: $PROD_BRANCH - - after_deploy: - - > - if [[ "$SENTRY_PROJECT" && "$SENTRY_AUTH_TOKEN" && "$SENTRY_ORG" && "$SENTRY_URL" ]]; then - curl -sL https://sentry.io/get-cli/ | bash - sentry-cli releases --org $SENTRY_ORG --project $SENTRY_PROJECT new "$TAG" - sentry-cli releases files "$TAG" upload-sourcemaps ./ --rewrite --ignore-file .sentryignore - sentry-cli releases finalize "$TAG" - fi - -stages: - - Build application - - Tests - - Deploy diff --git a/CHANGELOG.md b/CHANGELOG.md index cc0c4ff18e..e182d73a50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,65 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [v5.36.0](https://github.com/opengovsg/FormSG/compare/v5.35.0...v5.36.0) + +- feat: migrate CI pipeline to github actions [`#3120`](https://github.com/opengovsg/FormSG/pull/3120) +- fix(deps): bump aws-sdk from 2.1039.0 to 2.1040.0 [`#3123`](https://github.com/opengovsg/FormSG/pull/3123) +- chore(deps-dev): bump type-fest from 2.6.0 to 2.8.0 [`#3122`](https://github.com/opengovsg/FormSG/pull/3122) +- fix(deps): bump angular-ui-router from 1.0.29 to 1.0.30 [`#3121`](https://github.com/opengovsg/FormSG/pull/3121) +- docs: update README.md to bring webhooks out of beta [`#3108`](https://github.com/opengovsg/FormSG/pull/3108) +- chore(ci): add semantic.yml to modify CI behaviour [`#3109`](https://github.com/opengovsg/FormSG/pull/3109) +- fix(deps): bump aws-sdk from 2.1037.0 to 2.1039.0 [`#3118`](https://github.com/opengovsg/FormSG/pull/3118) +- fix(deps): bump date-fns from 2.26.0 to 2.27.0 [`#3117`](https://github.com/opengovsg/FormSG/pull/3117) +- chore(deps-dev): bump core-js from 3.19.1 to 3.19.2 [`#3115`](https://github.com/opengovsg/FormSG/pull/3115) +- chore(deps-dev): bump jest-extended from 1.1.0 to 1.2.0 [`#3114`](https://github.com/opengovsg/FormSG/pull/3114) +- chore(deps-dev): bump htmlhint from 0.16.3 to 1.0.0 [`#3105`](https://github.com/opengovsg/FormSG/pull/3105) +- fix(deps): bump aws-sdk from 2.1036.0 to 2.1037.0 [`#3106`](https://github.com/opengovsg/FormSG/pull/3106) +- fix(deps): bump nodemailer from 6.7.1 to 6.7.2 [`#3104`](https://github.com/opengovsg/FormSG/pull/3104) +- chore(deps-dev): bump prettier from 2.4.1 to 2.5.0 [`#3102`](https://github.com/opengovsg/FormSG/pull/3102) +- fix(deps): bump aws-sdk from 2.1035.0 to 2.1036.0 [`#3101`](https://github.com/opengovsg/FormSG/pull/3101) +- fix(deps): bump aws-sdk from 2.1034.0 to 2.1035.0 [`#3097`](https://github.com/opengovsg/FormSG/pull/3097) +- chore(deps-dev): bump htmlhint from 0.16.1 to 0.16.3 [`#3098`](https://github.com/opengovsg/FormSG/pull/3098) +- fix(deps): bump aws-sdk from 2.1033.0 to 2.1034.0 [`#3096`](https://github.com/opengovsg/FormSG/pull/3096) +- chore(deps-dev): bump eslint-plugin-jest from 25.2.4 to 25.3.0 [`#3095`](https://github.com/opengovsg/FormSG/pull/3095) +- chore(deps-dev): bump type-fest from 2.5.4 to 2.6.0 [`#3094`](https://github.com/opengovsg/FormSG/pull/3094) +- chore(deps-dev): bump lint-staged from 12.1.1 to 12.1.2 [`#3089`](https://github.com/opengovsg/FormSG/pull/3089) +- chore: merge release v5.35.0 back to develop [`#3057`](https://github.com/opengovsg/FormSG/pull/3057) +- chore(deps-dev): bump csv-parse from 5.0.2 to 5.0.3 [`#3085`](https://github.com/opengovsg/FormSG/pull/3085) +- fix(deps): bump date-fns from 2.25.0 to 2.26.0 [`#3084`](https://github.com/opengovsg/FormSG/pull/3084) +- chore(deps-dev): bump lint-staged from 12.0.3 to 12.1.1 [`#3088`](https://github.com/opengovsg/FormSG/pull/3088) +- fix(deps): bump neverthrow from 4.3.0 to 4.3.1 [`#3087`](https://github.com/opengovsg/FormSG/pull/3087) +- fix(deps): bump aws-sdk from 2.1032.0 to 2.1033.0 [`#3086`](https://github.com/opengovsg/FormSG/pull/3086) +- fix(deps): bump cookie-parser from 1.4.5 to 1.4.6 [`#3071`](https://github.com/opengovsg/FormSG/pull/3071) +- chore(deps-dev): bump csv-parse from 4.16.3 to 5.0.2 [`#3072`](https://github.com/opengovsg/FormSG/pull/3072) +- chore(deps-dev): bump lint-staged from 12.0.2 to 12.0.3 [`#3083`](https://github.com/opengovsg/FormSG/pull/3083) +- chore(deps-dev): bump core-js from 3.19.0 to 3.19.1 [`#3082`](https://github.com/opengovsg/FormSG/pull/3082) +- fix(deps): bump aws-sdk from 2.1031.0 to 2.1032.0 [`#3081`](https://github.com/opengovsg/FormSG/pull/3081) +- chore(deps-dev): bump @types/node from 14.17.33 to 14.17.34 [`#3080`](https://github.com/opengovsg/FormSG/pull/3080) +- chore(deps-dev): bump @types/jest from 27.0.2 to 27.0.3 [`#3079`](https://github.com/opengovsg/FormSG/pull/3079) +- chore(deps-dev): bump htmlhint from 0.16.0 to 0.16.1 [`#3076`](https://github.com/opengovsg/FormSG/pull/3076) +- chore(deps-dev): bump @types/validator from 13.6.6 to 13.7.0 [`#3078`](https://github.com/opengovsg/FormSG/pull/3078) +- fix(deps): bump express-rate-limit from 5.5.0 to 5.5.1 [`#3077`](https://github.com/opengovsg/FormSG/pull/3077) +- chore(deps-dev): bump typescript from 4.4.4 to 4.5.2 [`#3074`](https://github.com/opengovsg/FormSG/pull/3074) +- chore(deps-dev): bump @types/uuid from 8.3.1 to 8.3.3 [`#3075`](https://github.com/opengovsg/FormSG/pull/3075) +- chore(deps-dev): bump concurrently from 6.3.0 to 6.4.0 [`#3073`](https://github.com/opengovsg/FormSG/pull/3073) +- fix(deps): bump twilio from 3.71.1 to 3.71.2 [`#3069`](https://github.com/opengovsg/FormSG/pull/3069) +- fix(deps): bump aws-sdk from 2.1019.0 to 2.1031.0 [`#3068`](https://github.com/opengovsg/FormSG/pull/3068) +- chore(deps-dev): bump eslint-plugin-jest from 25.2.2 to 25.2.4 [`#3066`](https://github.com/opengovsg/FormSG/pull/3066) +- chore(deps-dev): bump @babel/plugin-transform-runtime [`#3063`](https://github.com/opengovsg/FormSG/pull/3063) +- fix(deps): bump @sentry/integrations from 6.13.3 to 6.15.0 [`#3065`](https://github.com/opengovsg/FormSG/pull/3065) +- chore(deps-dev): bump @types/node from 14.17.32 to 14.17.33 [`#3064`](https://github.com/opengovsg/FormSG/pull/3064) +- chore(deps-dev): bump eslint-plugin-import from 2.25.2 to 2.25.3 [`#3062`](https://github.com/opengovsg/FormSG/pull/3062) +- fix(deps): bump libphonenumber-js from 1.9.39 to 1.9.43 [`#3061`](https://github.com/opengovsg/FormSG/pull/3061) +- chore(deps-dev): bump @babel/preset-env from 7.16.0 to 7.16.4 [`#3060`](https://github.com/opengovsg/FormSG/pull/3060) +- chore(deps-dev): bump type-fest from 2.5.2 to 2.5.4 [`#3059`](https://github.com/opengovsg/FormSG/pull/3059) +- fix(deps): bump bson-ext from 2.0.5 to 2.0.6 [`#3058`](https://github.com/opengovsg/FormSG/pull/3058) +- build: release v5.35.0 [`#3056`](https://github.com/opengovsg/FormSG/pull/3056) + #### [v5.35.0](https://github.com/opengovsg/FormSG/compare/v5.34.0...v5.35.0) +> 17 November 2021 + - fix(deps): bump @sentry/browser from 6.13.3 to 6.15.0 [`#3052`](https://github.com/opengovsg/FormSG/pull/3052) - fix(deps): bump web-streams-polyfill from 3.1.1 to 3.2.0 [`#3051`](https://github.com/opengovsg/FormSG/pull/3051) - fix(deps): bump moment-timezone from 0.5.33 to 0.5.34 [`#3053`](https://github.com/opengovsg/FormSG/pull/3053) @@ -17,6 +74,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - chore: merge release v5.34.0 back to develop [`#3043`](https://github.com/opengovsg/FormSG/pull/3043) - build: release v5.34.0 [`#3042`](https://github.com/opengovsg/FormSG/pull/3042) - build: Release 5.33.0 [`#3014`](https://github.com/opengovsg/FormSG/pull/3014) +- chore: bump version to v5.35.0 [`567478d`](https://github.com/opengovsg/FormSG/commit/567478d0bda03f898780b31051a17dd837106c35) #### [v5.34.0](https://github.com/opengovsg/FormSG/compare/v5.33.0...v5.34.0) @@ -905,7 +963,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - fix(verification): loosen OTP waiting time by 2 seconds [`#1957`](https://github.com/opengovsg/FormSG/pull/1957) - chore: bump version to 5.12.0 [`85759bc`](https://github.com/opengovsg/FormSG/commit/85759bc9dc01f73da3cbd0ec73c636e58e983948) -#### [v5.11.0](https://github.com/opengovsg/FormSG/compare/v5.10.1...v5.11.0) +#### [v5.11.0](https://github.com/opengovsg/FormSG/compare/v5.10.0...v5.11.0) > 25 May 2021 @@ -973,11 +1031,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - chore(deps-dev): bump @typescript-eslint/eslint-plugin [`#1868`](https://github.com/opengovsg/FormSG/pull/1868) - fix(deps): bump @sentry/integrations from 6.3.5 to 6.3.6 [`#1850`](https://github.com/opengovsg/FormSG/pull/1850) - chore: bump version to 5.11.0 [`54b1958`](https://github.com/opengovsg/FormSG/commit/54b1958d0968e670ef145461d9d7859384d573ef) - -#### [v5.10.1](https://github.com/opengovsg/FormSG/compare/v5.10.0...v5.10.1) - -> 17 May 2021 - - chore: bump version to v5.10.1 [`0442cd7`](https://github.com/opengovsg/FormSG/commit/0442cd72637019fb1e43bce5f8f5abe14ee79f8c) - fix: allow for unknown keys in updateEndPage validator [`617d86a`](https://github.com/opengovsg/FormSG/commit/617d86a28910eec6ebd3249a2de636086429d6a6) diff --git a/README.md b/README.md index c5839949d0..bd5efb8e73 100755 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # FormSG -[![Build Status](https://travis-ci.com/opengovsg/formsg.svg?branch=release)](https://travis-ci.com/opengovsg/formsg) +[![Build Status](https://github.com/opengovsg/FormSG/actions/workflows/deploy-eb.yml)](https://github.com/opengovsg/FormSG/actions/workflows/deploy-eb.yml) [![Coverage Status](https://coveralls.io/repos/github/opengovsg/FormSG/badge.svg?branch=develop)](https://coveralls.io/github/opengovsg/FormSG?branch=develop) ## Table of Contents @@ -37,7 +37,7 @@ Notable features include: - (Singapore government agencies only) Citizen authentication with [SingPass](https://www.singpass.gov.sg/singpass/common/aboutus) - (Singapore government agencies only) Corporate authentication with [CorpPass](https://www.corppass.gov.sg/corppass/common/aboutus) - (Singapore government agencies only) Automatic prefill of verified data with [MyInfo](https://www.singpass.gov.sg/myinfo/common/aboutus) -- (beta) Webhooks functionality via the [FormSG JavaScript SDK](https://github.com/opengovsg/formsg-sdk). +- Webhooks functionality via the official [FormSG JavaScript SDK](https://github.com/opengovsg/formsg-sdk) and contributor-supported [FormSG Ruby SDK] (https://github.com/opengovsg/formsg-ruby-sdk) The current product roadmap includes: diff --git a/docs/DEPLOYMENT_SETUP.md b/docs/DEPLOYMENT_SETUP.md index d9bee23381..71088f256c 100644 --- a/docs/DEPLOYMENT_SETUP.md +++ b/docs/DEPLOYMENT_SETUP.md @@ -23,7 +23,7 @@ Infrastructure DevOps -- TravisCI for running tests and builds +- Github Actions for running tests and builds - AWS Elastic Container Registry to host built Docker images Network @@ -76,32 +76,22 @@ Secondly, edit the form document belonging to that specific form adminstrator by If no `msgSrvcName` is found in the form document, SMSes associated with that form will be sent out using and charged to the default Twilio API credentials. -### Travis CI/CD environment variables +### Github Actions Secrets -For more information about the various environment variables, please refer to -[Travis documentation](https://docs.travis-ci.com/user/deployment/elasticbeanstalk/). - -The following env variables are set in Travis: -| Variable | Description| +The following repository secrets are set in Github Actions: +| Secret | Description| |:---------|------------| -|`REPO`|The repository of the AWS Elastic Container Registry| -|`STAGING_BRANCH`|Name of staging branch, usually `master`.| -|`STAGING_ALT_BRANCH`|Name of staging-alt (if any) branch, usually `release`. An alternate staging branch is used to host diverging feature sets, useful for A/B testing.| -|`PROD_BRANCH`|Name of production branch, usually `release`.| |`AWS_ACCESS_KEY_ID`|AWS IAM access key ID used to deploy.| |`AWS_SECRET_ACCESS_KEY`|AWS IAM access secret used to deploy.| -|`AWS_REGION`|AWS region to use.| -|`PROD_APP_NAME`|The names of the deployed docker application for the production application on AWS as determined by `PROD_BRANCH`.| -|`STAGING_APP_NAME`|The names of the deployed docker application for the staging application on AWS as determined by `STAGING_BRANCH`.| -|`PROD_BUCKET_NAME`|Bucket name to upload the code of the production app to. Elastic Beanstalk will create and deploy an application version from the source bundle in this Amazon S3 bucket.| -|`STAGING_BUCKET_NAME`|Bucket name to upload the code of the staging app to. Elastic Beanstalk will create and deploy an application version from the source bundle in this Amazon S3 bucket.| -|`PROD_DEPLOY_ENV`|The name of the Elastic Beanstalk environment the production application will be deployed to.| -|`STAGING_DEPLOY_ENV`|The name of the Elastic Beanstalk environment the staging application will be deployed to.| -|`STAGING_ALT_DEPLOY_ENV`|The name of the Elastic Beanstalk environment the staging-alt application will be deployed to.| -|`SENTRY_ORG`|Organisation that source-maps should be linked to on sentry dashboard.| -|`SENTRY_AUTH_TOKEN`|Authentication token used by sentry cli to authenticate with sentry service.| -|`SENTRY_PROJECT`|Project that source-maps should be linked to on sentry dashboard.| -|`SENTRY_URL`|Sentry service that source-maps should be pushed to.| +|`AWS_DEFAULT_REGION`|AWS region to use.| +|`ECR_REPO`|ECR Repository which stores the docker images.| +|`BUCKET_NAME`| S3 Bucket used to store zipped `Dockerrun.aws.json`.| + +There are also environment secrets for each environment (`staging`, `staging-alt`, `release`, `uat`): +| Secret | Description| +|:---------|------------| +|`APP_NAME`|Application name for the environment.| +|`DEPLOY_ENV`|Deployment environment on elastic beanstalk.| ## Environment Variables diff --git a/package-lock.json b/package-lock.json index 2adc7ca426..ada101f84b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "FormSG", - "version": "5.35.0", + "version": "5.36.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -6007,29 +6007,6 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.34.tgz", "integrity": "sha512-USUftMYpmuMzeWobskoPfzDi+vkpe0dvcOBRNOscFrGxVp4jomnRxWuVohgqBow2xyIPC0S3gjxV/5079jhmDg==" }, - "@types/node-fetch": { - "version": "2.5.12", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.12.tgz", - "integrity": "sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw==", - "dev": true, - "requires": { - "@types/node": "*", - "form-data": "^3.0.0" - }, - "dependencies": { - "form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - } - } - }, "@types/nodemailer": { "version": "6.4.4", "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.4.tgz", @@ -6418,9 +6395,9 @@ } }, "@uirouter/core": { - "version": "6.0.7", - "resolved": "https://registry.npmjs.org/@uirouter/core/-/core-6.0.7.tgz", - "integrity": "sha512-KUTJxL+6q0PiBnFx4/Z+Hsyg0pSGiaW5yZQeJmUxknecjpTbnXkLU8H2EqRn9N2B+qDRa7Jg8RcgeNDPY72O1w==" + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/@uirouter/core/-/core-6.0.8.tgz", + "integrity": "sha512-Gc/BAW47i4L54p8dqYCJJZuv2s3tqlXQ0fvl6Zp2xrblELPVfxmjnc0eurx3XwfQdaqm3T6uls6tQKkof/4QMw==" }, "@webassemblyjs/ast": { "version": "1.9.0", @@ -6818,11 +6795,11 @@ "integrity": "sha512-yzcHpPMLQl0232nDzm5P4iAFTFQ9dMw0QgFLuKYbDj9M0xJ62z0oudYD/Lvh1pWfRsukiytP4Xj6BHOSrSXP8A==" }, "angular-ui-router": { - "version": "1.0.29", - "resolved": "https://registry.npmjs.org/angular-ui-router/-/angular-ui-router-1.0.29.tgz", - "integrity": "sha512-VurVxwueqEFD0JJBHkATOvLinhebc8/052jyhYrFVbHtWEc//IX4Wr55WvmJoTZJ6lnQ3nBlpX9VBKS5wiRsOg==", + "version": "1.0.30", + "resolved": "https://registry.npmjs.org/angular-ui-router/-/angular-ui-router-1.0.30.tgz", + "integrity": "sha512-8xMpxbOtCJbRnGR1fhbyZ5BhFXr3zs1L2ytXQiBACTJjot309QNFFCaWx0lDM2eVXp8qte4idigU9gwWdspmtQ==", "requires": { - "@uirouter/core": "6.0.7" + "@uirouter/core": "6.0.8" } }, "ansi-colors": { @@ -7323,9 +7300,9 @@ "integrity": "sha512-24q5Rh3bno7ldoyCq99d6hpnLI+PAMocdeVaaGt/5BTQMprvDwQToHfNnruqN11odCHZZIQbRBw+nZo1lTCH9g==" }, "aws-sdk": { - "version": "2.1033.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1033.0.tgz", - "integrity": "sha512-cgcjiuR82bhfBWTffqt6e9+Cn/UgeC6QPQTrlJy3GxwPxChthyrt/h5pekj2l4PLFvETsG10Y6CqQysJEMsncw==", + "version": "2.1040.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1040.0.tgz", + "integrity": "sha512-xGKYoVNFA46gphJZ5jRykxT96L3YNMO/STmjdW/cl36n61ENfTvH61OO5v2ReoAoReddAV7F0WMXfkzwjYc5Jw==", "requires": { "buffer": "4.9.2", "events": "1.1.1", @@ -9667,9 +9644,9 @@ } }, "core-js": { - "version": "3.19.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.19.1.tgz", - "integrity": "sha512-Tnc7E9iKd/b/ff7GFbhwPVzJzPztGrChB8X8GLqoYGdEOG8IpLnK1xPyo3ZoO3HsK6TodJS58VGPOxA+hLHQMg==", + "version": "3.19.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.19.2.tgz", + "integrity": "sha512-ciYCResnLIATSsXuXnIOH4CbdfgV+H1Ltg16hJFN7/v6OxqnFr/IFGeLacaZ+fHLAm0TBbXwNK9/DNBzBUrO/g==", "dev": true }, "core-js-compat": { @@ -10219,9 +10196,9 @@ } }, "date-fns": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.26.0.tgz", - "integrity": "sha512-VQI812dRi3cusdY/fhoBKvc6l2W8BPWU1FNVnFH9Nttjx4AFBRzfSVb/Eyc7jBT6e9sg1XtAGsYpBQ6c/jygbg==" + "version": "2.27.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.27.0.tgz", + "integrity": "sha512-sj+J0Mo2p2X1e306MHq282WS4/A8Pz/95GIFcsPNMPMZVI3EUrAdSv90al1k+p74WGLCruMXk23bfEDZa71X9Q==" }, "dayjs": { "version": "1.10.7", @@ -11796,9 +11773,9 @@ } }, "eslint-plugin-jest": { - "version": "25.2.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.2.4.tgz", - "integrity": "sha512-HRyinpgmEdkVr7pNPaYPHCoGqEzpgk79X8pg/xCeoAdurbyQjntJQ4pTzHl7BiVEBlam/F1Qsn+Dk0HtJO7Aaw==", + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.3.0.tgz", + "integrity": "sha512-79WQtuBsTN1S8Y9+7euBYwxIOia/k7ykkl9OCBHL3xuww5ecursHy/D8GCIlvzHVWv85gOkS5Kv6Sh7RxOgK1Q==", "dev": true, "requires": { "@typescript-eslint/experimental-utils": "^5.0.0" @@ -13504,7 +13481,8 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true + "dev": true, + "optional": true }, "handlebars": { "version": "4.7.7", @@ -13877,16 +13855,15 @@ "dev": true }, "htmlhint": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/htmlhint/-/htmlhint-0.16.1.tgz", - "integrity": "sha512-5uxZsGTC8ILh9W9K/7eJ2pCfP7Hj4VEF2wLlm56qhMvvnXbzfgdRgSwBPqtY46jSWWJAv9J1SegFLI3xfwIteQ==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/htmlhint/-/htmlhint-1.0.0.tgz", + "integrity": "sha512-Z+8hVuoHHRoWRUMWE7ehtNVJbED/sbmIFN/azvNnBMliF9vgdTISdATUnPvA1Y5B6FV4tDPFCMrJ5+gvKIZ2rQ==", "dev": true, "requires": { - "@types/node-fetch": "^2.5.12", - "async": "3.2.0", - "chalk": "4.1.0", - "commander": "5.1.0", - "glob": "7.1.7", + "async": "3.2.2", + "chalk": "^4.1.2", + "commander": "^8.3.0", + "glob": "^7.2.0", "node-fetch": "^2.6.2", "parse-glob": "3.0.4", "strip-json-comments": "3.1.0", @@ -13903,15 +13880,15 @@ } }, "async": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", - "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.2.tgz", + "integrity": "sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g==", "dev": true }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -13934,15 +13911,15 @@ "dev": true }, "commander": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", "dev": true }, "glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -14828,6 +14805,7 @@ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, + "optional": true, "requires": { "is-docker": "^2.0.0" } @@ -15392,9 +15370,9 @@ } }, "jest-extended": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jest-extended/-/jest-extended-1.1.0.tgz", - "integrity": "sha512-rC1U9N4SYSFEiHJP3H0ZSbVAARwnjzBOFoluuFYePATsOJaX7PMMNiM9svS4WTgSNCIIVT3RWlWy+Y4W3zLsjg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/jest-extended/-/jest-extended-1.2.0.tgz", + "integrity": "sha512-KYc5DgD+/8viJSEKBzb1vRXe/rEEQUxEovBTdNEer9A6lzvHvhuyslM5tQFBz8TbLEkicCmsEcQF+4N7GiPTLg==", "dev": true, "requires": { "expect": "^26.6.2", @@ -15404,9 +15382,9 @@ }, "dependencies": { "@jest/types": { - "version": "27.2.5", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.2.5.tgz", - "integrity": "sha512-nmuM4VuDtCZcY+eTpw+0nvstwReMsjPoj7ZR80/BbixulhLaiX+fbv8oeLW8WZlJMcsGQsTmMKT/iTZu1Uy/lQ==", + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.0.tgz", + "integrity": "sha512-jIsLdASXMf8GS7P7oGFGwobNse/6Ewq3GBPHoo0i6XRmja+NrUoDqJm4a1ffF2bHGleKJizxokcp1sCqSktP3g==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", @@ -15466,9 +15444,9 @@ "dev": true }, "diff-sequences": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz", - "integrity": "sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==", + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.4.0.tgz", + "integrity": "sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww==", "dev": true }, "has-flag": { @@ -15478,42 +15456,42 @@ "dev": true }, "jest-diff": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.3.1.tgz", - "integrity": "sha512-PCeuAH4AWUo2O5+ksW4pL9v5xJAcIKPUPfIhZBcG1RKv/0+dvaWTQK1Nrau8d67dp65fOqbeMdoil+6PedyEPQ==", + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.4.0.tgz", + "integrity": "sha512-fdXgpnyQH4LNSnYgRfHN/g413bqbPspWIAZPlXrdNISehDih1VNDtuRvlzGQJ4Go+fur1HKB2IyI25t6cWi5EA==", "dev": true, "requires": { "chalk": "^4.0.0", - "diff-sequences": "^27.0.6", - "jest-get-type": "^27.3.1", - "pretty-format": "^27.3.1" + "diff-sequences": "^27.4.0", + "jest-get-type": "^27.4.0", + "pretty-format": "^27.4.0" } }, "jest-get-type": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.3.1.tgz", - "integrity": "sha512-+Ilqi8hgHSAdhlQ3s12CAVNd8H96ZkQBfYoXmArzZnOfAtVAJEiPDBirjByEblvG/4LPJmkL+nBqPO3A1YJAEg==", + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", + "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", "dev": true }, "jest-matcher-utils": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.3.1.tgz", - "integrity": "sha512-hX8N7zXS4k+8bC1Aj0OWpGb7D3gIXxYvPNK1inP5xvE4ztbz3rc4AkI6jGVaerepBnfWB17FL5lWFJT3s7qo8w==", + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.4.0.tgz", + "integrity": "sha512-vBy1tEyuKiItYgV9x9ubccyadOy5xAAmDBgXk8dMppXBXG4glggrGcZvE+8l1r+te477bRcFLB/hRyGm5Tdxzw==", "dev": true, "requires": { "chalk": "^4.0.0", - "jest-diff": "^27.3.1", - "jest-get-type": "^27.3.1", - "pretty-format": "^27.3.1" + "jest-diff": "^27.4.0", + "jest-get-type": "^27.4.0", + "pretty-format": "^27.4.0" } }, "pretty-format": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.3.1.tgz", - "integrity": "sha512-DR/c+pvFc52nLimLROYjnXPtolawm+uWDxr4FjuLDLUn+ktWnSN851KoHwHzzqq6rfCOjkzN8FLgDrSub6UDuA==", + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.0.tgz", + "integrity": "sha512-n0QR6hMREfp6nLzfVksXMAfIxk1ffOOfbb/FzKHFmRtn9iJKaZXB8WMzLr8a72IASShEAhqK06nlwp1gVWgqKg==", "dev": true, "requires": { - "@jest/types": "^27.2.5", + "@jest/types": "^27.4.0", "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^17.0.1" @@ -16778,9 +16756,9 @@ "dev": true }, "lint-staged": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-12.1.1.tgz", - "integrity": "sha512-zOmteWgJwTfZXcj6vXSnjeDDI/fvkKI2KOqRdc84ZFc2ZMDKXEeiTITtaskE3HiNrHraFmYVBpnMSZHngLoogA==", + "version": "12.1.2", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-12.1.2.tgz", + "integrity": "sha512-bSMcQVqMW98HLLLR2c2tZ+vnDCnx4fd+0QJBQgN/4XkdspGRPc8DGp7UuOEBe1ApCfJ+wXXumYnJmU+wDo7j9A==", "dev": true, "requires": { "cli-truncate": "^3.1.0", @@ -18821,6 +18799,7 @@ "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz", "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==", "dev": true, + "optional": true, "requires": { "growly": "^1.3.0", "is-wsl": "^2.2.0", @@ -18835,6 +18814,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, + "optional": true, "requires": { "lru-cache": "^6.0.0" } @@ -18844,6 +18824,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "optional": true, "requires": { "isexe": "^2.0.0" } @@ -18857,9 +18838,9 @@ "dev": true }, "nodemailer": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.1.tgz", - "integrity": "sha512-E1C8G3rnXrGjznwGP1k+OrW5k4rl0XtqTEB19f7vtJAMYwfxZVSsAu2iY5xJkrZsbVYr6PwwAwRmFlakPoFC0A==" + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.2.tgz", + "integrity": "sha512-Dz7zVwlef4k5R71fdmxwR8Q39fiboGbu3xgswkzGwczUfjp873rVxt1O46+Fh0j1ORnAC6L9+heI8uUpO6DT7Q==" }, "noop-logger": { "version": "0.1.1", @@ -20236,9 +20217,9 @@ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" }, "prettier": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz", - "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.0.tgz", + "integrity": "sha512-FM/zAKgWTxj40rH03VxzIPdXmj39SwSjwG0heUcNFwI+EMZJnY93yAiKXM3dObIKAM5TA88werc8T/EwhB45eg==", "dev": true }, "prettier-linter-helpers": { @@ -21751,7 +21732,8 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true + "dev": true, + "optional": true }, "side-channel": { "version": "1.0.4", @@ -24811,9 +24793,9 @@ "dev": true }, "type-fest": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.5.4.tgz", - "integrity": "sha512-zyPomVvb6u7+gJ/GPYUH6/nLDNiTtVOqXVUHtxFv5PmZQh6skgfeRtFYzWC01T5KeNWNIx5/0P111rKFLlkFvA==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.8.0.tgz", + "integrity": "sha512-O+V9pAshf9C6loGaH0idwsmugI2LxVNR7DtS40gVo2EXZVYFgz9OuNtOhgHLdHdapOEWNdvz9Ob/eeuaWwwlxA==", "dev": true }, "type-is": { diff --git a/package.json b/package.json index ba165aaa30..92908745ca 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "FormSG", "description": "Form Manager for Government", - "version": "5.35.0", + "version": "5.36.0", "homepage": "https://form.gov.sg", "authors": [ "FormSG " @@ -80,9 +80,9 @@ "angular-translate": "^2.19.0", "angular-translate-loader-partial": "^2.19.0", "angular-ui-bootstrap": "~2.5.6", - "angular-ui-router": "~1.0.29", + "angular-ui-router": "~1.0.30", "aws-info": "^1.2.0", - "aws-sdk": "^2.1033.0", + "aws-sdk": "^2.1040.0", "axios": "^0.24.0", "bcrypt": "^5.0.1", "bluebird": "^3.5.2", @@ -100,7 +100,7 @@ "cookie-parser": "~1.4.6", "css-toggle-switch": "^4.1.0", "csv-string": "^4.0.1", - "date-fns": "^2.26.0", + "date-fns": "^2.27.0", "dedent-js": "~1.0.1", "dotenv": "^10.0.0", "ejs": "^3.1.6", @@ -132,7 +132,7 @@ "ngclipboard": "^2.0.0", "nocache": "^3.0.1", "node-cache": "^5.1.2", - "nodemailer": "^6.7.1", + "nodemailer": "^6.7.2", "opossum": "^6.2.1", "p-queue": "^6.6.2", "promise-retry": "^2.0.1", @@ -201,7 +201,7 @@ "babel-loader": "^8.2.3", "concurrently": "^6.4.0", "copy-webpack-plugin": "^6.0.2", - "core-js": "^3.19.1", + "core-js": "^3.19.2", "coveralls": "^3.1.1", "css-loader": "^2.1.1", "csv-parse": "^5.0.3", @@ -210,7 +210,7 @@ "eslint-config-prettier": "^8.3.0", "eslint-plugin-angular": "^4.1.0", "eslint-plugin-import": "^2.25.3", - "eslint-plugin-jest": "^25.2.4", + "eslint-plugin-jest": "^25.3.0", "eslint-plugin-prettier": "^4.0.0", "eslint-plugin-simple-import-sort": "^7.0.0", "eslint-plugin-typesafe": "^0.5.2", @@ -218,13 +218,13 @@ "form-data": "^4.0.0", "google-fonts-plugin": "4.1.0", "html-loader": "~0.5.5", - "htmlhint": "^0.16.1", + "htmlhint": "^1.0.0", "husky": "^7.0.4", "jest": "^26.6.3", - "jest-extended": "^1.1.0", + "jest-extended": "^1.2.0", "jest-localstorage-mock": "^2.4.18", "jest-mock-axios": "^4.4.1", - "lint-staged": "^12.1.1", + "lint-staged": "^12.1.2", "maildev": "^1.1.0", "mini-css-extract-plugin": "^0.5.0", "mockdate": "^3.0.5", @@ -232,7 +232,7 @@ "mongodb-memory-server-core": "^6.9.6", "ngrok": "^4.2.2", "optimize-css-assets-webpack-plugin": "^5.0.8", - "prettier": "^2.4.1", + "prettier": "^2.5.0", "proxyquire": "^2.1.3", "regenerator": "^0.14.4", "rimraf": "^3.0.2", @@ -249,7 +249,7 @@ "ts-loader": "^7.0.5", "ts-node": "^10.4.0", "ts-node-dev": "^1.1.8", - "type-fest": "^2.5.4", + "type-fest": "^2.8.0", "typescript": "^4.5.2", "url-loader": "^1.1.2", "webpack": "^4.46.0", diff --git a/src/app/modules/bounce/bounce.controller.ts b/src/app/modules/bounce/bounce.controller.ts index 7b0e065500..404cd59568 100644 --- a/src/app/modules/bounce/bounce.controller.ts +++ b/src/app/modules/bounce/bounce.controller.ts @@ -18,104 +18,105 @@ const logger = createLoggerWithLabel(module) * @param req Express request object * @param res - Express response object */ -export const handleSns: ControllerHandler = - async (req, res) => { - const notificationResult = await BounceService.validateSnsRequest( - req.body, - ).andThen(() => BounceService.safeParseNotification(req.body.Message)) - if (notificationResult.isErr()) { - logger.warn({ - message: 'Unable to parse email notification request', - meta: { - action: 'handleSns', - }, - error: notificationResult.error, - }) - return res.sendStatus(StatusCodes.UNAUTHORIZED) - } - const notification = notificationResult.value +export const handleSns: ControllerHandler< + unknown, + never, + ISnsNotification +> = async (req, res) => { + const notificationResult = await BounceService.validateSnsRequest( + req.body, + ).andThen(() => BounceService.safeParseNotification(req.body.Message)) + if (notificationResult.isErr()) { + logger.warn({ + message: 'Unable to parse email notification request', + meta: { + action: 'handleSns', + }, + error: notificationResult.error, + }) + return res.sendStatus(StatusCodes.UNAUTHORIZED) + } + const notification = notificationResult.value - BounceService.logEmailNotification(notification) - // If not admin response, no more action to be taken - if ( - BounceService.extractEmailType(notification) !== EmailType.AdminResponse - ) { - return res.sendStatus(StatusCodes.OK) - } + BounceService.logEmailNotification(notification) + // If not admin response, no more action to be taken + if ( + BounceService.extractEmailType(notification) !== EmailType.AdminResponse + ) { + return res.sendStatus(StatusCodes.OK) + } - const bounceDocResult = await BounceService.getUpdatedBounceDoc( - notification, - ) - if (bounceDocResult.isErr()) { - logger.warn({ - message: 'Error while retrieving or creating new bounce doc', - meta: { - action: 'handleSns', - }, - error: bounceDocResult.error, - }) - return res.sendStatus(StatusCodes.OK) - } - const bounceDoc = bounceDocResult.value + const bounceDocResult = await BounceService.getUpdatedBounceDoc(notification) + if (bounceDocResult.isErr()) { + logger.warn({ + message: 'Error while retrieving or creating new bounce doc', + meta: { + action: 'handleSns', + }, + error: bounceDocResult.error, + }) + return res.sendStatus(StatusCodes.OK) + } + const bounceDoc = bounceDocResult.value - const formResult = await FormService.retrieveFullFormById(bounceDoc.formId) - if (formResult.isErr()) { - // Either database error occurred or the formId saved in the bounce collection - // doesn't exist, so something went wrong. - logger.error({ - message: 'Failed to retrieve form corresponding to bounced formId', - meta: { - action: 'handleSns', - formId: bounceDoc.formId, - }, - }) - return res.sendStatus(StatusCodes.INTERNAL_SERVER_ERROR) - } - const form = formResult.value + const formResult = await FormService.retrieveFullFormById(bounceDoc.formId) + if (formResult.isErr()) { + // Either database error occurred or the formId saved in the bounce collection + // doesn't exist, so something went wrong. + logger.error({ + message: 'Failed to retrieve form corresponding to bounced formId', + meta: { + action: 'handleSns', + formId: bounceDoc.formId, + }, + }) + return res.sendStatus(StatusCodes.INTERNAL_SERVER_ERROR) + } + const form = formResult.value - if (bounceDoc.isCriticalBounce()) { - // Send notifications and deactivate form on best-effort basis, ignore errors - const possibleSmsRecipients = - await BounceService.getEditorsWithContactNumbers(form).unwrapOr([]) - const emailRecipients = await BounceService.sendEmailBounceNotification( - bounceDoc, - form, - ).unwrapOr([]) - const smsRecipients = await BounceService.sendSmsBounceNotification( - bounceDoc, + if (bounceDoc.isCriticalBounce()) { + // Send notifications and deactivate form on best-effort basis, ignore errors + const possibleSmsRecipients = + await BounceService.getEditorsWithContactNumbers(form).unwrapOr([]) + const emailRecipients = await BounceService.sendEmailBounceNotification( + bounceDoc, + form, + ).unwrapOr([]) + const smsRecipients = await BounceService.sendSmsBounceNotification( + bounceDoc, + form, + possibleSmsRecipients, + ).unwrapOr([]) + bounceDoc.setNotificationState(emailRecipients, smsRecipients) + + const shouldDeactivate = bounceDoc.areAllPermanentBounces() + if (shouldDeactivate) { + await FormService.deactivateForm(bounceDoc.formId) + await BounceService.notifyAdminsOfDeactivation( form, possibleSmsRecipients, - ).unwrapOr([]) - bounceDoc.setNotificationState(emailRecipients, smsRecipients) - - const shouldDeactivate = bounceDoc.areAllPermanentBounces() - if (shouldDeactivate) { - await FormService.deactivateForm(bounceDoc.formId) - await BounceService.notifyAdminsOfDeactivation( - form, - possibleSmsRecipients, - ) - } - - // Important log message for user follow-ups - BounceService.logCriticalBounce({ - bounceDoc, - notification, - autoEmailRecipients: emailRecipients, - autoSmsRecipients: smsRecipients, - hasDeactivated: shouldDeactivate, - }) + ) } - return BounceService.saveBounceDoc(bounceDoc) - .map(() => res.sendStatus(StatusCodes.OK)) - .mapErr((error) => { - // Accept the risk that there might be concurrency problems - // when multiple server instances try to access the same - // document, due to notifications arriving asynchronously. - if (error instanceof DatabaseConflictError) - return res.sendStatus(StatusCodes.OK) - // Otherwise internal database error - return res.sendStatus(StatusCodes.INTERNAL_SERVER_ERROR) - }) + // Important log message for user follow-ups + BounceService.logCriticalBounce({ + bounceDoc, + notification, + autoEmailRecipients: emailRecipients, + autoSmsRecipients: smsRecipients, + hasDeactivated: shouldDeactivate, + }) } + + return BounceService.saveBounceDoc(bounceDoc) + .map(() => res.sendStatus(StatusCodes.OK)) + .mapErr((error) => { + // Accept the risk that there might be concurrency problems + // when multiple server instances try to access the same + // document, due to notifications arriving asynchronously. + if (error instanceof DatabaseConflictError) + return res.sendStatus(StatusCodes.OK) + // Otherwise internal database error + return res.sendStatus(StatusCodes.INTERNAL_SERVER_ERROR) + }) +} diff --git a/src/app/utils/field-validation/validators/common.ts b/src/app/utils/field-validation/validators/common.ts index 73f4715510..f337bc4e1e 100644 --- a/src/app/utils/field-validation/validators/common.ts +++ b/src/app/utils/field-validation/validators/common.ts @@ -12,14 +12,15 @@ import { ProcessedSingleAnswerResponse } from '../../../modules/submission/submi /** * A function which returns a validator to check if single answer has a non-empty response */ -export const notEmptySingleAnswerResponse: ResponseValidator = - (response) => { - if (response.answer.trim().length === 0) - return left( - 'CommonValidator.notEmptySingleAnswerResponse:\tanswer is an empty string', - ) - return right(response) - } +export const notEmptySingleAnswerResponse: ResponseValidator< + ProcessedSingleAnswerResponse +> = (response) => { + if (response.answer.trim().length === 0) + return left( + 'CommonValidator.notEmptySingleAnswerResponse:\tanswer is an empty string', + ) + return right(response) +} /** * A function which returns a signature validator constructor for mobile and email verified field. diff --git a/src/public/modules/core/views/edit-contact-number-modal.view.html b/src/public/modules/core/views/edit-contact-number-modal.view.html index 3219b041e9..af7dd4795d 100644 --- a/src/public/modules/core/views/edit-contact-number-modal.view.html +++ b/src/public/modules/core/views/edit-contact-number-modal.view.html @@ -65,12 +65,7 @@ diff --git a/src/public/modules/forms/admin/views/collaborator.client.modal.html b/src/public/modules/forms/admin/views/collaborator.client.modal.html index 67d79ad002..a95f80fcec 100644 --- a/src/public/modules/forms/admin/views/collaborator.client.modal.html +++ b/src/public/modules/forms/admin/views/collaborator.client.modal.html @@ -231,10 +231,7 @@ {{ ROLES.ADMIN }}
@@ -316,10 +313,7 @@