From 246e0194bd17d5cb3d678ae1a00f1871986411e5 Mon Sep 17 00:00:00 2001 From: Robert Helmer Date: Tue, 6 Aug 2024 11:49:55 -0700 Subject: [PATCH] Update dependency doc with info on testing backend updates (#4919) * update details for backend dependency testing * add details to README about load testing using k6 * types/k6 package Co-authored-by: Vincent --- README.md | 15 +++++++++++ docs/dependency-updates.md | 49 ++++++++++++++++++++++++++++----- package-lock.json | 8 ++++++ package.json | 1 + src/scripts/loadtest/hibp.js | 52 ++++++++++++++++++++++++++++++++++++ 5 files changed, 118 insertions(+), 7 deletions(-) create mode 100644 src/scripts/loadtest/hibp.js diff --git a/README.md b/README.md index 26b3ada6c..c2baca92c 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ the "what" and "why" of data breach alerts. - [Volta](https://volta.sh/) (installs the correct version of Node and npm) - [Postgres](https://www.postgresql.org/) | Note: On a Mac, we recommend downloading the [Postgres.app](https://postgresapp.com/) instead. - [Python](https://www.python.org/downloads/) | [With Homebrew](https://docs.brew.sh/Homebrew-and-Python) +- [k6](https://grafana.com/docs/k6/latest/set-up/install-k6/) | k6 load testing tool ### Code style @@ -209,6 +210,20 @@ To test this part of Monitor: 4. Go to `about:protections` 5. Everything should be using your localhost instance of Monitor. +#### Load testing + +k6 is used for load testing. + +To test the HIBP breach alerts endpoint, use: + +```sh +export SERVER_URL=... +export HIBP_NOTIFY_TOKEN=... +k6 -u 10 src/scripts/loadtest/hibp.js # Run with 10 virtual users +``` + +See https://grafana.com/docs/k6/latest/get-started/running-k6/ for more information. + ## Localization All text that is visible to the user is defined in [Fluent](https://projectfluent.org/) files inside `/locales/en/` and `/locales-pending/`. After strings get added to files in the former directory on our `main` branch, they will be made available to our volunteer localizers via Pontoon, Mozilla's localization platform. Be sure to reference the [localization documentation](https://mozilla-l10n.github.io/documentation/localization/dev_best_practices.html) for best practices. It's best to only move the strings to `/locales/en/` when they are more-or-less final and ready for localization. Your PR should be automatically tagged with a reviewer from the [Mozilla L10n team](https://wiki.mozilla.org/L10n:Mozilla_Team) to approve your request. diff --git a/docs/dependency-updates.md b/docs/dependency-updates.md index 998e6bf75..b7754e937 100644 --- a/docs/dependency-updates.md +++ b/docs/dependency-updates.md @@ -215,31 +215,66 @@ TODO: Describe how the `fxa-rp-events` endpoint uses these packages. ### `uuid` -TODO: Describe how to verify that `uuid` updates didn't break anything. +Used in places where a random identifier is needed: + +- as a `nonce` in `src/middleware.ts` for CSP +- server-side Glean document IDs in `src/app/functions/server/glean.ts` +- as an experimentation ID for Nimbus in `src/app/functions/server/getUserId.tsx` and `src/app/functions/server/getExperimentationId.ts` +- for email verification tokens in `src/db/tables/emailAddresses.js` + +1. Check that `nonce` is present in `content-security-policy` header for HTTP responses. +2. Check that `experimentationId` is set as a cookie in the form `guest-${uuid}` +3. Add a secondary email from the Settings screen and ensure that email verification works ### `@aws-sdk/*` -TODO: Describe how to verify that AWS SDK updates didn't break anything. +Used for S3, by the `npm run cron:db-pull-breaches` cron job. + +This job runs periodically on stage and production to download Favicon files from DuckDuckGo and re-uploads them to Monitor's S3 bucket. +Check in the server logs that this job completed without errors. ### `@google-cloud/pubsub` -TODO: Describe how to verify that GCP pubsub updates didn't break anything. +GCP PubSub is used for email breach notifications from HIBP: + +- `src/app/api/v1/hibp/notify/route.ts` receives the breach notification and queues in PubSub +- `src/scripts/cronjobs/emailBreachAlerts.ts` is run by a periodic cron job + +Check the server logs and ensure there are no errors. See +[this section of the README](https://github.com/mozilla/blurts-server/blob/main/README.md#incoming-webhook-requests-from-hibp-will-be-of-the-form) +for information about simulating a breach alert. + +See `./src/loadtest/hibp.js` for a K6 load testing script which will exercise this. ### `@grpc/grpc-js` -TODO: Describe how to verify that GRPC updates didn't break anything. +GRPC is used as a communication protocol for various GCP services. + +Monitor uses it to facilitate the local PubSub emulator. See [this section of the README](https://github.com/mozilla/blurts-server/blob/main/README.md#pubsub) +for instructions on running the Pub/Sub emulator locally. ### `winston` and `@google-cloud/logging-winston` -TODO: Describe how to verify that logger updates didn't break anything. +Winston is a logging library that provides structured logging in GCP. + +Look for any `logger.*` statement in `./src` and ensure that log messages are being written as [structured logs](https://cloud.google.com/logging/docs/structured-logging). ### `@sentry/*` -TODO: Describe how to verify that Sentry updates didn't break anything. +Sentry is an error reporting service that captured front-end (browser) as well as back-end (Node) error messages. + +In normal operation nothing should be sent to Sentry, but you can verify that the SDK is loading: + +1. in the browser, verify that there are no errors related to Sentry in the devtools console +2. in the server logs, verify `instrumentationHook` is logged as enabled and there are no errors related to Sentry ### `nodemailer` -TODO: Describe how to verify that nodemailer updates didn't break anything. +Nodemailer is used by `src/utils/email.js` to send all email related to Monitor. It uses AWS Simple Email Services (SES) by default, +which is controlled by the `SMTP_URL` environment variable. Any `smtps://` URL can be used here for testing, and any email Monitor sends +can be used for testing. + +Monitor provides a tool for sending test email at the endpoint `/admin/emails`. ### `adm-zip` diff --git a/package-lock.json b/package-lock.json index b78e7070c..f0ed9f2b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -69,6 +69,7 @@ "@types/jest-axe": "^3.5.9", "@types/jsonwebtoken": "^9.0.6", "@types/jwk-to-pem": "^2.0.3", + "@types/k6": "^0.52.0", "@types/mjml": "^4.7.4", "@types/mjml-browser": "^4.15.0", "@types/nodemailer": "^6.4.15", @@ -10952,6 +10953,13 @@ "integrity": "sha512-I/WFyFgk5GrNbkpmt14auGO3yFK1Wt4jXzkLuI+fDBNtO5ZI2rbymyGd6bKzfSBEuyRdM64ZUwxU1+eDcPSOEQ==", "dev": true }, + "node_modules/@types/k6": { + "version": "0.52.0", + "resolved": "https://registry.npmjs.org/@types/k6/-/k6-0.52.0.tgz", + "integrity": "sha512-yaw2wg61nKQtToDML+nngzgXVjZ6wNA4R0Q3jKDTeadG5EqfZgis5a1Q2hwY7kjuGuXmu8eM6gHg3tgnOj4vNw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/lodash": { "version": "4.14.202", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", diff --git a/package.json b/package.json index 28ccd808b..72a485cdf 100644 --- a/package.json +++ b/package.json @@ -122,6 +122,7 @@ "@types/jest-axe": "^3.5.9", "@types/jsonwebtoken": "^9.0.6", "@types/jwk-to-pem": "^2.0.3", + "@types/k6": "^0.52.0", "@types/mjml": "^4.7.4", "@types/mjml-browser": "^4.15.0", "@types/nodemailer": "^6.4.15", diff --git a/src/scripts/loadtest/hibp.js b/src/scripts/loadtest/hibp.js new file mode 100644 index 000000000..ddd0e0e36 --- /dev/null +++ b/src/scripts/loadtest/hibp.js @@ -0,0 +1,52 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * NOTE: This is a k6 loadtest script, see https://k6.io/ for more information. + * + * In particular, k6 supports JS but is not a Node package: https://k6.io/docs/get-started/installation/ + * This is why import/no-unresolved and no-undef are ignored. + * + * @see https://grafana.com/docs/k6/latest/get-started/running-k6 + */ + +/* eslint-disable import/no-unresolved */ +/* eslint-disable no-undef */ + +import { post } from "k6/http"; + +const url = `${__ENV.SERVER_URL}/api/v1/hibp/notify`; + +// eslint-disable-next-line import/no-anonymous-default-export +export default function () { + let data = { + breachName: "ApexSMS", + // NOTE: modify this hash range if you want to receive email to specific test account(s). + // This example should only email an address that is a sha1 hash for 1c48923da9f6f17165711712d11bc104087444cc. + // See https://www.troyhunt.com/understanding-have-i-been-pwneds-use-of-sha-1-and-k-anonymity/ for more information. + hashPrefix: "1c4892", + hashSuffixes: [ + "3da9f6f17165711712d11bc104087444cc", + "3da9f6fffff5711712d11bc104087444cc", + ], + }; + + // Using a JSON string as body + let res = post(url, JSON.stringify(data), { + headers: { + "Content-Type": "application/json", + // eslint-disable-next-line no-undef + Authorization: `Bearer ${__ENV.HIBP_NOTIFY_TOKEN}`, + }, + }); + + try { + const result = res.json(); + if (result.success !== true) { + throw new Error(`Non-success result: ${JSON.stringify(result)}`); + } + } catch (ex) { + throw new Error(`Failed to parse result: ${res.status}, ${res.text}`); + } +}