mirror of
https://github.com/GSA/notifications-api.git
synced 2026-08-21 14:59:26 -04:00
Compare commits
24 Commits
02-08-2024
...
02-27-2024
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0368307802 | ||
|
|
55dc017205 | ||
|
|
f508ff2c76 | ||
|
|
24e379cfa8 | ||
|
|
f301c7a389 | ||
|
|
bfb619d5e9 | ||
|
|
993b171236 | ||
|
|
9cd68a10dc | ||
|
|
4412a86b28 | ||
|
|
1cf2a81d26 | ||
|
|
a93cdf9211 | ||
|
|
d1d55cca4e | ||
|
|
158316a77b | ||
|
|
ba94b5a0ec | ||
|
|
755f5e085e | ||
|
|
467a2919f4 | ||
|
|
2f5fea6d81 | ||
|
|
aabb822824 | ||
|
|
d9e6ebdbe3 | ||
|
|
88a553651b | ||
|
|
6e6c0ee61d | ||
|
|
050d92d822 | ||
|
|
f7673aa968 | ||
|
|
afd77cf9fe |
79
.github/pull_request_template.md
vendored
Normal file
79
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
<!--
|
||||
Please follow the instructions found in this pull request template so that we
|
||||
have all of the relevant details needed for our work.
|
||||
|
||||
At the minimum, please be sure to fill in all sections found below and also do
|
||||
the following:
|
||||
|
||||
- Provide an appropriate and descriptive title for the pull request
|
||||
- Link the pull request to its corresponding issue (must be done after creating
|
||||
the pull request itself)
|
||||
- Assign yourself as the author
|
||||
- Attach the appropriate labels to it
|
||||
- Set it to be on the Notify.gov project board
|
||||
- Select one or more reviewers from the team or mark the pull request as a draft
|
||||
depending on its current state
|
||||
- If the pull request is a draft, please be sure to add reviewers once it is
|
||||
ready for review and mark it ready for review
|
||||
|
||||
For each section, please delete the instructions/sample text (that includes this
|
||||
text, though it is wrapped in an HTML comment just in case) and put in your own
|
||||
information. Thank you!
|
||||
-->
|
||||
|
||||
*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.
|
||||
@@ -117,7 +117,7 @@ def extract_phones(job):
|
||||
current_app.logger.info(f"PHONE INDEX IS NOW {phone_index}")
|
||||
current_app.logger.info(f"LENGTH OF ROW IS {len(row)}")
|
||||
if phone_index >= len(row):
|
||||
phones[job_row] = "Error: can't retrieve phone number"
|
||||
phones[job_row] = "Unavailable"
|
||||
current_app.logger.error(
|
||||
"Corrupt csv file, missing columns or possibly a byte order mark in the file"
|
||||
)
|
||||
@@ -151,7 +151,7 @@ def get_phone_number_from_s3(service_id, job_id, job_row_number):
|
||||
current_app.logger.warning(
|
||||
f"Couldnt find phone for job_id {job_id} row number {job_row_number} because job is missing"
|
||||
)
|
||||
return "Unknown Phone"
|
||||
return "Unavailable"
|
||||
|
||||
# If we look in the JOBS cache for the quick lookup dictionary of phones for a given job
|
||||
# and that dictionary is not there, create it
|
||||
@@ -167,12 +167,12 @@ def get_phone_number_from_s3(service_id, job_id, job_row_number):
|
||||
current_app.logger.warning(
|
||||
f"Was unable to retrieve phone number from lookup dictionary for job {job_id}"
|
||||
)
|
||||
return "Unknown Phone"
|
||||
return "Unavailable"
|
||||
else:
|
||||
current_app.logger.error(
|
||||
f"Was unable to construct lookup dictionary for job {job_id}"
|
||||
)
|
||||
return "Unknown Phone"
|
||||
return "Unavailable"
|
||||
|
||||
|
||||
def get_job_metadata_from_s3(service_id, job_id):
|
||||
|
||||
@@ -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"],
|
||||
|
||||
@@ -3,11 +3,7 @@ from datetime import date, datetime, time, timedelta
|
||||
|
||||
def get_months_for_financial_year(year):
|
||||
return [
|
||||
month
|
||||
for month in (
|
||||
get_months_for_year(4, 13, year) + get_months_for_year(1, 4, year + 1)
|
||||
)
|
||||
if month < datetime.now()
|
||||
month for month in (get_months_for_year(1, 13, year)) if month < datetime.now()
|
||||
]
|
||||
|
||||
|
||||
|
||||
121
docs/all.md
121
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
|
||||
========
|
||||
|
||||
|
||||
115
poetry.lock
generated
115
poetry.lock
generated
@@ -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]
|
||||
@@ -1169,13 +1169,13 @@ pgp = ["gpg"]
|
||||
|
||||
[[package]]
|
||||
name = "eventlet"
|
||||
version = "0.34.3"
|
||||
version = "0.35.2"
|
||||
description = "Highly concurrent networking library"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "eventlet-0.34.3-py3-none-any.whl", hash = "sha256:3093f2822ce2f40792bf9aa7eb8920fe3b90db785d3bea7640c50412969dcfd7"},
|
||||
{file = "eventlet-0.34.3.tar.gz", hash = "sha256:ed2d28a64414a001894b3baf5b650f2c9596b00d57f57d4d7a38f9d3d0c252e8"},
|
||||
{file = "eventlet-0.35.2-py3-none-any.whl", hash = "sha256:8fc1ee60d583f1dd58d6f304bb95fd46d34865ab22f57cb99008a81d61d573db"},
|
||||
{file = "eventlet-0.35.2.tar.gz", hash = "sha256:8d1263e20b7f816a046ac60e1d272f9e5bc503f7a34d9adc789f8a85b14fa57d"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -1259,19 +1259,19 @@ typing = ["typing-extensions (>=4.8)"]
|
||||
|
||||
[[package]]
|
||||
name = "flake8"
|
||||
version = "6.1.0"
|
||||
version = "7.0.0"
|
||||
description = "the modular source code checker: pep8 pyflakes and co"
|
||||
optional = false
|
||||
python-versions = ">=3.8.1"
|
||||
files = [
|
||||
{file = "flake8-6.1.0-py2.py3-none-any.whl", hash = "sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5"},
|
||||
{file = "flake8-6.1.0.tar.gz", hash = "sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23"},
|
||||
{file = "flake8-7.0.0-py2.py3-none-any.whl", hash = "sha256:a6dfbb75e03252917f2473ea9653f7cd799c3064e54d4c8140044c5c065f53c3"},
|
||||
{file = "flake8-7.0.0.tar.gz", hash = "sha256:33f96621059e65eec474169085dc92bf26e7b2d47366b70be2f67ab80dc25132"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
mccabe = ">=0.7.0,<0.8.0"
|
||||
pycodestyle = ">=2.11.0,<2.12.0"
|
||||
pyflakes = ">=3.1.0,<3.2.0"
|
||||
pyflakes = ">=3.2.0,<3.3.0"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-bugbear"
|
||||
@@ -2015,6 +2015,7 @@ description = "Powerful and Pythonic XML processing library combining libxml2/li
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "lxml-5.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:704f5572ff473a5f897745abebc6df40f22d4133c1e0a1f124e4f2bd3330ff7e"},
|
||||
{file = "lxml-5.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9d3c0f8567ffe7502d969c2c1b809892dc793b5d0665f602aad19895f8d508da"},
|
||||
{file = "lxml-5.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5fcfbebdb0c5d8d18b84118842f31965d59ee3e66996ac842e21f957eb76138c"},
|
||||
{file = "lxml-5.1.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f37c6d7106a9d6f0708d4e164b707037b7380fcd0b04c5bd9cae1fb46a856fb"},
|
||||
@@ -2024,6 +2025,7 @@ files = [
|
||||
{file = "lxml-5.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:82bddf0e72cb2af3cbba7cec1d2fd11fda0de6be8f4492223d4a268713ef2147"},
|
||||
{file = "lxml-5.1.0-cp310-cp310-win32.whl", hash = "sha256:b66aa6357b265670bb574f050ffceefb98549c721cf28351b748be1ef9577d93"},
|
||||
{file = "lxml-5.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:4946e7f59b7b6a9e27bef34422f645e9a368cb2be11bf1ef3cafc39a1f6ba68d"},
|
||||
{file = "lxml-5.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:14deca1460b4b0f6b01f1ddc9557704e8b365f55c63070463f6c18619ebf964f"},
|
||||
{file = "lxml-5.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ed8c3d2cd329bf779b7ed38db176738f3f8be637bb395ce9629fc76f78afe3d4"},
|
||||
{file = "lxml-5.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:436a943c2900bb98123b06437cdd30580a61340fbdb7b28aaf345a459c19046a"},
|
||||
{file = "lxml-5.1.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:acb6b2f96f60f70e7f34efe0c3ea34ca63f19ca63ce90019c6cbca6b676e81fa"},
|
||||
@@ -2033,6 +2035,7 @@ files = [
|
||||
{file = "lxml-5.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f4c9bda132ad108b387c33fabfea47866af87f4ea6ffb79418004f0521e63204"},
|
||||
{file = "lxml-5.1.0-cp311-cp311-win32.whl", hash = "sha256:bc64d1b1dab08f679fb89c368f4c05693f58a9faf744c4d390d7ed1d8223869b"},
|
||||
{file = "lxml-5.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:a5ab722ae5a873d8dcee1f5f45ddd93c34210aed44ff2dc643b5025981908cda"},
|
||||
{file = "lxml-5.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9aa543980ab1fbf1720969af1d99095a548ea42e00361e727c58a40832439114"},
|
||||
{file = "lxml-5.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6f11b77ec0979f7e4dc5ae081325a2946f1fe424148d3945f943ceaede98adb8"},
|
||||
{file = "lxml-5.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a36c506e5f8aeb40680491d39ed94670487ce6614b9d27cabe45d94cd5d63e1e"},
|
||||
{file = "lxml-5.1.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f643ffd2669ffd4b5a3e9b41c909b72b2a1d5e4915da90a77e119b8d48ce867a"},
|
||||
@@ -2058,8 +2061,8 @@ files = [
|
||||
{file = "lxml-5.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8f52fe6859b9db71ee609b0c0a70fea5f1e71c3462ecf144ca800d3f434f0764"},
|
||||
{file = "lxml-5.1.0-cp37-cp37m-win32.whl", hash = "sha256:d42e3a3fc18acc88b838efded0e6ec3edf3e328a58c68fbd36a7263a874906c8"},
|
||||
{file = "lxml-5.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:eac68f96539b32fce2c9b47eb7c25bb2582bdaf1bbb360d25f564ee9e04c542b"},
|
||||
{file = "lxml-5.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ae15347a88cf8af0949a9872b57a320d2605ae069bcdf047677318bc0bba45b1"},
|
||||
{file = "lxml-5.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c26aab6ea9c54d3bed716b8851c8bfc40cb249b8e9880e250d1eddde9f709bf5"},
|
||||
{file = "lxml-5.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cfbac9f6149174f76df7e08c2e28b19d74aed90cad60383ad8671d3af7d0502f"},
|
||||
{file = "lxml-5.1.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:342e95bddec3a698ac24378d61996b3ee5ba9acfeb253986002ac53c9a5f6f84"},
|
||||
{file = "lxml-5.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:725e171e0b99a66ec8605ac77fa12239dbe061482ac854d25720e2294652eeaa"},
|
||||
{file = "lxml-5.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d184e0d5c918cff04cdde9dbdf9600e960161d773666958c9d7b565ccc60c45"},
|
||||
@@ -2067,6 +2070,7 @@ files = [
|
||||
{file = "lxml-5.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6d48fc57e7c1e3df57be5ae8614bab6d4e7b60f65c5457915c26892c41afc59e"},
|
||||
{file = "lxml-5.1.0-cp38-cp38-win32.whl", hash = "sha256:7ec465e6549ed97e9f1e5ed51c657c9ede767bc1c11552f7f4d022c4df4a977a"},
|
||||
{file = "lxml-5.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:b21b4031b53d25b0858d4e124f2f9131ffc1530431c6d1321805c90da78388d1"},
|
||||
{file = "lxml-5.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:52427a7eadc98f9e62cb1368a5079ae826f94f05755d2d567d93ee1bc3ceb354"},
|
||||
{file = "lxml-5.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6a2a2c724d97c1eb8cf966b16ca2915566a4904b9aad2ed9a09c748ffe14f969"},
|
||||
{file = "lxml-5.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:843b9c835580d52828d8f69ea4302537337a21e6b4f1ec711a52241ba4a824f3"},
|
||||
{file = "lxml-5.1.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9b99f564659cfa704a2dd82d0684207b1aadf7d02d33e54845f9fc78e06b7581"},
|
||||
@@ -2184,6 +2188,16 @@ files = [
|
||||
{file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"},
|
||||
{file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"},
|
||||
{file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"},
|
||||
{file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"},
|
||||
{file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"},
|
||||
{file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"},
|
||||
{file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"},
|
||||
{file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"},
|
||||
{file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"},
|
||||
{file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"},
|
||||
{file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"},
|
||||
{file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"},
|
||||
{file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"},
|
||||
{file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"},
|
||||
{file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"},
|
||||
{file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"},
|
||||
@@ -2567,12 +2581,12 @@ setuptools = "*"
|
||||
|
||||
[[package]]
|
||||
name = "notifications-python-client"
|
||||
version = "8.2.0"
|
||||
version = "9.0.0"
|
||||
description = "Python API client for GOV.UK Notify."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "notifications_python_client-8.2.0-py3-none-any.whl", hash = "sha256:8cd8bd01ae603a972a5413c430ca42b16f6481f37d98406c3e9b68c1c192f59e"},
|
||||
{file = "notifications_python_client-9.0.0-py3-none-any.whl", hash = "sha256:664a5b5da2aa1a00efa8106bfa4855db04da95d79586e5edfb0411637d20d2d9"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -2582,7 +2596,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 +2614,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 +2648,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"
|
||||
@@ -3192,13 +3206,13 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "pyflakes"
|
||||
version = "3.1.0"
|
||||
version = "3.2.0"
|
||||
description = "passive checker of Python programs"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pyflakes-3.1.0-py2.py3-none-any.whl", hash = "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774"},
|
||||
{file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"},
|
||||
{file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"},
|
||||
{file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3441,6 +3455,7 @@ files = [
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
|
||||
@@ -4717,4 +4732,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = ">=3.9,<3.12"
|
||||
content-hash = "a6d1d609f32455bcd4a1b2934512bba368d3bad792a032bb0e8e2b49f6f5f99a"
|
||||
content-hash = "f6d89a19888ec8a666200c9c2552434c0f9efb49fb0d29d69b56707bae47315a"
|
||||
|
||||
@@ -24,7 +24,7 @@ click-didyoumean = "==0.3.0"
|
||||
click-plugins = "==1.1.1"
|
||||
click-repl = "==0.3.0"
|
||||
deprecated = "==1.2.14"
|
||||
eventlet = "==0.34.3"
|
||||
eventlet = "==0.35.2"
|
||||
expiringdict = "==1.2.2"
|
||||
flask = "~=2.3"
|
||||
flask-bcrypt = "==1.0.1"
|
||||
@@ -39,7 +39,7 @@ lxml = "==5.1.0"
|
||||
marshmallow = "==3.20.2"
|
||||
marshmallow-sqlalchemy = "==0.30.0"
|
||||
newrelic = "*"
|
||||
notifications-python-client = "==8.2.0"
|
||||
notifications-python-client = "==9.0.0"
|
||||
notifications-utils = {git = "https://github.com/GSA/notifications-utils.git"}
|
||||
oscrypto = "==1.3.0"
|
||||
packaging = "==23.2"
|
||||
@@ -57,7 +57,7 @@ bandit = "*"
|
||||
black = "^23.12.1"
|
||||
cloudfoundry-client = "*"
|
||||
exceptiongroup = "==1.2.0"
|
||||
flake8 = "^6.1.0"
|
||||
flake8 = "^7.0.0"
|
||||
flake8-bugbear = "^24.1.17"
|
||||
freezegun = "^1.4.0"
|
||||
honcho = "*"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -149,10 +149,13 @@ def _stats(requested, delivered, failed):
|
||||
@pytest.mark.parametrize(
|
||||
"year, expected_years",
|
||||
[
|
||||
(2018, ["2018-04", "2018-05", "2018-06"]),
|
||||
(2018, ["2018-01", "2018-02", "2018-03", "2018-04", "2018-05", "2018-06"]),
|
||||
(
|
||||
2017,
|
||||
[
|
||||
"2017-01",
|
||||
"2017-02",
|
||||
"2017-03",
|
||||
"2017-04",
|
||||
"2017-05",
|
||||
"2017-06",
|
||||
@@ -162,9 +165,6 @@ def _stats(requested, delivered, failed):
|
||||
"2017-10",
|
||||
"2017-11",
|
||||
"2017-12",
|
||||
"2018-01",
|
||||
"2018-02",
|
||||
"2018-03",
|
||||
],
|
||||
),
|
||||
],
|
||||
@@ -220,8 +220,11 @@ def test_add_monthly_notification_status_stats():
|
||||
data["2018-05"]["sms"]["sending"] = 16
|
||||
|
||||
add_monthly_notification_status_stats(data, rows)
|
||||
|
||||
# first 3 months are empty
|
||||
assert data == {
|
||||
"2018-01": {"sms": {}, "email": {}},
|
||||
"2018-02": {"sms": {}, "email": {}},
|
||||
"2018-03": {"sms": {}, "email": {}},
|
||||
"2018-04": {"sms": {"sending": 1, "delivered": 2}, "email": {"sending": 4}},
|
||||
"2018-05": {"sms": {"sending": 24}, "email": {"sending": 32}},
|
||||
"2018-06": {"sms": {}, "email": {}},
|
||||
|
||||
@@ -177,6 +177,9 @@ def test_get_monthly_notification_stats_returns_empty_stats_with_correct_dates(
|
||||
assert len(response["data"]) == 12
|
||||
|
||||
keys = [
|
||||
"2016-01",
|
||||
"2016-02",
|
||||
"2016-03",
|
||||
"2016-04",
|
||||
"2016-05",
|
||||
"2016-06",
|
||||
@@ -186,9 +189,6 @@ def test_get_monthly_notification_stats_returns_empty_stats_with_correct_dates(
|
||||
"2016-10",
|
||||
"2016-11",
|
||||
"2016-12",
|
||||
"2017-01",
|
||||
"2017-02",
|
||||
"2017-03",
|
||||
]
|
||||
assert sorted(response["data"].keys()) == keys
|
||||
for val in response["data"].values():
|
||||
@@ -266,7 +266,7 @@ def test_get_monthly_notification_stats_combines_todays_data_and_historic_stats(
|
||||
year=2016,
|
||||
)
|
||||
|
||||
assert len(response["data"]) == 3 # apr, may, jun
|
||||
assert len(response["data"]) == 6 # January to June
|
||||
assert response["data"]["2016-05"] == {"sms": {"delivered": 1}, "email": {}}
|
||||
assert response["data"]["2016-06"] == {
|
||||
"sms": {
|
||||
|
||||
Reference in New Issue
Block a user