diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..cb6b2c84b --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,79 @@ + + +*A note to PR reviewers: it may be helpful to review our +[code review documentation](https://github.com/GSA/notifications-api/blob/main/docs/all.md#code-reviews) +to know what to keep in mind while reviewing pull requests.* + +## Description + +Please enter a clear description about your proposed changes and what the +expected outcome(s) is/are from there. If there are complex implementation +details within the changes, this is a great place to explain those details using +plain language. + +This should include: + +- Links to issues that this PR addresses +- Screenshots or screen captures of any visible changes, especially for UI work +- Dependency changes + +If there are any caveats, known issues, follow-up items, etc., make a quick note +of them here as well, though more details are probably warranted in the issue +itself in this case. + +## TODO (optional) + +If you're opening a draft PR, it might be helpful to list any outstanding work, +especially if you're asking folks to take a look before it's ready for full +review. In this case, create a small checklist with the outstanding items: + +- [ ] TODO item 1 +- [ ] TODO item 2 +- [ ] TODO item ... + +## Security Considerations + +Please think about the security compliance aspect of your changes and what the +potential impacts might be. + +**NOTE: Please be mindful of sharing sensitive information here! If you're not +sure of what to write, please ask the team first before writing anything here.** + +Relevant details could include (and are not limited to) the following: + +- Handling secrets/credential management (or specifically calling out that there + is nothing to handle) +- Any adjustments to the flow of data in and out the system, or even within it +- Connecting or disconnecting any external services to the application +- Handling of any sensitive information, such as PII +- Handling of information within log statements or other application monitoring + services/hooks +- The inclusion of a new external dependency or the removal of an existing one +- ... (anything else relevant from a security compliance perspective) + +There are some cases where there are no security considerations to be had, e.g., +updating our documentation with publicly available information. In those cases +it is fine to simply put something like this: + +- None; this is a documentation update with publicly available information. diff --git a/app/clients/cloudwatch/aws_cloudwatch.py b/app/clients/cloudwatch/aws_cloudwatch.py index 4fac575a3..0deac089e 100644 --- a/app/clients/cloudwatch/aws_cloudwatch.py +++ b/app/clients/cloudwatch/aws_cloudwatch.py @@ -90,23 +90,39 @@ class AwsCloudwatchClient(Client): account_number = ses_domain_arn.split(":") return account_number + def warn_if_dev_is_opted_out(self, provider_response, notification_id): + if ( + "is opted out" in provider_response.lower() + or "has blocked sms" in provider_response.lower() + ): + if os.getenv("NOTIFY_ENVIRONMENT") in ["development", "test"]: + ansi_red = "\033[31m" + ansi_reset = "\033[0m" + logline = ( + ansi_red + + f"The phone number for notification_id {notification_id} is OPTED OUT. You need to opt back in" + + ansi_reset + ) + current_app.logger.warning(logline) + return logline + return None + def check_sms(self, message_id, notification_id, created_at): - current_app.logger.info(f"CREATED AT = {created_at}") region = cloud_config.sns_region # TODO this clumsy approach to getting the account number will be fixed as part of notify-api #258 account_number = self._extract_account_number(cloud_config.ses_domain_arn) time_now = datetime.utcnow() log_group_name = f"sns/{region}/{account_number[4]}/DirectPublishToPhoneNumber" - current_app.logger.info( - f"Log group name: {log_group_name} message id: {message_id}" - ) filter_pattern = '{$.notification.messageId="XXXXX"}' filter_pattern = filter_pattern.replace("XXXXX", message_id) all_log_events = self._get_log(filter_pattern, log_group_name, created_at) if all_log_events and len(all_log_events) > 0: event = all_log_events[0] message = json.loads(event["message"]) + self.warn_if_dev_is_opted_out( + message["delivery"]["providerResponse"], notification_id + ) return ( "success", message["delivery"]["providerResponse"], @@ -116,13 +132,13 @@ class AwsCloudwatchClient(Client): log_group_name = ( f"sns/{region}/{account_number[4]}/DirectPublishToPhoneNumber/Failure" ) - current_app.logger.info(f"Failure log group name: {log_group_name}") all_failed_events = self._get_log(filter_pattern, log_group_name, created_at) if all_failed_events and len(all_failed_events) > 0: - current_app.logger.info("SHOULD RETURN FAILED BECAUSE WE FOUND A FAILURE") event = all_failed_events[0] message = json.loads(event["message"]) - current_app.logger.info(f"MESSAGE {message}") + self.warn_if_dev_is_opted_out( + message["delivery"]["providerResponse"], notification_id + ) return ( "failure", message["delivery"]["providerResponse"], diff --git a/docs/all.md b/docs/all.md index c74b11af3..4803102dd 100644 --- a/docs/all.md +++ b/docs/all.md @@ -36,17 +36,20 @@ - [Celery scheduled tasks](#celery-scheduled-tasks) - [Notify.gov](#notifygov) - [System Description](#system-description) +- [Code Reviews](#code-reviews) + - [For the reviewer](#for-the-reviewer) + - [For the author](#for-the-author) - [Run Book](#run-book) - - [ Alerts, Notifications, Monitoring](#-alerts-notifications-monitoring) - - [ Restaging Apps](#-restaging-apps) - - [ Smoke-testing the App](#-smoke-testing-the-app) - - [ Simulated bulk send testing](#-simulated-bulk-send-testing) - - [ Configuration Management](#-configuration-management) - - [ DNS Changes](#-dns-changes) + - [Alerts, Notifications, Monitoring](#-alerts-notifications-monitoring) + - [Restaging Apps](#-restaging-apps) + - [Smoke-testing the App](#-smoke-testing-the-app) + - [Simulated bulk send testing](#-simulated-bulk-send-testing) + - [Configuration Management](#-configuration-management) + - [DNS Changes](#-dns-changes) - [Exporting test results for compliance monitoring](#exporting-test-results-for-compliance-monitoring) - - [ Known Gotchas](#-known-gotchas) - - [ User Account Management](#-user-account-management) - - [ SMS Phone Number Management](#-sms-phone-number-management) + - [Known Gotchas](#-known-gotchas) + - [User Account Management](#-user-account-management) + - [SMS Phone Number Management](#-sms-phone-number-management) - [Data Storage Policies \& Procedures](#data-storage-policies--procedures) - [Potential PII Locations](#potential-pii-locations) - [Data Retention Policy](#data-retention-policy) @@ -711,10 +714,6 @@ make run-celery-beat ``` - - - - Notify.gov ========= @@ -755,6 +754,102 @@ Notify.gov also provisions and uses two AWS services via a [supplemental service For further details of the system and how it connects to supporting services, see the [application boundary diagram](https://github.com/GSA/us-notify-compliance/blob/main/diagrams/rendered/apps/application.boundary.png) +Code Reviews +============ + +When conducting a code review there are several things to keep in mind to ensure +a quality and valuable review. Remember, we're trying to improve Notify.gov as +best we can; it does us no good if we do not double check that our work meets +our standards, especially before going out the door! + +It also does us no good if we do not treat each other without mutual respect or +consideration either; if there are mistakes or oversights found in a pull +request, or even just suggestions for alternative ways of approaching something, +these become learning opportunities for all parties involved in addition to +modeling positive behavior and practices for the public and broader open source +community. + +Given this basis of approaching code reviews, here are some general guidelines +and suggestions for how to approach a code review from the perspectives of both +the reviewer and the author. + +### For the reviewer + +When performing a code review, please be curious and critical while also being +respectful and appreciative of the work submitted. Code reviews are a chance +to check that things meet our standards and provide learning opportunities. +They are not places for belittling or disparaging someone's work or approach to +a task, and absolutely not the person(s) themselves. + +That said, any responses to the code review should also be respectful and +considerate. Remember, this is a chance to not only improve our work and the +state of Notify.gov, it's also a chance to learn something new! + +**Note: If a response is condescending, derogatory, disrespectful, etc., please +do not hesitate to either speak with the author(s) directly about this or reach +out to a team lead/supervisor for additional help to rectify the issue. Such +behavior and lack of professionalism is not acceptable or tolerated.** + +When performing a code review, it is helpful to keep the following guidelines in +mind: + +- Be on the lookout for any sensitive information and/or leaked credentials, + secrets, PII, etc. +- Ask and call out things that aren't clear to you; it never hurts to double + check your understanding of something! +- Check that things are named descriptively and appropriately and call out + anything that is not. +- Check that comments are present for complex areas when needed. +- Make sure the pull request itself is properly prepared - it has a clear + description, calls out security concerns, and has the necessary labels, flags, + issue link, etc., set on it. +- Do not be shy about using the suggested changes feature in GitHub pull request + comments; this can help save a lot of time! +- Do not be shy about marking a review with the `Request Changes` status - yes, + it looks big and red when it shows up, but this is completely fine and not to + be taken as a personal mark against the author(s) of the pull request! + +Additionally, if you find yourself making a lot of comments and/or end up having +several concerns about the overall approach, it will likely be helpful to +schedule time to speak with the author(s) directly and talk through everything. +This can save folks a lot of misunderstanding and back-and-forth! + +### For the author + +When receiving a code review, please remember that someone took the time to look +over all of your work with a critical eye to make sure our standards are being +met and that we're producing the best quality work possible. It's completely +fine if there are specific changes requested and/or other parts are sent back +for additional work! + +That said, the review should also be respectful, helpful, and a learning +opportunity where possible. Remember, this is a chance to not only improve your +work and the state of Notify.gov, it's also a chance to learn something new! + +**Note: If a review is condescending, derogatory, disrespectful, etc., please do +not hesitate to either speak with the reviewer(s) directly about this or reach +out to a team lead/supervisor for additional help to rectify the issue. Such +behavior and lack of professionalism is not acceptable or tolerated.** + +When going over a review, it may be helpful to keep these perspectives in mind: + +- Approach the review with an open mind, curiosity, and appreciation. +- If anything the reviewer(s) mentions is unclear to you, please ask for + clarification and engage them in further dialogue! +- If you disagree with a suggestion or request, please say so and engage in an + open and respecful dialogue to come to a mutual understanding of what the + appropriate next step(S) should be - accept the change, reject the change, + take a different path entirely, etc. +- If there are no issues with any suggested edits or requested changes, make + the necessary adjustments and let the reviewer(s) know when the work is ready + for review again. + +Additionally, if you find yourself responding to a lot of things and questioning +the feedback received throughout much of the code review, it will likely be +helpful to schedule time to speak with the reviewer(s) directly and talk through +everything. This can save folks a lot of misunderstanding and back-and-forth! + + Run Book ======== diff --git a/poetry.lock b/poetry.lock index 2d1d30bb1..3a92d1031 100644 --- a/poetry.lock +++ b/poetry.lock @@ -940,43 +940,43 @@ files = [ [[package]] name = "cryptography" -version = "42.0.2" +version = "42.0.4" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-42.0.2-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:701171f825dcab90969596ce2af253143b93b08f1a716d4b2a9d2db5084ef7be"}, - {file = "cryptography-42.0.2-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:61321672b3ac7aade25c40449ccedbc6db72c7f5f0fdf34def5e2f8b51ca530d"}, - {file = "cryptography-42.0.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea2c3ffb662fec8bbbfce5602e2c159ff097a4631d96235fcf0fb00e59e3ece4"}, - {file = "cryptography-42.0.2-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b15c678f27d66d247132cbf13df2f75255627bcc9b6a570f7d2fd08e8c081d2"}, - {file = "cryptography-42.0.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8e88bb9eafbf6a4014d55fb222e7360eef53e613215085e65a13290577394529"}, - {file = "cryptography-42.0.2-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a047682d324ba56e61b7ea7c7299d51e61fd3bca7dad2ccc39b72bd0118d60a1"}, - {file = "cryptography-42.0.2-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:36d4b7c4be6411f58f60d9ce555a73df8406d484ba12a63549c88bd64f7967f1"}, - {file = "cryptography-42.0.2-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:a00aee5d1b6c20620161984f8ab2ab69134466c51f58c052c11b076715e72929"}, - {file = "cryptography-42.0.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b97fe7d7991c25e6a31e5d5e795986b18fbbb3107b873d5f3ae6dc9a103278e9"}, - {file = "cryptography-42.0.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5fa82a26f92871eca593b53359c12ad7949772462f887c35edaf36f87953c0e2"}, - {file = "cryptography-42.0.2-cp37-abi3-win32.whl", hash = "sha256:4b063d3413f853e056161eb0c7724822a9740ad3caa24b8424d776cebf98e7ee"}, - {file = "cryptography-42.0.2-cp37-abi3-win_amd64.whl", hash = "sha256:841ec8af7a8491ac76ec5a9522226e287187a3107e12b7d686ad354bb78facee"}, - {file = "cryptography-42.0.2-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:55d1580e2d7e17f45d19d3b12098e352f3a37fe86d380bf45846ef257054b242"}, - {file = "cryptography-42.0.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28cb2c41f131a5758d6ba6a0504150d644054fd9f3203a1e8e8d7ac3aea7f73a"}, - {file = "cryptography-42.0.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9097a208875fc7bbeb1286d0125d90bdfed961f61f214d3f5be62cd4ed8a446"}, - {file = "cryptography-42.0.2-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:44c95c0e96b3cb628e8452ec060413a49002a247b2b9938989e23a2c8291fc90"}, - {file = "cryptography-42.0.2-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2f9f14185962e6a04ab32d1abe34eae8a9001569ee4edb64d2304bf0d65c53f3"}, - {file = "cryptography-42.0.2-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:09a77e5b2e8ca732a19a90c5bca2d124621a1edb5438c5daa2d2738bfeb02589"}, - {file = "cryptography-42.0.2-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad28cff53f60d99a928dfcf1e861e0b2ceb2bc1f08a074fdd601b314e1cc9e0a"}, - {file = "cryptography-42.0.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:130c0f77022b2b9c99d8cebcdd834d81705f61c68e91ddd614ce74c657f8b3ea"}, - {file = "cryptography-42.0.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:fa3dec4ba8fb6e662770b74f62f1a0c7d4e37e25b58b2bf2c1be4c95372b4a33"}, - {file = "cryptography-42.0.2-cp39-abi3-win32.whl", hash = "sha256:3dbd37e14ce795b4af61b89b037d4bc157f2cb23e676fa16932185a04dfbf635"}, - {file = "cryptography-42.0.2-cp39-abi3-win_amd64.whl", hash = "sha256:8a06641fb07d4e8f6c7dda4fc3f8871d327803ab6542e33831c7ccfdcb4d0ad6"}, - {file = "cryptography-42.0.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:087887e55e0b9c8724cf05361357875adb5c20dec27e5816b653492980d20380"}, - {file = "cryptography-42.0.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a7ef8dd0bf2e1d0a27042b231a3baac6883cdd5557036f5e8df7139255feaac6"}, - {file = "cryptography-42.0.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4383b47f45b14459cab66048d384614019965ba6c1a1a141f11b5a551cace1b2"}, - {file = "cryptography-42.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:fbeb725c9dc799a574518109336acccaf1303c30d45c075c665c0793c2f79a7f"}, - {file = "cryptography-42.0.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:320948ab49883557a256eab46149df79435a22d2fefd6a66fe6946f1b9d9d008"}, - {file = "cryptography-42.0.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5ef9bc3d046ce83c4bbf4c25e1e0547b9c441c01d30922d812e887dc5f125c12"}, - {file = "cryptography-42.0.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:52ed9ebf8ac602385126c9a2fe951db36f2cb0c2538d22971487f89d0de4065a"}, - {file = "cryptography-42.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:141e2aa5ba100d3788c0ad7919b288f89d1fe015878b9659b307c9ef867d3a65"}, - {file = "cryptography-42.0.2.tar.gz", hash = "sha256:e0ec52ba3c7f1b7d813cd52649a5b3ef1fc0d433219dc8c93827c57eab6cf888"}, + {file = "cryptography-42.0.4-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:ffc73996c4fca3d2b6c1c8c12bfd3ad00def8621da24f547626bf06441400449"}, + {file = "cryptography-42.0.4-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:db4b65b02f59035037fde0998974d84244a64c3265bdef32a827ab9b63d61b18"}, + {file = "cryptography-42.0.4-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad9c385ba8ee025bb0d856714f71d7840020fe176ae0229de618f14dae7a6e2"}, + {file = "cryptography-42.0.4-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69b22ab6506a3fe483d67d1ed878e1602bdd5912a134e6202c1ec672233241c1"}, + {file = "cryptography-42.0.4-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e09469a2cec88fb7b078e16d4adec594414397e8879a4341c6ace96013463d5b"}, + {file = "cryptography-42.0.4-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3e970a2119507d0b104f0a8e281521ad28fc26f2820687b3436b8c9a5fcf20d1"}, + {file = "cryptography-42.0.4-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:e53dc41cda40b248ebc40b83b31516487f7db95ab8ceac1f042626bc43a2f992"}, + {file = "cryptography-42.0.4-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:c3a5cbc620e1e17009f30dd34cb0d85c987afd21c41a74352d1719be33380885"}, + {file = "cryptography-42.0.4-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6bfadd884e7280df24d26f2186e4e07556a05d37393b0f220a840b083dc6a824"}, + {file = "cryptography-42.0.4-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:01911714117642a3f1792c7f376db572aadadbafcd8d75bb527166009c9f1d1b"}, + {file = "cryptography-42.0.4-cp37-abi3-win32.whl", hash = "sha256:fb0cef872d8193e487fc6bdb08559c3aa41b659a7d9be48b2e10747f47863925"}, + {file = "cryptography-42.0.4-cp37-abi3-win_amd64.whl", hash = "sha256:c1f25b252d2c87088abc8bbc4f1ecbf7c919e05508a7e8628e6875c40bc70923"}, + {file = "cryptography-42.0.4-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:15a1fb843c48b4a604663fa30af60818cd28f895572386e5f9b8a665874c26e7"}, + {file = "cryptography-42.0.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1327f280c824ff7885bdeef8578f74690e9079267c1c8bd7dc5cc5aa065ae52"}, + {file = "cryptography-42.0.4-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ffb03d419edcab93b4b19c22ee80c007fb2d708429cecebf1dd3258956a563a"}, + {file = "cryptography-42.0.4-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:1df6fcbf60560d2113b5ed90f072dc0b108d64750d4cbd46a21ec882c7aefce9"}, + {file = "cryptography-42.0.4-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:44a64043f743485925d3bcac548d05df0f9bb445c5fcca6681889c7c3ab12764"}, + {file = "cryptography-42.0.4-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:3c6048f217533d89f2f8f4f0fe3044bf0b2090453b7b73d0b77db47b80af8dff"}, + {file = "cryptography-42.0.4-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6d0fbe73728c44ca3a241eff9aefe6496ab2656d6e7a4ea2459865f2e8613257"}, + {file = "cryptography-42.0.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:887623fe0d70f48ab3f5e4dbf234986b1329a64c066d719432d0698522749929"}, + {file = "cryptography-42.0.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ce8613beaffc7c14f091497346ef117c1798c202b01153a8cc7b8e2ebaaf41c0"}, + {file = "cryptography-42.0.4-cp39-abi3-win32.whl", hash = "sha256:810bcf151caefc03e51a3d61e53335cd5c7316c0a105cc695f0959f2c638b129"}, + {file = "cryptography-42.0.4-cp39-abi3-win_amd64.whl", hash = "sha256:a0298bdc6e98ca21382afe914c642620370ce0470a01e1bef6dd9b5354c36854"}, + {file = "cryptography-42.0.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5f8907fcf57392cd917892ae83708761c6ff3c37a8e835d7246ff0ad251d9298"}, + {file = "cryptography-42.0.4-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:12d341bd42cdb7d4937b0cabbdf2a94f949413ac4504904d0cdbdce4a22cbf88"}, + {file = "cryptography-42.0.4-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1cdcdbd117681c88d717437ada72bdd5be9de117f96e3f4d50dab3f59fd9ab20"}, + {file = "cryptography-42.0.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0e89f7b84f421c56e7ff69f11c441ebda73b8a8e6488d322ef71746224c20fce"}, + {file = "cryptography-42.0.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f1e85a178384bf19e36779d91ff35c7617c885da487d689b05c1366f9933ad74"}, + {file = "cryptography-42.0.4-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d2a27aca5597c8a71abbe10209184e1a8e91c1fd470b5070a2ea60cafec35bcd"}, + {file = "cryptography-42.0.4-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4e36685cb634af55e0677d435d425043967ac2f3790ec652b2b88ad03b85c27b"}, + {file = "cryptography-42.0.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f47be41843200f7faec0683ad751e5ef11b9a56a220d57f300376cd8aba81660"}, + {file = "cryptography-42.0.4.tar.gz", hash = "sha256:831a4b37accef30cccd34fcb916a5d7b5be3cbbe27268a02832c3e450aea39cb"}, ] [package.dependencies] @@ -2582,7 +2582,7 @@ requests = ">=2.0.0" [[package]] name = "notifications-utils" -version = "0.2.8" +version = "0.2.9" description = "" optional = false python-versions = ">=3.9,<3.12" @@ -2600,7 +2600,7 @@ certifi = "^2023.7.22" cffi = "^1.16.0" charset-normalizer = "^3.1.0" click = "^8.1.3" -cryptography = "^42.0.0" +cryptography = "^42.0.4" flask = "^2.3.2" flask-redis = "^0.4.0" geojson = "^3.0.1" @@ -2634,7 +2634,7 @@ werkzeug = "^3.0.1" type = "git" url = "https://github.com/GSA/notifications-utils.git" reference = "HEAD" -resolved_reference = "a48171e865eb83cf29c75751be7369f396cbe3e2" +resolved_reference = "df8ece836cad303c5d161edf485cf9bbdc666688" [[package]] name = "numpy" diff --git a/tests/app/clients/test_aws_cloudwatch.py b/tests/app/clients/test_aws_cloudwatch.py index 5eeffb979..2eb70c94b 100644 --- a/tests/app/clients/test_aws_cloudwatch.py +++ b/tests/app/clients/test_aws_cloudwatch.py @@ -1,6 +1,7 @@ # import pytest from datetime import datetime +import pytest from flask import current_app from app import aws_cloudwatch_client @@ -54,6 +55,27 @@ def side_effect(filterPattern, logGroupName, startTime, endTime): return {"events": []} +@pytest.mark.parametrize( + "response, notify_id, expected_message", + [ + ( + "Phone has blocked SMS", + "abc", + "\x1b[31mThe phone number for notification_id abc is OPTED OUT. You need to opt back in\x1b[0m", + ), + ( + "Some phone is opted out", + "xyz", + "\x1b[31mThe phone number for notification_id xyz is OPTED OUT. You need to opt back in\x1b[0m", + ), + ("Phone is A-OK", "123", None), + ], +) +def test_warn_if_dev_is_opted_out(response, notify_id, expected_message): + result = aws_cloudwatch_client.warn_if_dev_is_opted_out(response, notify_id) + assert result == expected_message + + def test_check_sms_success(notify_api, mocker): aws_cloudwatch_client.init_app(current_app) boto_mock = mocker.patch.object(aws_cloudwatch_client, "_client", create=True)