diff --git a/.github/workflows/build-docker-images.yml b/.github/workflows/build-docker-images.yml index e9b19e87cf..aaa96281de 100644 --- a/.github/workflows/build-docker-images.yml +++ b/.github/workflows/build-docker-images.yml @@ -38,8 +38,8 @@ on: default: us-east-1 type: choice options: - - us-east-1 - - us-west-2 + - us-east-1 + - us-west-2 required: true permissions: @@ -63,6 +63,13 @@ jobs: name: "bfd-mgmt-eft-sftp-outbound-transfer-lambda", dockerfile: "ops/jenkins/bfd-build-eft-sftp-outbound-transfer-lambda/Dockerfile", contextDir: "ops/terraform/services/eft/lambda_src/sftp_outbound_transfer", + platform: "linux/amd64", + }, + { + name: "bfd-mgmt-pipeline-ccw-manifests-verifier-lambda", + dockerfile: "ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/lambda_src/Dockerfile", + contextDir: "ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/lambda_src", + platform: "linux/arm64", }, ] runs-on: ubuntu-latest @@ -128,9 +135,9 @@ jobs: tags: ${{ steps.setup_tags.outputs.image_tags }} # AWS Lambda does not support multi-platform images, something that is enabled by default # by this Action via the "provenance" flag. Until AWS Lambda supports this feature - # properly, we must explicitly disable provenance and specify the amd64 platform. + # properly, we must explicitly disable provenance and specify the platform directly. # See https://github.com/docker/buildx/issues/1533 provenance: false - platforms: "linux/amd64" + platforms: ${{ matrix.image.platform }} env: DOCKER_BUILDKIT: 1 diff --git a/.gitignore b/.gitignore index 51a73044b1..b4cb866a13 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ !.github !.sensitive-files !.terraform-docs.yml +!.python-version # Ignore everything within top-level dist directory /dist/**/* diff --git a/apps/bfd-data-fda/pom.xml b/apps/bfd-data-fda/pom.xml index 8080790836..f535735101 100644 --- a/apps/bfd-data-fda/pom.xml +++ b/apps/bfd-data-fda/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT gov.cms.bfd.data.fda.utility diff --git a/apps/bfd-data-npi/pom.xml b/apps/bfd-data-npi/pom.xml index 9302cd6bd6..66197bd282 100644 --- a/apps/bfd-data-npi/pom.xml +++ b/apps/bfd-data-npi/pom.xml @@ -3,7 +3,7 @@ gov.cms.bfd bfd-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT gov.cms.bfd.data.npi diff --git a/apps/bfd-db-migrator/pom.xml b/apps/bfd-db-migrator/pom.xml index 2bf304a31d..113e6df8e5 100644 --- a/apps/bfd-db-migrator/pom.xml +++ b/apps/bfd-db-migrator/pom.xml @@ -5,7 +5,7 @@ gov.cms.bfd bfd-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-db-migrator diff --git a/apps/bfd-model/bfd-model-codebook-data/pom.xml b/apps/bfd-model/bfd-model-codebook-data/pom.xml index 8c17f3162f..c7e96b8582 100644 --- a/apps/bfd-model/bfd-model-codebook-data/pom.xml +++ b/apps/bfd-model/bfd-model-codebook-data/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-model-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-model-codebook-data diff --git a/apps/bfd-model/bfd-model-codebook-library/pom.xml b/apps/bfd-model/bfd-model-codebook-library/pom.xml index 12d171adce..31c4d73d79 100644 --- a/apps/bfd-model/bfd-model-codebook-library/pom.xml +++ b/apps/bfd-model/bfd-model-codebook-library/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-model-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-model-codebook-library diff --git a/apps/bfd-model/bfd-model-codebook-plugin/pom.xml b/apps/bfd-model/bfd-model-codebook-plugin/pom.xml index 7a157da2ac..0409468140 100644 --- a/apps/bfd-model/bfd-model-codebook-plugin/pom.xml +++ b/apps/bfd-model/bfd-model-codebook-plugin/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-model-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-model-codebook-plugin diff --git a/apps/bfd-model/bfd-model-dsl-codegen/bfd-model-dsl-codegen-library/pom.xml b/apps/bfd-model/bfd-model-dsl-codegen/bfd-model-dsl-codegen-library/pom.xml index 508aa12b82..078ec487db 100644 --- a/apps/bfd-model/bfd-model-dsl-codegen/bfd-model-dsl-codegen-library/pom.xml +++ b/apps/bfd-model/bfd-model-dsl-codegen/bfd-model-dsl-codegen-library/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-model-dsl-codegen-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-model-dsl-codegen-library diff --git a/apps/bfd-model/bfd-model-dsl-codegen/bfd-model-dsl-codegen-plugin/pom.xml b/apps/bfd-model/bfd-model-dsl-codegen/bfd-model-dsl-codegen-plugin/pom.xml index 73decad378..8bd28f2188 100644 --- a/apps/bfd-model/bfd-model-dsl-codegen/bfd-model-dsl-codegen-plugin/pom.xml +++ b/apps/bfd-model/bfd-model-dsl-codegen/bfd-model-dsl-codegen-plugin/pom.xml @@ -5,11 +5,11 @@ gov.cms.bfd bfd-model-dsl-codegen-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-model-dsl-codegen-plugin - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT maven-plugin diff --git a/apps/bfd-model/bfd-model-dsl-codegen/pom.xml b/apps/bfd-model/bfd-model-dsl-codegen/pom.xml index c2e6ee9164..5599b1c21d 100644 --- a/apps/bfd-model/bfd-model-dsl-codegen/pom.xml +++ b/apps/bfd-model/bfd-model-dsl-codegen/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-model-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-model-dsl-codegen-parent diff --git a/apps/bfd-model/bfd-model-rda/pom.xml b/apps/bfd-model/bfd-model-rda/pom.xml index 3b26d58c7f..1ef84308b9 100644 --- a/apps/bfd-model/bfd-model-rda/pom.xml +++ b/apps/bfd-model/bfd-model-rda/pom.xml @@ -5,7 +5,7 @@ gov.cms.bfd bfd-model-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-model-rda diff --git a/apps/bfd-model/bfd-model-rif-samples/pom.xml b/apps/bfd-model/bfd-model-rif-samples/pom.xml index f59406df63..04137a151c 100644 --- a/apps/bfd-model/bfd-model-rif-samples/pom.xml +++ b/apps/bfd-model/bfd-model-rif-samples/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-model-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-model-rif-samples diff --git a/apps/bfd-model/bfd-model-rif/mappings/PartDEvent.yaml b/apps/bfd-model/bfd-model-rif/mappings/PartDEvent.yaml index f1c20eef49..105ceedd16 100644 --- a/apps/bfd-model/bfd-model-rif/mappings/PartDEvent.yaml +++ b/apps/bfd-model/bfd-model-rif/mappings/PartDEvent.yaml @@ -67,7 +67,7 @@ mappings: dbName: prscrbr_id name: prescriberId nullable: false - sqlType: varchar(15) + sqlType: varchar(35) - comment: RX Service Reference Number (https://www.ccwdata.org/cs/groups/public/documents/datadictionary/rx_srvc_rfrnc_num.txt) dbName: rx_srvc_rfrnc_num name: prescriptionReferenceNumber @@ -77,7 +77,7 @@ mappings: dbName: prod_srvc_id name: nationalDrugCode nullable: false - sqlType: varchar(19) + sqlType: varchar(40) - comment: Plan Contract Record ID (https://www.ccwdata.org/cs/groups/public/documents/datadictionary/plan_cntrct_rec_id.txt) dbName: plan_cntrct_rec_id name: planContractId @@ -219,7 +219,7 @@ mappings: - comment: Submission Clarification Code (https://www.ccwdata.org/cs/groups/public/documents/datadictionary/submsn_clr_cd.txt) dbName: submsn_clr_cd name: submissionClarificationCode - sqlType: varchar(2) + sqlType: varchar(3) - comment: LAST_UPDATED (https://bluebutton.cms.gov/resources/variables/lastUpdated) dbName: last_updated name: lastUpdated diff --git a/apps/bfd-model/bfd-model-rif/pom.xml b/apps/bfd-model/bfd-model-rif/pom.xml index 059a4257ac..58996343ac 100644 --- a/apps/bfd-model/bfd-model-rif/pom.xml +++ b/apps/bfd-model/bfd-model-rif/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-model-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-model-rif diff --git a/apps/bfd-model/bfd-model-rif/src/main/resources/db/migration/V20250121143014662__update_pde_col_widths.sql b/apps/bfd-model/bfd-model-rif/src/main/resources/db/migration/V20250121143014662__update_pde_col_widths.sql new file mode 100644 index 0000000000..7f1d2be8bc --- /dev/null +++ b/apps/bfd-model/bfd-model-rif/src/main/resources/db/migration/V20250121143014662__update_pde_col_widths.sql @@ -0,0 +1,8 @@ +ALTER TABLE ccw.partd_events +ALTER COLUMN prscrbr_id type varchar(35); + +ALTER TABLE ccw.partd_events +ALTER COLUMN prod_srvc_id type varchar(40); + +ALTER TABLE ccw.partd_events +ALTER COLUMN submsn_clr_cd type varchar(3); diff --git a/apps/bfd-model/pom.xml b/apps/bfd-model/pom.xml index 562bb7b530..0f38797ee9 100644 --- a/apps/bfd-model/pom.xml +++ b/apps/bfd-model/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-model-parent diff --git a/apps/bfd-ops/pom.xml b/apps/bfd-ops/pom.xml index 8f503268b7..9f271c72e1 100644 --- a/apps/bfd-ops/pom.xml +++ b/apps/bfd-ops/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-ops diff --git a/apps/bfd-pipeline/bfd-pipeline-app/pom.xml b/apps/bfd-pipeline/bfd-pipeline-app/pom.xml index 78edba30ec..6f93ddc1b3 100644 --- a/apps/bfd-pipeline/bfd-pipeline-app/pom.xml +++ b/apps/bfd-pipeline/bfd-pipeline-app/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-pipeline-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-pipeline-app diff --git a/apps/bfd-pipeline/bfd-pipeline-ccw-rif/pom.xml b/apps/bfd-pipeline/bfd-pipeline-ccw-rif/pom.xml index 9a9de24ad9..b306ac80ff 100644 --- a/apps/bfd-pipeline/bfd-pipeline-ccw-rif/pom.xml +++ b/apps/bfd-pipeline/bfd-pipeline-ccw-rif/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-pipeline-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-pipeline-ccw-rif diff --git a/apps/bfd-pipeline/bfd-pipeline-rda-bridge/pom.xml b/apps/bfd-pipeline/bfd-pipeline-rda-bridge/pom.xml index 1d531f7b85..fcee5925ed 100644 --- a/apps/bfd-pipeline/bfd-pipeline-rda-bridge/pom.xml +++ b/apps/bfd-pipeline/bfd-pipeline-rda-bridge/pom.xml @@ -5,7 +5,7 @@ gov.cms.bfd bfd-pipeline-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-pipeline-rda-bridge diff --git a/apps/bfd-pipeline/bfd-pipeline-rda-grpc-apps/pom.xml b/apps/bfd-pipeline/bfd-pipeline-rda-grpc-apps/pom.xml index b3de49bd0e..bca8230dbd 100644 --- a/apps/bfd-pipeline/bfd-pipeline-rda-grpc-apps/pom.xml +++ b/apps/bfd-pipeline/bfd-pipeline-rda-grpc-apps/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-pipeline-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-pipeline-rda-grpc-apps diff --git a/apps/bfd-pipeline/bfd-pipeline-rda-grpc/pom.xml b/apps/bfd-pipeline/bfd-pipeline-rda-grpc/pom.xml index 34673236cd..f711b5b831 100644 --- a/apps/bfd-pipeline/bfd-pipeline-rda-grpc/pom.xml +++ b/apps/bfd-pipeline/bfd-pipeline-rda-grpc/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-pipeline-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-pipeline-rda-grpc diff --git a/apps/bfd-pipeline/bfd-pipeline-shared-test-utils/pom.xml b/apps/bfd-pipeline/bfd-pipeline-shared-test-utils/pom.xml index d6557495bc..5559245e75 100644 --- a/apps/bfd-pipeline/bfd-pipeline-shared-test-utils/pom.xml +++ b/apps/bfd-pipeline/bfd-pipeline-shared-test-utils/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-pipeline-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-pipeline-shared-test-utils diff --git a/apps/bfd-pipeline/bfd-pipeline-shared-utils/pom.xml b/apps/bfd-pipeline/bfd-pipeline-shared-utils/pom.xml index bfcd64ee4b..ad9d17274d 100644 --- a/apps/bfd-pipeline/bfd-pipeline-shared-utils/pom.xml +++ b/apps/bfd-pipeline/bfd-pipeline-shared-utils/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-pipeline-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-pipeline-shared-utils diff --git a/apps/bfd-pipeline/pom.xml b/apps/bfd-pipeline/pom.xml index 35033e4480..b7cbe59366 100644 --- a/apps/bfd-pipeline/pom.xml +++ b/apps/bfd-pipeline/pom.xml @@ -5,7 +5,7 @@ gov.cms.bfd bfd-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-pipeline-parent diff --git a/apps/bfd-server/bfd-server-docs/pom.xml b/apps/bfd-server/bfd-server-docs/pom.xml index d85bdf203f..04e1330de9 100644 --- a/apps/bfd-server/bfd-server-docs/pom.xml +++ b/apps/bfd-server/bfd-server-docs/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-server-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-server-docs diff --git a/apps/bfd-server/bfd-server-image/pom.xml b/apps/bfd-server/bfd-server-image/pom.xml index 13e09ecd6e..cf9fe30c28 100644 --- a/apps/bfd-server/bfd-server-image/pom.xml +++ b/apps/bfd-server/bfd-server-image/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-server-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-server-image diff --git a/apps/bfd-server/bfd-server-launcher-sample/pom.xml b/apps/bfd-server/bfd-server-launcher-sample/pom.xml index d41aede9ce..bc60c1b7c9 100644 --- a/apps/bfd-server/bfd-server-launcher-sample/pom.xml +++ b/apps/bfd-server/bfd-server-launcher-sample/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-server-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-server-launcher-sample diff --git a/apps/bfd-server/bfd-server-launcher/pom.xml b/apps/bfd-server/bfd-server-launcher/pom.xml index 831c8b034a..639b404492 100644 --- a/apps/bfd-server/bfd-server-launcher/pom.xml +++ b/apps/bfd-server/bfd-server-launcher/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-server-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-server-launcher diff --git a/apps/bfd-server/bfd-server-shared-utils/pom.xml b/apps/bfd-server/bfd-server-shared-utils/pom.xml index 236fbf6eb3..3e525f8b24 100644 --- a/apps/bfd-server/bfd-server-shared-utils/pom.xml +++ b/apps/bfd-server/bfd-server-shared-utils/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-server-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-server-shared-utils diff --git a/apps/bfd-server/bfd-server-war/pom.xml b/apps/bfd-server/bfd-server-war/pom.xml index 7c2573700c..f3c1d90386 100644 --- a/apps/bfd-server/bfd-server-war/pom.xml +++ b/apps/bfd-server/bfd-server-war/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-server-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-server-war diff --git a/apps/bfd-server/pom.xml b/apps/bfd-server/pom.xml index 52f362d2b8..004debf703 100644 --- a/apps/bfd-server/pom.xml +++ b/apps/bfd-server/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-server-parent diff --git a/apps/bfd-shared-test-utils/pom.xml b/apps/bfd-shared-test-utils/pom.xml index c6d53ff6f2..90f6a5c7c2 100644 --- a/apps/bfd-shared-test-utils/pom.xml +++ b/apps/bfd-shared-test-utils/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-shared-test-utils diff --git a/apps/bfd-shared-utils/pom.xml b/apps/bfd-shared-utils/pom.xml index f48b4c3aa4..da61ec2953 100644 --- a/apps/bfd-shared-utils/pom.xml +++ b/apps/bfd-shared-utils/pom.xml @@ -4,7 +4,7 @@ gov.cms.bfd bfd-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT bfd-shared-utils diff --git a/apps/pom.xml b/apps/pom.xml index 05b750dc59..50050919dc 100644 --- a/apps/pom.xml +++ b/apps/pom.xml @@ -3,7 +3,7 @@ gov.cms.bfd bfd-parent - 2.175.0-SNAPSHOT + 2.176.0-SNAPSHOT pom bfd-parent @@ -65,7 +65,7 @@ 21 - 2025-01-16T21:29:31Z + 2025-01-22T16:46:25Z true jacoco diff --git a/apps/utils/locust_tests/README.md b/apps/utils/locust_tests/README.md index b9a3c0e9dc..d64f78bb8d 100644 --- a/apps/utils/locust_tests/README.md +++ b/apps/utils/locust_tests/README.md @@ -9,7 +9,7 @@ to avoid caching affecting the response times of repeat runs. These tests are intended to be run from a server instance which has access permissions to reach out to the BFD endpoints. How to do this is outside the scope of this document, but instructions for this can be found in this more detailed run guide on confluence: -https://confluence.cms.gov/display/BB2/Run+the+BFD+Load+Tests. +https://confluence.cms.gov/display/BFD/2022+Run+the+BFD+Load+Tests. The following test suites ([Locustfiles](https://docs.locust.io/en/stable/writing-a-locustfile.html)) are available to run: @@ -22,7 +22,7 @@ The following test suites ([Locustfiles](https://docs.locust.io/en/stable/writin | Load Testing Suite | `high_volume_suite.py` | Used to exhibit distributed load on a target BFD Server to produce performance metrics under stress. Invoked by the `bfd-run-server-load` Jenkins pipeline job | ## Dependencies -> **Important:** This project is targeting Python 3.8. Ensure that your local Python is version 3.8 **before** attempting to work in this project! +> **Important:** This project is targeting Python 3.11. Ensure that your local Python is version 3.11 **before** attempting to work in this project! > A good utility for managing multiple Python versions along with [virtualenv](https://virtualenv.pypa.io/en/latest/)s is [`pew`](https://github.com/berdario/pew). The tests use a few python libraries that will need to be installed on the run box prior to starting the tests. diff --git a/apps/utils/locust_tests/dev-requirements.txt b/apps/utils/locust_tests/dev-requirements.txt index b098adfb28..f59c5e6e2d 100644 --- a/apps/utils/locust_tests/dev-requirements.txt +++ b/apps/utils/locust_tests/dev-requirements.txt @@ -2,7 +2,7 @@ # This file is autogenerated by pip-compile with Python 3.11 # by the following command: # -# pip-compile --allow-unsafe --constraint=requirements.txt --generate-hashes --output-file=dev-requirements.txt dev-requirements.in +# pip-compile --allow-unsafe --constraint=requirements.txt --generate-hashes --no-reuse-hashes --output-file=dev-requirements.txt --strip-extras dev-requirements.in # astroid==2.15.6 \ --hash=sha256:389656ca57b6108f939cf5d2f9a2a825a3be50ba9d589670f393236e0a03b91c \ diff --git a/apps/utils/locust_tests/requirements.in b/apps/utils/locust_tests/requirements.in index 54060f62c3..e3b3972cb0 100644 --- a/apps/utils/locust_tests/requirements.in +++ b/apps/utils/locust_tests/requirements.in @@ -6,9 +6,9 @@ setuptools>=70.0.0 flask==2.3.3 flask-cors==5.0.0 requests==2.32.2 -gevent==23.9.1 +gevent==24.10.1 urllib3==1.26.19 -werkzeug==3.0.3 -jinja2==3.1.4 +werkzeug==3.0.6 +jinja2==3.1.5 idna>=3.7 certifi==2024.7.4 \ No newline at end of file diff --git a/apps/utils/locust_tests/requirements.txt b/apps/utils/locust_tests/requirements.txt index c571c41860..a747c2009c 100644 --- a/apps/utils/locust_tests/requirements.txt +++ b/apps/utils/locust_tests/requirements.txt @@ -2,7 +2,7 @@ # This file is autogenerated by pip-compile with Python 3.11 # by the following command: # -# pip-compile --allow-unsafe --generate-hashes --no-reuse-hashes --output-file=requirements.txt requirements.in +# pip-compile --allow-unsafe --generate-hashes --no-reuse-hashes --output-file=requirements.txt --strip-extras requirements.in # blinker==1.6.3 \ --hash=sha256:152090d27c1c5c722ee7e48504b02d76502811ce02e1523553b4cf8c8b3d3a8d \ @@ -22,6 +22,7 @@ brotli==1.1.0 \ --hash=sha256:03d20af184290887bdea3f0f78c4f737d126c74dc2f3ccadf07e54ceca3bf208 \ --hash=sha256:0541e747cce78e24ea12d69176f6a7ddb690e62c425e01d31cc065e69ce55b48 \ --hash=sha256:069a121ac97412d1fe506da790b3e69f52254b9df4eb665cd42460c837193354 \ + --hash=sha256:0737ddb3068957cf1b054899b0883830bb1fec522ec76b1098f9b6e0f02d9419 \ --hash=sha256:0b63b949ff929fbc2d6d3ce0e924c9b93c9785d877a21a1b678877ffbbc4423a \ --hash=sha256:0c6244521dda65ea562d5a69b9a26120769b7a9fb3db2fe9545935ed6735b128 \ --hash=sha256:11d00ed0a83fa22d29bc6b64ef636c4552ebafcef57154b4ddd132f5638fbd1c \ @@ -29,43 +30,67 @@ brotli==1.1.0 \ --hash=sha256:19c116e796420b0cee3da1ccec3b764ed2952ccfcc298b55a10e5610ad7885f9 \ --hash=sha256:1ab4fbee0b2d9098c74f3057b2bc055a8bd92ccf02f65944a241b4349229185a \ --hash=sha256:1ae56aca0402a0f9a3431cddda62ad71666ca9d4dc3a10a142b9dce2e3c0cda3 \ + --hash=sha256:1b2c248cd517c222d89e74669a4adfa5577e06ab68771a529060cf5a156e9757 \ + --hash=sha256:1e9a65b5736232e7a7f91ff3d02277f11d339bf34099a56cdab6a8b3410a02b2 \ --hash=sha256:224e57f6eac61cc449f498cc5f0e1725ba2071a3d4f48d5d9dffba42db196438 \ --hash=sha256:22fc2a8549ffe699bfba2256ab2ed0421a7b8fadff114a3d201794e45a9ff578 \ --hash=sha256:23032ae55523cc7bccb4f6a0bf368cd25ad9bcdcc1990b64a647e7bbcce9cb5b \ --hash=sha256:2333e30a5e00fe0fe55903c8832e08ee9c3b1382aacf4db26664a16528d51b4b \ --hash=sha256:2954c1c23f81c2eaf0b0717d9380bd348578a94161a65b3a2afc62c86467dd68 \ + --hash=sha256:2a24c50840d89ded6c9a8fdc7b6ed3692ed4e86f1c4a4a938e1e92def92933e0 \ --hash=sha256:2de9d02f5bda03d27ede52e8cfe7b865b066fa49258cbab568720aa5be80a47d \ + --hash=sha256:2feb1d960f760a575dbc5ab3b1c00504b24caaf6986e2dc2b01c09c87866a943 \ --hash=sha256:30924eb4c57903d5a7526b08ef4a584acc22ab1ffa085faceb521521d2de32dd \ --hash=sha256:316cc9b17edf613ac76b1f1f305d2a748f1b976b033b049a6ecdfd5612c70409 \ + --hash=sha256:32d95b80260d79926f5fab3c41701dbb818fde1c9da590e77e571eefd14abe28 \ --hash=sha256:38025d9f30cf4634f8309c6874ef871b841eb3c347e90b0851f63d1ded5212da \ --hash=sha256:39da8adedf6942d76dc3e46653e52df937a3c4d6d18fdc94a7c29d263b1f5b50 \ + --hash=sha256:3c0ef38c7a7014ffac184db9e04debe495d317cc9c6fb10071f7fefd93100a4f \ --hash=sha256:3d7954194c36e304e1523f55d7042c59dc53ec20dd4e9ea9d151f1b62b4415c0 \ + --hash=sha256:3ee8a80d67a4334482d9712b8e83ca6b1d9bc7e351931252ebef5d8f7335a547 \ --hash=sha256:4093c631e96fdd49e0377a9c167bfd75b6d0bad2ace734c6eb20b348bc3ea180 \ + --hash=sha256:43395e90523f9c23a3d5bdf004733246fba087f2948f87ab28015f12359ca6a0 \ --hash=sha256:43ce1b9935bfa1ede40028054d7f48b5469cd02733a365eec8a329ffd342915d \ + --hash=sha256:4410f84b33374409552ac9b6903507cdb31cd30d2501fc5ca13d18f73548444a \ + --hash=sha256:494994f807ba0b92092a163a0a283961369a65f6cbe01e8891132b7a320e61eb \ --hash=sha256:4d4a848d1837973bf0f4b5e54e3bec977d99be36a7895c61abb659301b02c112 \ --hash=sha256:4ed11165dd45ce798d99a136808a794a748d5dc38511303239d4e2363c0695dc \ + --hash=sha256:4f3607b129417e111e30637af1b56f24f7a49e64763253bbc275c75fa887d4b2 \ --hash=sha256:510b5b1bfbe20e1a7b3baf5fed9e9451873559a976c1a78eebaa3b86c57b4265 \ --hash=sha256:524f35912131cc2cabb00edfd8d573b07f2d9f21fa824bd3fb19725a9cf06327 \ --hash=sha256:587ca6d3cef6e4e868102672d3bd9dc9698c309ba56d41c2b9c85bbb903cdb95 \ + --hash=sha256:58d4b711689366d4a03ac7957ab8c28890415e267f9b6589969e74b6e42225ec \ --hash=sha256:5b3cc074004d968722f51e550b41a27be656ec48f8afaeeb45ebf65b561481dd \ + --hash=sha256:5dab0844f2cf82be357a0eb11a9087f70c5430b2c241493fc122bb6f2bb0917c \ + --hash=sha256:5e55da2c8724191e5b557f8e18943b1b4839b8efc3ef60d65985bcf6f587dd38 \ --hash=sha256:5eeb539606f18a0b232d4ba45adccde4125592f3f636a6182b4a8a436548b914 \ --hash=sha256:5f4d5ea15c9382135076d2fb28dde923352fe02951e66935a9efaac8f10e81b0 \ --hash=sha256:5fb2ce4b8045c78ebbc7b8f3c15062e435d47e7393cc57c25115cfd49883747a \ --hash=sha256:6172447e1b368dcbc458925e5ddaf9113477b0ed542df258d84fa28fc45ceea7 \ + --hash=sha256:6967ced6730aed543b8673008b5a391c3b1076d834ca438bbd70635c73775368 \ + --hash=sha256:6974f52a02321b36847cd19d1b8e381bf39939c21efd6ee2fc13a28b0d99348c \ --hash=sha256:6c3020404e0b5eefd7c9485ccf8393cfb75ec38ce75586e046573c9dc29967a0 \ + --hash=sha256:6c6e0c425f22c1c719c42670d561ad682f7bfeeef918edea971a79ac5252437f \ --hash=sha256:70051525001750221daa10907c77830bc889cb6d865cc0b813d9db7fefc21451 \ --hash=sha256:7905193081db9bfa73b1219140b3d315831cbff0d8941f22da695832f0dd188f \ + --hash=sha256:7bc37c4d6b87fb1017ea28c9508b36bbcb0c3d18b4260fcdf08b200c74a6aee8 \ --hash=sha256:7c4855522edb2e6ae7fdb58e07c3ba9111e7621a8956f481c68d5d979c93032e \ --hash=sha256:7e4c4629ddad63006efa0ef968c8e4751c5868ff0b1c5c40f76524e894c50248 \ + --hash=sha256:7eedaa5d036d9336c95915035fb57422054014ebdeb6f3b42eac809928e40d0c \ --hash=sha256:7f4bf76817c14aa98cc6697ac02f3972cb8c3da93e9ef16b9c66573a68014f91 \ --hash=sha256:81de08ac11bcb85841e440c13611c00b67d3bf82698314928d0b676362546724 \ + --hash=sha256:832436e59afb93e1836081a20f324cb185836c617659b07b129141a8426973c7 \ --hash=sha256:861bf317735688269936f755fa136a99d1ed526883859f86e41a5d43c61d8966 \ + --hash=sha256:87a3044c3a35055527ac75e419dfa9f4f3667a1e887ee80360589eb8c90aabb9 \ --hash=sha256:890b5a14ce214389b2cc36ce82f3093f96f4cc730c1cffdbefff77a7c71f2a97 \ --hash=sha256:89f4988c7203739d48c6f806f1e87a1d96e0806d44f0fba61dba81392c9e474d \ + --hash=sha256:8bf32b98b75c13ec7cf774164172683d6e7891088f6316e54425fde1efc276d5 \ --hash=sha256:8dadd1314583ec0bf2d1379f7008ad627cd6336625d6679cf2f8e67081b83acf \ --hash=sha256:901032ff242d479a0efa956d853d16875d42157f98951c0230f69e69f9c09bac \ + --hash=sha256:9011560a466d2eb3f5a6e4929cf4a09be405c64154e12df0dd72713f6500e32b \ --hash=sha256:906bc3a79de8c4ae5b86d3d75a8b77e44404b0f4261714306e3ad248d8ab0951 \ --hash=sha256:919e32f147ae93a09fe064d77d5ebf4e35502a8df75c29fb05788528e330fe74 \ + --hash=sha256:91d7cc2a76b5567591d12c01f019dd7afce6ba8cba6571187e21e2fc418ae648 \ --hash=sha256:929811df5462e182b13920da56c6e0284af407d1de637d8e536c5cd00a7daf60 \ --hash=sha256:949f3b7c29912693cee0afcf09acd6ebc04c57af949d9bf77d6101ebb61e388c \ --hash=sha256:a090ca607cbb6a34b0391776f0cb48062081f5f60ddcce5d11838e67a01928d1 \ @@ -76,27 +101,44 @@ brotli==1.1.0 \ --hash=sha256:a599669fd7c47233438a56936988a2478685e74854088ef5293802123b5b2460 \ --hash=sha256:a743e5a28af5f70f9c080380a5f908d4d21d40e8f0e0c8901604d15cfa9ba751 \ --hash=sha256:a77def80806c421b4b0af06f45d65a136e7ac0bdca3c09d9e2ea4e515367c7e9 \ + --hash=sha256:a7e53012d2853a07a4a79c00643832161a910674a893d296c9f1259859a289d2 \ + --hash=sha256:a93dde851926f4f2678e704fadeb39e16c35d8baebd5252c9fd94ce8ce68c4a0 \ --hash=sha256:aac0411d20e345dc0920bdec5548e438e999ff68d77564d5e9463a7ca9d3e7b1 \ --hash=sha256:ae15b066e5ad21366600ebec29a7ccbc86812ed267e4b28e860b8ca16a2bc474 \ + --hash=sha256:aea440a510e14e818e67bfc4027880e2fb500c2ccb20ab21c7a7c8b5b4703d75 \ + --hash=sha256:af6fa6817889314555aede9a919612b23739395ce767fe7fcbea9a80bf140fe5 \ + --hash=sha256:b760c65308ff1e462f65d69c12e4ae085cff3b332d894637f6273a12a482d09f \ --hash=sha256:be36e3d172dc816333f33520154d708a2657ea63762ec16b62ece02ab5e4daf2 \ + --hash=sha256:c247dd99d39e0338a604f8c2b3bc7061d5c2e9e2ac7ba9cc1be5a69cb6cd832f \ + --hash=sha256:c5529b34c1c9d937168297f2c1fde7ebe9ebdd5e121297ff9c043bdb2ae3d6fb \ --hash=sha256:c8146669223164fc87a7e3de9f81e9423c67a79d6b3447994dfb9c95da16e2d6 \ --hash=sha256:c8fd5270e906eef71d4a8d19b7c6a43760c6abcfcc10c9101d14eb2357418de9 \ + --hash=sha256:ca63e1890ede90b2e4454f9a65135a4d387a4585ff8282bb72964fab893f2111 \ --hash=sha256:caf9ee9a5775f3111642d33b86237b05808dafcd6268faa492250e9b78046eb2 \ + --hash=sha256:cb1dac1770878ade83f2ccdf7d25e494f05c9165f5246b46a621cc849341dc01 \ --hash=sha256:cdad5b9014d83ca68c25d2e9444e28e967ef16e80f6b436918c700c117a85467 \ --hash=sha256:cdbc1fc1bc0bff1cef838eafe581b55bfbffaed4ed0318b724d0b71d4d377619 \ --hash=sha256:ceb64bbc6eac5a140ca649003756940f8d6a7c444a68af170b3187623b43bebf \ --hash=sha256:d0c5516f0aed654134a2fc936325cc2e642f8a0e096d075209672eb321cff408 \ --hash=sha256:d143fd47fad1db3d7c27a1b1d66162e855b5d50a89666af46e1679c496e8e579 \ --hash=sha256:d192f0f30804e55db0d0e0a35d83a9fead0e9a359a9ed0285dbacea60cc10a84 \ + --hash=sha256:d2b35ca2c7f81d173d2fadc2f4f31e88cc5f7a39ae5b6db5513cf3383b0e0ec7 \ + --hash=sha256:d342778ef319e1026af243ed0a07c97acf3bad33b9f29e7ae6a1f68fd083e90c \ + --hash=sha256:d487f5432bf35b60ed625d7e1b448e2dc855422e87469e3f450aa5552b0eb284 \ + --hash=sha256:d7702622a8b40c49bffb46e1e3ba2e81268d5c04a34f460978c6b5517a34dd52 \ --hash=sha256:db85ecf4e609a48f4b29055f1e144231b90edc90af7481aa731ba2d059226b1b \ --hash=sha256:de6551e370ef19f8de1807d0a9aa2cdfdce2e85ce88b122fe9f6b2b076837e59 \ --hash=sha256:e1140c64812cb9b06c922e77f1c26a75ec5e3f0fb2bf92cc8c58720dec276752 \ + --hash=sha256:e4fe605b917c70283db7dfe5ada75e04561479075761a0b3866c081d035b01c1 \ --hash=sha256:e6a904cb26bfefc2f0a6f240bdf5233be78cd2488900a2f846f3c3ac8489ab80 \ + --hash=sha256:e79e6520141d792237c70bcd7a3b122d00f2613769ae0cb61c52e89fd3443839 \ --hash=sha256:e84799f09591700a4154154cab9787452925578841a94321d5ee8fb9a9a328f0 \ --hash=sha256:e93dfc1a1165e385cc8239fab7c036fb2cd8093728cbd85097b284d7b99249a2 \ --hash=sha256:efa8b278894b14d6da122a72fefcebc28445f2d3f880ac59d46c90f4c13be9a3 \ --hash=sha256:f0d8a7a6b5983c2496e364b969f0e526647a06b075d034f3297dc66f3b360c64 \ + --hash=sha256:f0db75f47be8b8abc8d9e31bc7aad0547ca26f24a54e6fd10231d623f183d089 \ --hash=sha256:f296c40e23065d0d6650c4aefe7470d2a25fffda489bcc3eb66083f3ac9f6643 \ + --hash=sha256:f31859074d57b4639318523d6ffdca586ace54271a73ad23ad021acd807eb14b \ --hash=sha256:f66b5337fa213f1da0d9000bc8dc0cb5b896b726eefd9c6046f699b169c41b9e \ --hash=sha256:f733d788519c7e3e71f0855c96618720f5d3d60c3cb829d8bbb722dddce37985 \ --hash=sha256:fce1473f3ccc4187f75b4690cfc922628aed4d3dd013d047f95a9b3919a86596 \ @@ -227,47 +269,45 @@ flask-cors==5.0.0 \ # via # -r requirements.in # locust -gevent==23.9.1 \ - --hash=sha256:272cffdf535978d59c38ed837916dfd2b5d193be1e9e5dcc60a5f4d5025dd98a \ - --hash=sha256:2c7b5c9912378e5f5ccf180d1fdb1e83f42b71823483066eddbe10ef1a2fcaa2 \ - --hash=sha256:36a549d632c14684bcbbd3014a6ce2666c5f2a500f34d58d32df6c9ea38b6535 \ - --hash=sha256:4368f341a5f51611411ec3fc62426f52ac3d6d42eaee9ed0f9eebe715c80184e \ - --hash=sha256:43daf68496c03a35287b8b617f9f91e0e7c0d042aebcc060cadc3f049aadd653 \ - --hash=sha256:455e5ee8103f722b503fa45dedb04f3ffdec978c1524647f8ba72b4f08490af1 \ - --hash=sha256:45792c45d60f6ce3d19651d7fde0bc13e01b56bb4db60d3f32ab7d9ec467374c \ - --hash=sha256:4e24c2af9638d6c989caffc691a039d7c7022a31c0363da367c0d32ceb4a0648 \ - --hash=sha256:52b4abf28e837f1865a9bdeef58ff6afd07d1d888b70b6804557e7908032e599 \ - --hash=sha256:52e9f12cd1cda96603ce6b113d934f1aafb873e2c13182cf8e86d2c5c41982ea \ - --hash=sha256:5f3c781c84794926d853d6fb58554dc0dcc800ba25c41d42f6959c344b4db5a6 \ - --hash=sha256:62d121344f7465e3739989ad6b91f53a6ca9110518231553fe5846dbe1b4518f \ - --hash=sha256:65883ac026731ac112184680d1f0f1e39fa6f4389fd1fc0bf46cc1388e2599f9 \ - --hash=sha256:707904027d7130ff3e59ea387dddceedb133cc742b00b3ffe696d567147a9c9e \ - --hash=sha256:72c002235390d46f94938a96920d8856d4ffd9ddf62a303a0d7c118894097e34 \ - --hash=sha256:7532c17bc6c1cbac265e751b95000961715adef35a25d2b0b1813aa7263fb397 \ - --hash=sha256:78eebaf5e73ff91d34df48f4e35581ab4c84e22dd5338ef32714264063c57507 \ - --hash=sha256:7c1abc6f25f475adc33e5fc2dbcc26a732608ac5375d0d306228738a9ae14d3b \ - --hash=sha256:7c28e38dcde327c217fdafb9d5d17d3e772f636f35df15ffae2d933a5587addd \ - --hash=sha256:7ccf0fd378257cb77d91c116e15c99e533374a8153632c48a3ecae7f7f4f09fe \ - --hash=sha256:921dda1c0b84e3d3b1778efa362d61ed29e2b215b90f81d498eb4d8eafcd0b7a \ - --hash=sha256:a2898b7048771917d85a1d548fd378e8a7b2ca963db8e17c6d90c76b495e0e2b \ - --hash=sha256:a3c5e9b1f766a7a64833334a18539a362fb563f6c4682f9634dea72cbe24f771 \ - --hash=sha256:ada07076b380918829250201df1d016bdafb3acf352f35e5693b59dceee8dd2e \ - --hash=sha256:b101086f109168b23fa3586fccd1133494bdb97f86920a24dc0b23984dc30b69 \ - --hash=sha256:bf456bd6b992eb0e1e869e2fd0caf817f0253e55ca7977fd0e72d0336a8c1c6a \ - --hash=sha256:bf7af500da05363e66f122896012acb6e101a552682f2352b618e541c941a011 \ - --hash=sha256:c3e5d2fa532e4d3450595244de8ccf51f5721a05088813c1abd93ad274fe15e7 \ - --hash=sha256:c84d34256c243b0a53d4335ef0bc76c735873986d478c53073861a92566a8d71 \ - --hash=sha256:d163d59f1be5a4c4efcdd13c2177baaf24aadf721fdf2e1af9ee54a998d160f5 \ - --hash=sha256:d57737860bfc332b9b5aa438963986afe90f49645f6e053140cfa0fa1bdae1ae \ - --hash=sha256:dbb22a9bbd6a13e925815ce70b940d1578dbe5d4013f20d23e8a11eddf8d14a7 \ - --hash=sha256:dcb8612787a7f4626aa881ff15ff25439561a429f5b303048f0fca8a1c781c39 \ - --hash=sha256:dd6c32ab977ecf7c7b8c2611ed95fa4aaebd69b74bf08f4b4960ad516861517d \ - --hash=sha256:de350fde10efa87ea60d742901e1053eb2127ebd8b59a7d3b90597eb4e586599 \ - --hash=sha256:e1ead6863e596a8cc2a03e26a7a0981f84b6b3e956101135ff6d02df4d9a6b07 \ - --hash=sha256:ed7a048d3e526a5c1d55c44cb3bc06cfdc1947d06d45006cc4cf60dedc628904 \ - --hash=sha256:f632487c87866094546a74eefbca2c74c1d03638b715b6feb12e80120960185a \ - --hash=sha256:fae8d5b5b8fa2a8f63b39f5447168b02db10c888a3e387ed7af2bd1b8612e543 \ - --hash=sha256:fde6402c5432b835fbb7698f1c7f2809c8d6b2bd9d047ac1f5a7c1d5aa569303 +gevent==24.10.1 \ + --hash=sha256:075c72450103c6d151c1b5c96dca0c991b61655e50e6947ab9e08a532788f976 \ + --hash=sha256:0b6e3f64694bdf90c245bc3b17468542c9b222a087c8ae2f67850351c7ebb6dd \ + --hash=sha256:1281474d088f8d708adb1e87d6acdde3d5f936ee1bc4722d75ac623f4e1ccdf7 \ + --hash=sha256:14948bd7dae9784d83a2f7ebf51c70d3d53684723f4a78a5e4a368187bc9bccd \ + --hash=sha256:16b96b0abe1473e27849800a1f3241ec05a09a06da14be33207a5e2b7a982711 \ + --hash=sha256:28028532c286003da2fab4380f3c82ea4042147a5119518693578ef8aec36c84 \ + --hash=sha256:2bf4ab090ea02e528d6c92e51be1a3797f65a5be325d896d7edb267d89ea34c8 \ + --hash=sha256:34bdcaba413f3a0b2bd3432e41dd12dd3b915e19ae683e7cdb5a71514186980e \ + --hash=sha256:3f14933aa07babdfee1b1552d5eb46573c422132f25692dbd72cef2583d8f34a \ + --hash=sha256:40e16c27e9d114b5dd6f6e03b705ca849fd8563a291613d09f7822a5bcbfe4d2 \ + --hash=sha256:415da2f25e835a1d0750b75dc883a570319a41051bd26b024a709227ec86a78b \ + --hash=sha256:42bce9eae88b8cdad092a913ead9a4c81310708993120982c7539bd1eb1425cf \ + --hash=sha256:477fc1a09dd61544d2c53b1cfc4775996e27cfb549a5eb00ed6db4175a34b046 \ + --hash=sha256:539b833b6c8a729ed9d8010d14de1fe5a7eea7db51abdc585e95640d0c65ae54 \ + --hash=sha256:5e46ff8f4dfe99f5c2fe74f5d68785bb116100f4d23e55e7b0479bff811a0819 \ + --hash=sha256:63aacdc8067fc66c7d50e845e8d407c6027ff7d88aed13b761337855c0dae50d \ + --hash=sha256:6b081a761919ba84f7f48b99622304404da32a9aec721ba8648dbcab147b07b9 \ + --hash=sha256:6dd5a32e3f6cf8d317ef1e2ed9f380f957881d31b04f3a1b92d900d918a06c16 \ + --hash=sha256:71eb75e8421d44f3abec0b79f85df51e68c59831156f5b25a8891201d3049b5e \ + --hash=sha256:75b5e85a88b95b4dc62cac60bdf17bb6ab0ab99b44cbb5d1833218a209694f2e \ + --hash=sha256:7bf86426936211876149d4b75980987042313a3548d466b04cd1713d1aab7d28 \ + --hash=sha256:816834f9eef17864c87390ea8e6ccbf8aecab84b84c683ec5f2a95aea00a748e \ + --hash=sha256:818e4b608cfdcb00a1ee7b19622e2bc31613fddc34747f0d16b611f16f6e3fb2 \ + --hash=sha256:92d1e3afbec8cb4b7897be629aea524da237163adcf2a38d0795e6fd479699f6 \ + --hash=sha256:9abd11884562ec108fe8271edcd942453ae0e4d68565c8616045cf40ba9ed8f6 \ + --hash=sha256:9be9a2d3d9c0829077dc22ec1be2d906fd57204bb0a7810fcb3bcfc1521a8507 \ + --hash=sha256:a1a480e5f2f109a2597dd2aab8b59606d79ef05e95fe84c9ac76461873e3ada0 \ + --hash=sha256:b3dfea44933f6fc10e060b240ec1c25f3e94616d5a0c4f4146f6bf365d616bab \ + --hash=sha256:bb15f6eff0a030f6e74e2fe44dff0884cb31489ad0e89402f3d5dfd2928f6e85 \ + --hash=sha256:c4007fba5f95191c77dfad54fc70011f1c927fbef11d4ae5779796037436efe4 \ + --hash=sha256:cab473b6fb7ea67827ce8ffbd769c00044a8e29c3e0de4254c1b95a0bb8ff186 \ + --hash=sha256:cc2d9ee27126ab25b1d183841a5577ce2cf3aa15ab521cce4534f6d826d3e0f3 \ + --hash=sha256:d7d13100489e984c75d7cc31c0ba99ffb295ae39ced392630711ab0b88b41e54 \ + --hash=sha256:e161df2af05ffafa99937f33bf8a41c326e831889bd2aa556c0b07f45a46732f \ + --hash=sha256:e51cb033d25cbf4b646d80adad3574cff70aa923d71f233953910115ebc9ba17 \ + --hash=sha256:e6bf97a51fbda758011808436c18a17105fb2e75050eb521f79a0fa36c77f755 \ + --hash=sha256:ed46d2a6b3e97b6449e061d21229f8c8a2719502579a107f094e4731a69b601c \ + --hash=sha256:ee7ce02499eb684b2d377a294a6de136ed12158b500cebeb499dda1105ebcf0a # via # -r requirements.in # geventhttpclient @@ -382,64 +422,80 @@ geventhttpclient==2.0.11 \ --hash=sha256:f509176bc7754b1181375a25ec6909425a5997e58c98ea29a36fe8b6a376852f \ --hash=sha256:f5d73be013a7a2a357eb27d18e5990c773365f63f50a43eaf357d6efb1fd46a6 # via locust -greenlet==3.0.1 \ - --hash=sha256:0a02d259510b3630f330c86557331a3b0e0c79dac3d166e449a39363beaae174 \ - --hash=sha256:0b6f9f8ca7093fd4433472fd99b5650f8a26dcd8ba410e14094c1e44cd3ceddd \ - --hash=sha256:100f78a29707ca1525ea47388cec8a049405147719f47ebf3895e7509c6446aa \ - --hash=sha256:1757936efea16e3f03db20efd0cd50a1c86b06734f9f7338a90c4ba85ec2ad5a \ - --hash=sha256:19075157a10055759066854a973b3d1325d964d498a805bb68a1f9af4aaef8ec \ - --hash=sha256:19bbdf1cce0346ef7341705d71e2ecf6f41a35c311137f29b8a2dc2341374565 \ - --hash=sha256:20107edf7c2c3644c67c12205dc60b1bb11d26b2610b276f97d666110d1b511d \ - --hash=sha256:22f79120a24aeeae2b4471c711dcf4f8c736a2bb2fabad2a67ac9a55ea72523c \ - --hash=sha256:2847e5d7beedb8d614186962c3d774d40d3374d580d2cbdab7f184580a39d234 \ - --hash=sha256:28e89e232c7593d33cac35425b58950789962011cc274aa43ef8865f2e11f46d \ - --hash=sha256:329c5a2e5a0ee942f2992c5e3ff40be03e75f745f48847f118a3cfece7a28546 \ - --hash=sha256:337322096d92808f76ad26061a8f5fccb22b0809bea39212cd6c406f6a7060d2 \ - --hash=sha256:3fcc780ae8edbb1d050d920ab44790201f027d59fdbd21362340a85c79066a74 \ - --hash=sha256:41bdeeb552d814bcd7fb52172b304898a35818107cc8778b5101423c9017b3de \ - --hash=sha256:4eddd98afc726f8aee1948858aed9e6feeb1758889dfd869072d4465973f6bfd \ - --hash=sha256:52e93b28db27ae7d208748f45d2db8a7b6a380e0d703f099c949d0f0d80b70e9 \ - --hash=sha256:55d62807f1c5a1682075c62436702aaba941daa316e9161e4b6ccebbbf38bda3 \ - --hash=sha256:5805e71e5b570d490938d55552f5a9e10f477c19400c38bf1d5190d760691846 \ - --hash=sha256:599daf06ea59bfedbec564b1692b0166a0045f32b6f0933b0dd4df59a854caf2 \ - --hash=sha256:60d5772e8195f4e9ebf74046a9121bbb90090f6550f81d8956a05387ba139353 \ - --hash=sha256:696d8e7d82398e810f2b3622b24e87906763b6ebfd90e361e88eb85b0e554dc8 \ - --hash=sha256:6e6061bf1e9565c29002e3c601cf68569c450be7fc3f7336671af7ddb4657166 \ - --hash=sha256:80ac992f25d10aaebe1ee15df45ca0d7571d0f70b645c08ec68733fb7a020206 \ - --hash=sha256:816bd9488a94cba78d93e1abb58000e8266fa9cc2aa9ccdd6eb0696acb24005b \ - --hash=sha256:85d2b77e7c9382f004b41d9c72c85537fac834fb141b0296942d52bf03fe4a3d \ - --hash=sha256:87c8ceb0cf8a5a51b8008b643844b7f4a8264a2c13fcbcd8a8316161725383fe \ - --hash=sha256:89ee2e967bd7ff85d84a2de09df10e021c9b38c7d91dead95b406ed6350c6997 \ - --hash=sha256:8bef097455dea90ffe855286926ae02d8faa335ed8e4067326257cb571fc1445 \ - --hash=sha256:8d11ebbd679e927593978aa44c10fc2092bc454b7d13fdc958d3e9d508aba7d0 \ - --hash=sha256:91e6c7db42638dc45cf2e13c73be16bf83179f7859b07cfc139518941320be96 \ - --hash=sha256:97e7ac860d64e2dcba5c5944cfc8fa9ea185cd84061c623536154d5a89237884 \ - --hash=sha256:990066bff27c4fcf3b69382b86f4c99b3652bab2a7e685d968cd4d0cfc6f67c6 \ - --hash=sha256:9fbc5b8f3dfe24784cee8ce0be3da2d8a79e46a276593db6868382d9c50d97b1 \ - --hash=sha256:ac4a39d1abae48184d420aa8e5e63efd1b75c8444dd95daa3e03f6c6310e9619 \ - --hash=sha256:b2c02d2ad98116e914d4f3155ffc905fd0c025d901ead3f6ed07385e19122c94 \ - --hash=sha256:b2d3337dcfaa99698aa2377c81c9ca72fcd89c07e7eb62ece3f23a3fe89b2ce4 \ - --hash=sha256:b489c36d1327868d207002391f662a1d163bdc8daf10ab2e5f6e41b9b96de3b1 \ - --hash=sha256:b641161c302efbb860ae6b081f406839a8b7d5573f20a455539823802c655f63 \ - --hash=sha256:b8ba29306c5de7717b5761b9ea74f9c72b9e2b834e24aa984da99cbfc70157fd \ - --hash=sha256:b9934adbd0f6e476f0ecff3c94626529f344f57b38c9a541f87098710b18af0a \ - --hash=sha256:ce85c43ae54845272f6f9cd8320d034d7a946e9773c693b27d620edec825e376 \ - --hash=sha256:cf868e08690cb89360eebc73ba4be7fb461cfbc6168dd88e2fbbe6f31812cd57 \ - --hash=sha256:d2905ce1df400360463c772b55d8e2518d0e488a87cdea13dd2c71dcb2a1fa16 \ - --hash=sha256:d57e20ba591727da0c230ab2c3f200ac9d6d333860d85348816e1dca4cc4792e \ - --hash=sha256:d6a8c9d4f8692917a3dc7eb25a6fb337bff86909febe2f793ec1928cd97bedfc \ - --hash=sha256:d923ff276f1c1f9680d32832f8d6c040fe9306cbfb5d161b0911e9634be9ef0a \ - --hash=sha256:daa7197b43c707462f06d2c693ffdbb5991cbb8b80b5b984007de431493a319c \ - --hash=sha256:dbd4c177afb8a8d9ba348d925b0b67246147af806f0b104af4d24f144d461cd5 \ - --hash=sha256:dc4d815b794fd8868c4d67602692c21bf5293a75e4b607bb92a11e821e2b859a \ - --hash=sha256:e9d21aaa84557d64209af04ff48e0ad5e28c5cca67ce43444e939579d085da72 \ - --hash=sha256:ea6b8aa9e08eea388c5f7a276fabb1d4b6b9d6e4ceb12cc477c3d352001768a9 \ - --hash=sha256:eabe7090db68c981fca689299c2d116400b553f4b713266b130cfc9e2aa9c5a9 \ - --hash=sha256:f2f6d303f3dee132b322a14cd8765287b8f86cdc10d2cb6a6fae234ea488888e \ - --hash=sha256:f33f3258aae89da191c6ebaa3bc517c6c4cbc9b9f689e5d8452f7aedbb913fa8 \ - --hash=sha256:f7bfb769f7efa0eefcd039dd19d843a4fbfbac52f1878b1da2ed5793ec9b1a65 \ - --hash=sha256:f89e21afe925fcfa655965ca8ea10f24773a1791400989ff32f467badfe4a064 \ - --hash=sha256:fa24255ae3c0ab67e613556375a4341af04a084bd58764731972bcbc8baeba36 +greenlet==3.1.1 \ + --hash=sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e \ + --hash=sha256:03a088b9de532cbfe2ba2034b2b85e82df37874681e8c470d6fb2f8c04d7e4b7 \ + --hash=sha256:04b013dc07c96f83134b1e99888e7a79979f1a247e2a9f59697fa14b5862ed01 \ + --hash=sha256:05175c27cb459dcfc05d026c4232f9de8913ed006d42713cb8a5137bd49375f1 \ + --hash=sha256:09fc016b73c94e98e29af67ab7b9a879c307c6731a2c9da0db5a7d9b7edd1159 \ + --hash=sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563 \ + --hash=sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83 \ + --hash=sha256:1443279c19fca463fc33e65ef2a935a5b09bb90f978beab37729e1c3c6c25fe9 \ + --hash=sha256:1776fd7f989fc6b8d8c8cb8da1f6b82c5814957264d1f6cf818d475ec2bf6395 \ + --hash=sha256:1d3755bcb2e02de341c55b4fca7a745a24a9e7212ac953f6b3a48d117d7257aa \ + --hash=sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942 \ + --hash=sha256:275f72decf9932639c1c6dd1013a1bc266438eb32710016a1c742df5da6e60a1 \ + --hash=sha256:2846930c65b47d70b9d178e89c7e1a69c95c1f68ea5aa0a58646b7a96df12441 \ + --hash=sha256:3319aa75e0e0639bc15ff54ca327e8dc7a6fe404003496e3c6925cd3142e0e22 \ + --hash=sha256:346bed03fe47414091be4ad44786d1bd8bef0c3fcad6ed3dee074a032ab408a9 \ + --hash=sha256:36b89d13c49216cadb828db8dfa6ce86bbbc476a82d3a6c397f0efae0525bdd0 \ + --hash=sha256:37b9de5a96111fc15418819ab4c4432e4f3c2ede61e660b1e33971eba26ef9ba \ + --hash=sha256:396979749bd95f018296af156201d6211240e7a23090f50a8d5d18c370084dc3 \ + --hash=sha256:3b2813dc3de8c1ee3f924e4d4227999285fd335d1bcc0d2be6dc3f1f6a318ec1 \ + --hash=sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6 \ + --hash=sha256:47da355d8687fd65240c364c90a31569a133b7b60de111c255ef5b606f2ae291 \ + --hash=sha256:48ca08c771c268a768087b408658e216133aecd835c0ded47ce955381105ba39 \ + --hash=sha256:4afe7ea89de619adc868e087b4d2359282058479d7cfb94970adf4b55284574d \ + --hash=sha256:4ce3ac6cdb6adf7946475d7ef31777c26d94bccc377e070a7986bd2d5c515467 \ + --hash=sha256:4ead44c85f8ab905852d3de8d86f6f8baf77109f9da589cb4fa142bd3b57b475 \ + --hash=sha256:54558ea205654b50c438029505def3834e80f0869a70fb15b871c29b4575ddef \ + --hash=sha256:5e06afd14cbaf9e00899fae69b24a32f2196c19de08fcb9f4779dd4f004e5e7c \ + --hash=sha256:62ee94988d6b4722ce0028644418d93a52429e977d742ca2ccbe1c4f4a792511 \ + --hash=sha256:63e4844797b975b9af3a3fb8f7866ff08775f5426925e1e0bbcfe7932059a12c \ + --hash=sha256:6510bf84a6b643dabba74d3049ead221257603a253d0a9873f55f6a59a65f822 \ + --hash=sha256:667a9706c970cb552ede35aee17339a18e8f2a87a51fba2ed39ceeeb1004798a \ + --hash=sha256:6ef9ea3f137e5711f0dbe5f9263e8c009b7069d8a1acea822bd5e9dae0ae49c8 \ + --hash=sha256:7017b2be767b9d43cc31416aba48aab0d2309ee31b4dbf10a1d38fb7972bdf9d \ + --hash=sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01 \ + --hash=sha256:73aaad12ac0ff500f62cebed98d8789198ea0e6f233421059fa68a5aa7220145 \ + --hash=sha256:77c386de38a60d1dfb8e55b8c1101d68c79dfdd25c7095d51fec2dd800892b80 \ + --hash=sha256:7876452af029456b3f3549b696bb36a06db7c90747740c5302f74a9e9fa14b13 \ + --hash=sha256:7939aa3ca7d2a1593596e7ac6d59391ff30281ef280d8632fa03d81f7c5f955e \ + --hash=sha256:8320f64b777d00dd7ccdade271eaf0cad6636343293a25074cc5566160e4de7b \ + --hash=sha256:85f3ff71e2e60bd4b4932a043fbbe0f499e263c628390b285cb599154a3b03b1 \ + --hash=sha256:8b8b36671f10ba80e159378df9c4f15c14098c4fd73a36b9ad715f057272fbef \ + --hash=sha256:93147c513fac16385d1036b7e5b102c7fbbdb163d556b791f0f11eada7ba65dc \ + --hash=sha256:935e943ec47c4afab8965954bf49bfa639c05d4ccf9ef6e924188f762145c0ff \ + --hash=sha256:94b6150a85e1b33b40b1464a3f9988dcc5251d6ed06842abff82e42632fac120 \ + --hash=sha256:94ebba31df2aa506d7b14866fed00ac141a867e63143fe5bca82a8e503b36437 \ + --hash=sha256:95ffcf719966dd7c453f908e208e14cde192e09fde6c7186c8f1896ef778d8cd \ + --hash=sha256:98884ecf2ffb7d7fe6bd517e8eb99d31ff7855a840fa6d0d63cd07c037f6a981 \ + --hash=sha256:99cfaa2110534e2cf3ba31a7abcac9d328d1d9f1b95beede58294a60348fba36 \ + --hash=sha256:9e8f8c9cb53cdac7ba9793c276acd90168f416b9ce36799b9b885790f8ad6c0a \ + --hash=sha256:a0dfc6c143b519113354e780a50381508139b07d2177cb6ad6a08278ec655798 \ + --hash=sha256:b2795058c23988728eec1f36a4e5e4ebad22f8320c85f3587b539b9ac84128d7 \ + --hash=sha256:b42703b1cf69f2aa1df7d1030b9d77d3e584a70755674d60e710f0af570f3761 \ + --hash=sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0 \ + --hash=sha256:b8a678974d1f3aa55f6cc34dc480169d58f2e6d8958895d68845fa4ab566509e \ + --hash=sha256:b8da394b34370874b4572676f36acabac172602abf054cbc4ac910219f3340af \ + --hash=sha256:c3a701fe5a9695b238503ce5bbe8218e03c3bcccf7e204e455e7462d770268aa \ + --hash=sha256:c4aab7f6381f38a4b42f269057aee279ab0fc7bf2e929e3d4abfae97b682a12c \ + --hash=sha256:ca9d0ff5ad43e785350894d97e13633a66e2b50000e8a183a50a88d834752d42 \ + --hash=sha256:d0028e725ee18175c6e422797c407874da24381ce0690d6b9396c204c7f7276e \ + --hash=sha256:d21e10da6ec19b457b82636209cbe2331ff4306b54d06fa04b7c138ba18c8a81 \ + --hash=sha256:d5e975ca70269d66d17dd995dafc06f1b06e8cb1ec1e9ed54c1d1e4a7c4cf26e \ + --hash=sha256:da7a9bff22ce038e19bf62c4dd1ec8391062878710ded0a845bcf47cc0200617 \ + --hash=sha256:db32b5348615a04b82240cc67983cb315309e88d444a288934ee6ceaebcad6cc \ + --hash=sha256:dcc62f31eae24de7f8dce72134c8651c58000d3b1868e01392baea7c32c247de \ + --hash=sha256:dfc59d69fc48664bc693842bd57acfdd490acafda1ab52c7836e3fc75c90a111 \ + --hash=sha256:e347b3bfcf985a05e8c0b7d462ba6f15b1ee1c909e2dcad795e49e91b152c383 \ + --hash=sha256:e4d333e558953648ca09d64f13e6d8f0523fa705f51cae3f03b5983489958c70 \ + --hash=sha256:ed10eac5830befbdd0c32f83e8aa6288361597550ba669b04c48f0f9a2c843c6 \ + --hash=sha256:efc0f674aa41b92da8c49e0346318c6075d734994c3c4e4430b1c3f853e498e4 \ + --hash=sha256:f1695e76146579f8c06c1509c7ce4dfe0706f49c6831a817ac04eebb2fd02011 \ + --hash=sha256:f1d4aeb8891338e60d1ab6127af1fe45def5259def8094b9c7e34690c8858803 \ + --hash=sha256:f406b22b7c9a9b4f8aa9d2ab13d6ae0ac3e85c9a809bd590ad53fed2bf70dc79 \ + --hash=sha256:f6ff3b14f2df4c41660a7dec01045a045653998784bf8cfcb5a525bdffffbc8f # via gevent idna==3.7 \ --hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \ @@ -451,9 +507,9 @@ itsdangerous==2.1.2 \ --hash=sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44 \ --hash=sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a # via flask -jinja2==3.1.4 \ - --hash=sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369 \ - --hash=sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d +jinja2==3.1.5 \ + --hash=sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb \ + --hash=sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb # via # -r requirements.in # flask @@ -801,9 +857,9 @@ urllib3==1.26.19 \ # -r requirements.in # botocore # requests -werkzeug==3.0.3 \ - --hash=sha256:097e5bfda9f0aba8da6b8545146def481d06aa7d3266e7448e2cccf67dd8bd18 \ - --hash=sha256:fc9645dc43e03e4d630d23143a04a7f947a9a3b5727cd535fdfe155a17cc48c8 +werkzeug==3.0.6 \ + --hash=sha256:1bc0c2310d2fbb07b1dd1105eba2f7af72f322e1e455f2f93c993bee8c8a5f17 \ + --hash=sha256:a8dd59d4de28ca70471a34cba79bed5f7ef2e036a76b3ab0835474246eb41f8d # via # -r requirements.in # flask diff --git a/ops/ansible/roles/bfd-pipeline/templates/bfd-pipeline-service.sh.j2 b/ops/ansible/roles/bfd-pipeline/templates/bfd-pipeline-service.sh.j2 index 7d4c1476ee..1c36fde164 100644 --- a/ops/ansible/roles/bfd-pipeline/templates/bfd-pipeline-service.sh.j2 +++ b/ops/ansible/roles/bfd-pipeline/templates/bfd-pipeline-service.sh.j2 @@ -5,8 +5,8 @@ # Force UTC time export TZ=UTC -export BFD_CCW_JOB_ENABLED={{ enabled if pipeline_instance_type == 'ccw' else 'false' }} {# derived from terraform control plane #}{{ '\n' }} -export BFD_RDA_JOB_ENABLED={{ enabled if pipeline_instance_type == 'rda' else 'false' }} {# derived from terraform control plane #}{{ '\n' }} +export BFD_CCW_JOB_ENABLED={{ job_enabled if pipeline_instance_type == 'ccw' else 'false' }} {# derived from terraform control plane #}{{ '\n' }} +export BFD_RDA_JOB_ENABLED={{ job_enabled if pipeline_instance_type == 'rda' else 'false' }} {# derived from terraform control plane #}{{ '\n' }} export BFD_DB_URL='{{ db_url }}' diff --git a/ops/terraform/env/mgmt/github-actions-iam.tf b/ops/terraform/env/mgmt/github-actions-iam.tf index 02aa145ebb..e34af0ac03 100644 --- a/ops/terraform/env/mgmt/github-actions-iam.tf +++ b/ops/terraform/env/mgmt/github-actions-iam.tf @@ -82,6 +82,7 @@ resource "aws_iam_policy" "github_actions_ecr" { "arn:aws:ecr:us-east-1:${local.account_id}:repository/bfd-server", "arn:aws:ecr:us-east-1:${local.account_id}:repository/bfd-pipeline-app", "arn:aws:ecr:us-east-1:${local.account_id}:repository/bfd-mgmt-eft-sftp-outbound-transfer-lambda", + "arn:aws:ecr:us-east-1:${local.account_id}:repository/bfd-mgmt-pipeline-ccw-manifests-verifier-lambda", ] Sid = "AllowPushPull" }, diff --git a/ops/terraform/services/base/values/ephemeral.yaml b/ops/terraform/services/base/values/ephemeral.yaml index 7cad04b131..a7a2927fdd 100644 --- a/ops/terraform/services/base/values/ephemeral.yaml +++ b/ops/terraform/services/base/values/ephemeral.yaml @@ -24,6 +24,8 @@ /bfd/${env}/pipeline/nonsensitive/ccw/instance_type: c6a.4xlarge /bfd/${env}/pipeline/nonsensitive/ccw/rif_thread_multiple_claims: "25" /bfd/${env}/pipeline/nonsensitive/ccw/slis_repeater_lambda_invoke_rate: 15 minutes +/bfd/${env}/pipeline/nonsensitive/ccw/slo/weekend_data_availability/verifier/enabled: false +/bfd/${env}/pipeline/nonsensitive/ccw/slo/weekend_data_availability/verifier/alert_topic: UNDEFINED /bfd/${env}/pipeline/nonsensitive/rda/grpc/inprocess_server/mode: UNDEFINED /bfd/${env}/pipeline/nonsensitive/rda/grpc/inprocess_server/s3/region: us-east-1 /bfd/${env}/pipeline/nonsensitive/rda/grpc/inprocess_server/s3/bucket: UNDEFINED diff --git a/ops/terraform/services/base/values/prod-sbx.yaml b/ops/terraform/services/base/values/prod-sbx.yaml index e5676c60a3..825d431f77 100644 --- a/ops/terraform/services/base/values/prod-sbx.yaml +++ b/ops/terraform/services/base/values/prod-sbx.yaml @@ -93,6 +93,8 @@ /bfd/${env}/pipeline/nonsensitive/ccw/new_relic/app_name: BFD Pipeline ccw (${env}) /bfd/${env}/pipeline/nonsensitive/ccw/rif_thread_multiple_claims: "25" /bfd/${env}/pipeline/nonsensitive/ccw/slis_repeater_lambda_invoke_rate: 1 minutes +/bfd/${env}/pipeline/nonsensitive/ccw/slo/weekend_data_availability/verifier/enabled: true +/bfd/${env}/pipeline/nonsensitive/ccw/slo/weekend_data_availability/verifier/alert_topics: bfd-prod-sbx-cloudwatch-alarms-slack-bfd-warnings /bfd/${env}/pipeline/nonsensitive/rda/grpc/max_idle_seconds: "600" /bfd/${env}/pipeline/nonsensitive/rda/grpc/server_type: InProcess /bfd/${env}/pipeline/nonsensitive/rda/grpc/inprocess_server/mode: S3 diff --git a/ops/terraform/services/base/values/prod.yaml b/ops/terraform/services/base/values/prod.yaml index 12af7fcd4a..a74f4c41a4 100644 --- a/ops/terraform/services/base/values/prod.yaml +++ b/ops/terraform/services/base/values/prod.yaml @@ -140,6 +140,8 @@ /bfd/${env}/pipeline/nonsensitive/ccw/new_relic/app_name: BFD Pipeline ccw (${env}) /bfd/${env}/pipeline/nonsensitive/ccw/rif_thread_multiple_claims: "25" /bfd/${env}/pipeline/nonsensitive/ccw/slis_repeater_lambda_invoke_rate: 1 minutes +/bfd/${env}/pipeline/nonsensitive/ccw/slo/weekend_data_availability/verifier/enabled: true +/bfd/${env}/pipeline/nonsensitive/ccw/slo/weekend_data_availability/verifier/alert_topics: bfd-prod-cloudwatch-alarms,bfd-prod-cloudwatch-alarms-slack-bfd-alerts /bfd/${env}/pipeline/nonsensitive/rda/grpc/max_idle_seconds: "600" /bfd/${env}/pipeline/nonsensitive/rda/grpc/server_type: Remote /bfd/${env}/pipeline/nonsensitive/rda/grpc/inprocess_server/mode: UNDEFINED diff --git a/ops/terraform/services/base/values/test.yaml b/ops/terraform/services/base/values/test.yaml index a6eff04eb0..e3d73ef88b 100644 --- a/ops/terraform/services/base/values/test.yaml +++ b/ops/terraform/services/base/values/test.yaml @@ -142,6 +142,8 @@ /bfd/${env}/pipeline/nonsensitive/ccw/new_relic/app_name: BFD Pipeline ccw (${env}) /bfd/${env}/pipeline/nonsensitive/ccw/rif_thread_multiple_claims: "25" /bfd/${env}/pipeline/nonsensitive/ccw/slis_repeater_lambda_invoke_rate: 1 minutes +/bfd/${env}/pipeline/nonsensitive/ccw/slo/weekend_data_availability/verifier/enabled: true +/bfd/${env}/pipeline/nonsensitive/ccw/slo/weekend_data_availability/verifier/alert_topics: bfd-test-cloudwatch-alarms-slack-bfd-test /bfd/${env}/pipeline/nonsensitive/rda/grpc/max_idle_seconds: "600" /bfd/${env}/pipeline/nonsensitive/rda/grpc/server_type: Remote /bfd/${env}/pipeline/nonsensitive/rda/grpc/inprocess_server/mode: UNDEFINED diff --git a/ops/terraform/services/pipeline/README.md b/ops/terraform/services/pipeline/README.md index 4047284afa..f9d61b29fa 100644 --- a/ops/terraform/services/pipeline/README.md +++ b/ops/terraform/services/pipeline/README.md @@ -89,6 +89,7 @@ | [aws_sns_topic.bfd_notices_slack_alarm](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/sns_topic) | data source | | [aws_sns_topic.bfd_test_slack_alarm](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/sns_topic) | data source | | [aws_sns_topic.ok](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/sns_topic) | data source | +| [aws_ssm_parameter.verifier_enabled](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameter) | data source | | [aws_ssm_parameters_by_path.nonsensitive_ccw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameters_by_path) | data source | | [aws_ssm_parameters_by_path.nonsensitive_common](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameters_by_path) | data source | | [aws_ssm_parameters_by_path.nonsensitive_rda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameters_by_path) | data source | diff --git a/ops/terraform/services/pipeline/data-sources.tf b/ops/terraform/services/pipeline/data-sources.tf index 7756425d32..bff771e89e 100644 --- a/ops/terraform/services/pipeline/data-sources.tf +++ b/ops/terraform/services/pipeline/data-sources.tf @@ -114,6 +114,10 @@ data "aws_ssm_parameters_by_path" "nonsensitive_rda" { path = "/bfd/${local.env}/${local.service}/nonsensitive/rda" } +data "aws_ssm_parameter" "verifier_enabled" { + name = "/bfd/${local.env}/${local.service}/nonsensitive/ccw/slo/weekend_data_availability/verifier/enabled" +} + # TODO: this needs to be defined in common data "aws_sns_topic" "alarm" { count = local.is_prod ? 1 : 0 diff --git a/ops/terraform/services/pipeline/main.tf b/ops/terraform/services/pipeline/main.tf index 569b9e46c9..6ebe6f5f61 100644 --- a/ops/terraform/services/pipeline/main.tf +++ b/ops/terraform/services/pipeline/main.tf @@ -152,6 +152,8 @@ locals { for k, v in local.pipeline_variant_configs : k => local.pipeline_variant_configs[k] if local.pipeline_variant_configs[k].enabled && k == "ccw" } + + ccw_manifests_verifier_enabled = tobool(nonsensitive(data.aws_ssm_parameter.verifier_enabled.value)) } # TODO: Determine if resource could be consolidated with RDA variant if RDA becomes on-demand @@ -447,3 +449,16 @@ module "bfd_pipeline_scheduler" { name = aws_autoscaling_group.this["ccw"].name } } + +module "bfd_pipeline_ccw_manifests_verifier" { + count = local.pipeline_variant_configs.ccw.enabled && local.ccw_manifests_verifier_enabled ? 1 : 0 + + source = "./modules/bfd_pipeline_ccw_manifests_verifier" + + db_cluster_identifier = local.db_cluster_identifier + etl_bucket_id = aws_s3_bucket.this.id + vpc_name = local.vpc_name + bfd_version = local.latest_bfd_release + kms_config_key_alias = local.nonsensitive_common_config["kms_config_key_alias"] + kms_key_alias = local.kms_key_id +} diff --git a/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/.terraform-docs.yml b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/.terraform-docs.yml new file mode 100644 index 0000000000..eb6117e251 --- /dev/null +++ b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/.terraform-docs.yml @@ -0,0 +1,60 @@ +formatter: markdown table +sections: + show: + - requirements + - inputs + - resources + - outputs + - data-sources + +# this `content` string is implemented as a golang template https://pkg.go.dev/text/template +# updates here correspond to `{{ .Content }}` in `output.template` setting below +content: |- + {{ .Requirements }} + + + + {{ .Inputs }} + + + + {{ .Resources }} + + + + {{ .Outputs }} + +output: + file: README.md + mode: inject + template: |- + + + {{ .Content }} + + +sort: + enabled: true + by: required + +settings: + indent: 2 + default: true + required: true + type: true diff --git a/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/README.md b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/README.md new file mode 100644 index 0000000000..4961845a79 --- /dev/null +++ b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/README.md @@ -0,0 +1,89 @@ +# `bfd_pipeline_ccw_manifests_verifier` Module + +This sub-module contains the Terraform IaC and Python Lambda source code for the per-environment `ccw_manifests_verifier` Lambda. This Lambda runs based on an EventBridge `cron` schedule that is configured to run the Lambda every Monday at 9 AM ET. The Lambda will then reconcile the state of CCW dataset manifests in the environment's ETL S3 Bucket prefixed with `Incoming/` and `Synthetic/Incoming/` and if there are any manifests that are not in the database as having been processed or they are not in the database at all the Lambda will send an alert to a configured SNS Topic (for `prod` this SNS Topic will send notifications to Splunk On Call, triggering an Incident). + +This solution implements the `Weekend data load availability` SLO. + + + +## Requirements + +No requirements. + + + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [bfd\_version](#input\_bfd\_version) | BFD Lambda version to deploy | `string` | n/a | yes | +| [db\_cluster\_identifier](#input\_db\_cluster\_identifier) | Cluster ID of the target database | `string` | n/a | yes | +| [etl\_bucket\_id](#input\_etl\_bucket\_id) | Bucket ID of the Pipeline ETL S3 Bucket | `string` | n/a | yes | +| [kms\_config\_key\_alias](#input\_kms\_config\_key\_alias) | Alias/ID of the config CMK | `string` | n/a | yes | +| [kms\_key\_alias](#input\_kms\_key\_alias) | Alias/ID of the main CMK | `string` | n/a | yes | +| [vpc\_name](#input\_vpc\_name) | Name of the current VPC | `string` | n/a | yes | + + + +## Resources + +| Name | Type | +|------|------| +| [aws_iam_policy.kms](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_policy.logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_policy.rds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_policy.scheduler_invoke_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_policy.sns](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_policy.ssm](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_role.scheduler_assume_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_role.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_role_policy_attachment.invoke_lambda_policy_to_scheduler_assume_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_iam_role_policy_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_lambda_function.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource | +| [aws_scheduler_schedule.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/scheduler_schedule) | resource | +| [aws_scheduler_schedule_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/scheduler_schedule_group) | resource | +| [aws_security_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource | +| [aws_security_group_rule.rds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_ecr_image.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ecr_image) | data source | +| [aws_ecr_repository.ecr](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ecr_repository) | data source | +| [aws_iam_policy_document.kms_policy_doc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.lambda_role_assume_policy_doc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.logs_policy_doc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.rds_policy_doc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.scheduler_invoke_lambda_policy_doc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.scheduler_role_assume_policy_doc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.sns_policy_doc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.ssm_policy_doc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_kms_key.cmk](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/kms_key) | data source | +| [aws_kms_key.config_cmk](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/kms_key) | data source | +| [aws_rds_cluster.cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/rds_cluster) | data source | +| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | +| [aws_security_group.rds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/security_group) | data source | +| [aws_sns_topic.alert_topic](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/sns_topic) | data source | +| [aws_ssm_parameter.alert_topic](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameter) | data source | +| [aws_subnets.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnets) | data source | +| [aws_vpc.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/vpc) | data source | + + + +## Outputs + +No outputs. + \ No newline at end of file diff --git a/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/data-sources.tf b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/data-sources.tf new file mode 100644 index 0000000000..d3da5a2455 --- /dev/null +++ b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/data-sources.tf @@ -0,0 +1,63 @@ +data "aws_region" "current" {} + +data "aws_caller_identity" "current" {} + +data "aws_vpc" "main" { + filter { + name = "tag:Name" + values = [var.vpc_name] + } +} + +data "aws_kms_key" "cmk" { + key_id = var.kms_key_alias +} + +data "aws_kms_key" "config_cmk" { + key_id = var.kms_config_key_alias +} + +data "aws_ecr_repository" "ecr" { + name = "bfd-mgmt-${local.service}-${local.lambda_name}-lambda" +} + +data "aws_ecr_image" "this" { + repository_name = data.aws_ecr_repository.ecr.name + image_tag = var.bfd_version +} + +data "aws_subnets" "main" { + filter { + name = "vpc-id" + values = [data.aws_vpc.main.id] + } + filter { + name = "tag:Layer" + values = [local.layer] + } +} + +data "aws_security_group" "rds" { + vpc_id = data.aws_vpc.main.id + filter { + name = "tag:Name" + values = [var.db_cluster_identifier] + } +} + +data "aws_rds_cluster" "cluster" { + cluster_identifier = var.db_cluster_identifier +} + +data "aws_ssm_parameter" "alert_topics" { + name = "/bfd/${local.env}/${local.service}/nonsensitive/ccw/slo/weekend_data_availability/verifier/alert_topics" +} + +data "aws_sns_topic" "alert_topic" { + count = length(local.alert_topics) + name = local.alert_topics[count.index] +} + +data "aws_s3_bucket" "etl_bucket" { + bucket = var.etl_bucket_id +} diff --git a/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/iam.tf b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/iam.tf new file mode 100644 index 0000000000..97d2b11a80 --- /dev/null +++ b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/iam.tf @@ -0,0 +1,188 @@ +data "aws_iam_policy_document" "logs_policy_doc" { + statement { + sid = "AllowLogGroupCreate" + actions = ["logs:CreateLogGroup"] + resources = ["arn:aws:logs:${local.region}:${local.account_id}:*"] + } + + statement { + sid = "AllowLogStreamControl" + actions = ["logs:CreateLogStream", "logs:PutLogEvents"] + resources = [ + "arn:aws:logs:${local.region}:${local.account_id}:log-group:/aws/lambda/${local.lambda_full_name}:*" + ] + } +} + +resource "aws_iam_policy" "logs" { + name = "${local.lambda_full_name}-logs" + description = join("", [ + "Permissions for the ${local.lambda_full_name} Lambda to write to its corresponding ", + "CloudWatch Log Group and Log Stream", + ]) + + policy = data.aws_iam_policy_document.logs_policy_doc.json +} + +data "aws_iam_policy_document" "ssm_policy_doc" { + statement { + actions = ["ssm:GetParameter"] + resources = [ + "arn:aws:ssm:${local.region}:${local.account_id}:parameter/bfd/${local.env}/pipeline/sensitive/db/username", + "arn:aws:ssm:${local.region}:${local.account_id}:parameter/bfd/${local.env}/pipeline/sensitive/db/password" + ] + } +} + +resource "aws_iam_policy" "ssm" { + name = "${local.lambda_full_name}-ssm" + description = "Permissions for the ${local.lambda_full_name} Lambda to get relevant SSM parameters" + policy = data.aws_iam_policy_document.ssm_policy_doc.json +} + +data "aws_iam_policy_document" "rds_policy_doc" { + statement { + sid = "AllowDescribeCluster" + actions = ["rds:DescribeDBClusters"] + resources = [data.aws_rds_cluster.cluster.arn] + } +} + +resource "aws_iam_policy" "rds" { + name = "${local.lambda_full_name}-rds" + description = "Permissions for the ${local.lambda_full_name} Lambda to describe the ${data.aws_rds_cluster.cluster.cluster_identifier} cluster" + policy = data.aws_iam_policy_document.rds_policy_doc.json +} + +data "aws_iam_policy_document" "kms_policy_doc" { + statement { + sid = "AllowDecryptionOfConfigKeys" + actions = ["kms:Decrypt"] + resources = local.kms_config_key_arns + } + + statement { + sid = "AllowEncryptionAndDecryptionOfMasterKeys" + actions = [ + "kms:Encrypt", + "kms:Decrypt", + "kms:ReEncrypt*", + "kms:GenerateDataKey*", + "kms:DescribeKey", + ] + resources = [local.kms_key_id] + } +} + +resource "aws_iam_policy" "kms" { + name = "${local.lambda_full_name}-kms" + description = join("", [ + "Permissions for the ${local.lambda_full_name} Lambda to decrypt config KMS keys and encrypt ", + "and decrypt master KMS keys for ${local.env}" + ]) + + policy = data.aws_iam_policy_document.kms_policy_doc.json +} + +data "aws_iam_policy_document" "s3_policy_doc" { + statement { + actions = ["s3:ListBucket"] + resources = [data.aws_s3_bucket.etl_bucket.arn] + } +} + +resource "aws_iam_policy" "s3" { + name = "${local.lambda_full_name}-s3" + description = "Permissions for the ${local.lambda_full_name} Lambda to list objects in the ${var.etl_bucket_id} Bucket" + policy = data.aws_iam_policy_document.s3_policy_doc.json +} + +data "aws_iam_policy_document" "sns_policy_doc" { + statement { + sid = "AllowPublish" + actions = ["SNS:Publish"] + resources = data.aws_sns_topic.alert_topic[*].arn + } +} + +resource "aws_iam_policy" "sns" { + name = "${local.lambda_full_name}-sns" + description = "Permissions for the ${local.lambda_full_name} Lambda to publish to the configured SNS Topic(s)" + policy = data.aws_iam_policy_document.sns_policy_doc.json +} + +data "aws_iam_policy_document" "lambda_role_assume_policy_doc" { + statement { + actions = ["sts:AssumeRole"] + principals { + type = "Service" + identifiers = ["lambda.amazonaws.com"] + } + } +} + +resource "aws_iam_role" "this" { + name = local.lambda_full_name + path = "/" + description = "Role for ${local.lambda_full_name} Lambda" + assume_role_policy = data.aws_iam_policy_document.lambda_role_assume_policy_doc.json + force_detach_policies = true +} + +resource "aws_iam_role_policy_attachment" "this" { + for_each = { + logs = aws_iam_policy.logs.arn, + ssm = aws_iam_policy.ssm.arn, + rds = aws_iam_policy.rds.arn + kms = aws_iam_policy.kms.arn, + s3 = aws_iam_policy.s3.arn, + sns = aws_iam_policy.sns.arn, + vpc = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole" + } + + role = aws_iam_role.this.name + policy_arn = each.value +} + +data "aws_iam_policy_document" "scheduler_invoke_lambda_policy_doc" { + statement { + actions = ["lambda:InvokeFunction"] + resources = [aws_lambda_function.this.arn] + } +} + +resource "aws_iam_policy" "scheduler_invoke_lambda" { + name = "${local.lambda_full_name}-scheduler-assumee-allow-lambda-invoke" + description = join("", [ + "Permissions for EventBridge Scheduler assumed role to invoke the ", + "${local.lambda_full_name} Lambda" + ]) + + policy = data.aws_iam_policy_document.scheduler_invoke_lambda_policy_doc.json +} + +data "aws_iam_policy_document" "scheduler_role_assume_policy_doc" { + statement { + actions = ["sts:AssumeRole"] + principals { + type = "Service" + identifiers = ["scheduler.amazonaws.com"] + } + } +} + +resource "aws_iam_role" "scheduler_assume_role" { + name = "${local.lambda_full_name}-scheduler-assumee" + path = "/" + description = join("", [ + "Role for EventBridge Scheduler allowing permissions to invoke the ", + "${local.lambda_full_name} Lambda" + ]) + assume_role_policy = data.aws_iam_policy_document.scheduler_role_assume_policy_doc.json + force_detach_policies = true +} + +resource "aws_iam_role_policy_attachment" "invoke_lambda_policy_to_scheduler_assume_role" { + role = aws_iam_role.scheduler_assume_role.name + policy_arn = aws_iam_policy.scheduler_invoke_lambda.arn +} diff --git a/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/lambda_src/.python-version b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/lambda_src/.python-version new file mode 100644 index 0000000000..24ee5b1be9 --- /dev/null +++ b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/lambda_src/.python-version @@ -0,0 +1 @@ +3.13 diff --git a/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/lambda_src/Dockerfile b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/lambda_src/Dockerfile new file mode 100644 index 0000000000..afda8163a5 --- /dev/null +++ b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/lambda_src/Dockerfile @@ -0,0 +1,28 @@ +FROM ghcr.io/astral-sh/uv:0.5.22 AS uv +# First, bundle the dependencies into the task root. +FROM public.ecr.aws/lambda/python:3.13-arm64 AS builder +# Enable bytecode compilation, to improve cold-start performance. +ENV UV_COMPILE_BYTECODE=1 +# Disable installer metadata, to create a deterministic layer. +ENV UV_NO_INSTALLER_METADATA=1 +# Enable copy mode to support bind mount caching. +ENV UV_LINK_MODE=copy +# Bundle the dependencies into the Lambda task root via `uv pip install --target`. +# +# Omit any local packages (`--no-emit-workspace`) and development dependencies (`--no-dev`). +# This ensures that the Docker layer cache is only invalidated when the `pyproject.toml` or `uv.lock` +# files change, but remains robust to changes in the application code. +COPY pyproject.toml . +COPY uv.lock . +RUN --mount=from=uv,source=/uv,target=/bin/uv \ + --mount=type=cache,target=/root/.cache/uv \ + uv export --frozen --no-emit-workspace --no-dev --no-editable -o requirements.txt && \ + uv pip install -r requirements.txt --target "${LAMBDA_TASK_ROOT}" + +FROM public.ecr.aws/lambda/python:3.13-arm64 +# Copy the runtime dependencies from the builder stage. +COPY --from=builder ${LAMBDA_TASK_ROOT} ${LAMBDA_TASK_ROOT} +# Copy the application code. +COPY . ${LAMBDA_TASK_ROOT}/app +CMD [ "app.ccw_manifests_verifier.handler" ] + diff --git a/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/lambda_src/Dockerfile.dockerignore b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/lambda_src/Dockerfile.dockerignore new file mode 100644 index 0000000000..6c2bd56902 --- /dev/null +++ b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/lambda_src/Dockerfile.dockerignore @@ -0,0 +1,4 @@ +* +!pyproject.toml +!uv.lock +!ccw_manifests_verifier.py diff --git a/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/lambda_src/README.md b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/lambda_src/README.md new file mode 100644 index 0000000000..68912196b8 --- /dev/null +++ b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/lambda_src/README.md @@ -0,0 +1,25 @@ +# `ccw-manifests-verifier` Lambda Source + +This subdirectory contains the Python source code for the `ccw-manifests-verifier` Lambda. + +## Environment Setup + +It is assumed you are using `pyright`/`pylance` for type-checking, `uv` for virtual environment and dependency management, and `ruff` for linting, formatting, and import sorting. + +1. Install `uv`: + + ```bash + brew install uv + ``` + +2. Setup Python 3.13 virtual environment: + + ```bash + uv sync + ``` + +3. Your virtual environment is now setup! By default, it is available under `.venv`; using VS Code, this Virtual Environment can be chosen using the `Python: Select Interpreter` command + +## Updating/managing dependencies + +See [`Managing dependencies`](https://docs.astral.sh/uv/concepts/projects/dependencies/) and [`Locking and syncing`](https://docs.astral.sh/uv/concepts/projects/sync/) in the `uv` docs for more information. diff --git a/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/lambda_src/ccw_manifests_verifier.py b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/lambda_src/ccw_manifests_verifier.py new file mode 100644 index 0000000000..69a8935292 --- /dev/null +++ b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/lambda_src/ccw_manifests_verifier.py @@ -0,0 +1,242 @@ +"""Source code for ccw-manifests-verifier Lambda. + +This Lambda verifies that all recently modified CCW manifests in S3 are marked as "COMPLETED" in the +database. If any are not, this Lambda will send an alert to the provided alert SNS Topic (expected +to be the Splunk On Call Topic in prod). +""" + +import itertools +import os +from datetime import UTC, datetime, timedelta +from typing import Annotated, Any + +import boto3 +import psycopg +from aws_lambda_powertools import Logger +from aws_lambda_powertools.utilities import parameters +from aws_lambda_powertools.utilities.typing import LambdaContext +from botocore.config import Config +from psycopg.rows import dict_row +from pydantic import BaseModel, Field, TypeAdapter + +REGION = os.environ.get("AWS_CURRENT_REGION", "us-east-1") +BFD_ENVIRONMENT = os.environ.get("BFD_ENVIRONMENT", "") +DB_CLUSTER_NAME = os.environ.get("DB_CLUSTER_NAME", "") +ETL_BUCKET_ID = os.environ.get("ETL_BUCKET_ID", "") +ALERT_TOPIC_ARNS = [arn.strip() for arn in os.environ.get("ALERT_TOPIC_ARNS", "").split(",")] +BOTO_CONFIG = Config( + region_name=REGION, + # Instructs boto3 to retry upto 10 times using an exponential backoff + retries={ + "total_max_attempts": 10, + "mode": "adaptive", + }, +) + +logger = Logger() + + +class ManifestFilesResultModel(BaseModel): + """Pydantic model modeling columns returned from the s3_manifest_files database table.""" + + s3_key: str + status: str + + +class SplunkOnCallNotificationModel(BaseModel): + """Pydantic model modeling the message that Splunk On Call expects from AWS alerts. + + The Splunk On Call integration we use to send alerts from AWS expects that alerts originate from + CloudWatch Alarms. This is true for every alert except this one, so rather than installing + another integration we simply create a fake CloudWatch Alarm message. This is why the serialized + fields are named strangely and all but the "alert_message" field default to unusual values. + Additionally, this Lambda is mostly relevant for prod for which alerts will be sent to the + corresponding Splunk On Call Topic + """ + + alert_message: Annotated[str, Field(serialization_alias="NewStateReason")] + alert_description: Annotated[ + str, + Field( + serialization_alias="AlarmDescription", + default_factory=lambda: ( + "Pseudo-Alarm alert generated by the ccw-manifests-verifier that alerts when the " + f"{BFD_ENVIRONMENT} CCW Pipeline fails to load all available manifests over the " + 'previous weekend by Monday at 9 AM ET. See the "alarm reason" for details on ' + "the failing manifests" + ), + ), + ] + alert_name: Annotated[ + str, + Field(serialization_alias="AlarmName", default="weekend-data-load-availability-failure"), + ] + state: Annotated[str, Field(serialization_alias="NewStateValue", default="ALARM")] + change_time: Annotated[ + datetime, + Field(serialization_alias="StateChangeTime", default_factory=lambda: datetime.now(UTC)), + ] + + +def create_splunk_sns_notification( + unprocessed_manifests: list[str], +) -> SplunkOnCallNotificationModel: + """Create a SplunkOnCallNotificationModel with an appropriate alert message. + + :param unprocessed_manifests: List of unprocessed manifests to alert upon + :type unprocessed_manifests: list[str] + :return: A model with a message indicating the unprocessed manifests + :rtype: SplunkOnCallNotificationModel + """ + return SplunkOnCallNotificationModel.model_validate({ + "alert_message": ( + f"{BFD_ENVIRONMENT} CCW Pipeline failed to load {len(unprocessed_manifests)}" + f" manifest(s) over the weekend: {', '.join(unprocessed_manifests)}" + ) + }) + + +@logger.inject_lambda_context(clear_state=True, log_event=True) +def handler(event: dict[Any, Any], context: LambdaContext) -> None: # noqa: ARG001 + """Lambda event handler function called when an EventBridge Scheduler Event is received. + + Args: + event (dict[Any, Any]): EventBridge Scheduler event details. Unused + context (LambdaContext): Lambda execution context. Unused + + Raises: + RuntimeError: If any AWS API operations fail + """ + try: + if not all([REGION, BFD_ENVIRONMENT, DB_CLUSTER_NAME, ETL_BUCKET_ID, ALERT_TOPIC_ARNS]): + raise RuntimeError("Not all necessary environment variables were defined") + + rds_client = boto3.client("rds", config=BOTO_CONFIG) + described_clusters = rds_client.describe_db_clusters( + DBClusterIdentifier=DB_CLUSTER_NAME + ).get("DBClusters", []) + try: + reader_endpoint = next( + cluster_detail["ReaderEndpoint"] + for cluster_detail in described_clusters + if "ReaderEndpoint" in cluster_detail + ) + except StopIteration as exc: + raise RuntimeError( + "describe-db-clusters returned invalid data for " + f"{DB_CLUSTER_NAME}: {described_clusters!s}" + ) from exc + db_username = parameters.get_parameter( + f"/bfd/{BFD_ENVIRONMENT}/pipeline/sensitive/db/username", decrypt=True + ) + db_password = parameters.get_parameter( + f"/bfd/{BFD_ENVIRONMENT}/pipeline/sensitive/db/password", decrypt=True + ) + + logger.info( + "Connecting to %s as Pipeline user in %s cluster...", + reader_endpoint, + DB_CLUSTER_NAME, + ) + with ( + psycopg.connect( + host=reader_endpoint, + user=db_username, + password=db_password, + port=5432, + dbname="fhirdb", + ) as conn, + conn.cursor(row_factory=dict_row) as curs, + ): + logger.info("Connected to %s", reader_endpoint) + two_weeks_ago = datetime.now(UTC) - timedelta(weeks=2) + + # Retrieve all manifests in the Incoming paths in s3 that were recently modified in the + # past 2 weeks. These manifests will be reconciled against their status in the database + logger.info( + "Discovering manifest(s) last modified after %s from S3 in Incoming...", + two_weeks_ago.isoformat(), + ) + s3_resource = boto3.resource("s3", config=BOTO_CONFIG) + etl_bucket = s3_resource.Bucket(ETL_BUCKET_ID) + all_incoming_objects = itertools.chain( + etl_bucket.objects.filter(Prefix="Incoming/"), + etl_bucket.objects.filter(Prefix="Synthetic/Incoming/"), + ) + recent_s3_manifest_keys = [ + object.key + for object in all_incoming_objects + if "manifest.xml" in object.key + and object.last_modified.astimezone(UTC) > two_weeks_ago + ] + logger.info( + "Discovered %d S3 manifest(s) modified after %s", + len(recent_s3_manifest_keys), + two_weeks_ago.isoformat(), + ) + + # Retrieve all manifests and their state that were discovered in the past 2 weeks from + # the database. This list will be the source of truth against which the manifests in s3 + # will be verified against + logger.info( + "Retrieving manifest(s) discovered since %s from the database", + two_weeks_ago.isoformat(), + ) + raw_results = curs.execute( + """ + SELECT s3_key, status FROM ccw.s3_manifest_files + WHERE discovery_timestamp > %s; + """, + (two_weeks_ago,), + ).fetchall() + db_manifest_files = TypeAdapter(list[ManifestFilesResultModel]).validate_python( + raw_results + ) + logger.info( + "Retrieved %d manifest(s) from the database discovered after %s", + len(db_manifest_files), + two_weeks_ago.isoformat(), + ) + + # Reconcile the retrieved recently modified s3 manifests in Incoming with the manifests + # and their state in the database. If any s3 manifests either are not in the COMPLETED + # state or simply aren't in the database, the Pipeline failed to finish loading over the + # weekend and we should alert + logger.info( + "Verifying all %d S3 manifest(s) have been loaded...", len(recent_s3_manifest_keys) + ) + unprocessed_manifests = [ + s3_manifest + for s3_manifest in recent_s3_manifest_keys + if not any( + s3_manifest == db_manifest.s3_key and db_manifest.status == "COMPLETED" + for db_manifest in db_manifest_files + ) + ] + if len(unprocessed_manifests) == 0: + logger.info("All manifests in S3 have been loaded by the Pipeline. Stopping") + return + + # If we get here, there are unprocessed manifests. We need to send an alert to the alert + # topic(s) + logger.info( + "%d manifest(s) failed to load over the weekend; publishing notification(s) to " + "topic(s) %s; (manifest(s): %s)", + len(unprocessed_manifests), + ", ".join(arn.split(":")[-1] for arn in ALERT_TOPIC_ARNS), + ", ".join(unprocessed_manifests), + ) + sns_client = boto3.client("sns", config=BOTO_CONFIG) + sns_message = create_splunk_sns_notification( + unprocessed_manifests=unprocessed_manifests + ).model_dump_json(by_alias=True) + for topic_arn in ALERT_TOPIC_ARNS: + logger.info("Publishing message to %s...", topic_arn) + sns_client.publish( + TopicArn=topic_arn, + Message=sns_message, + ) + logger.info("Published message to %s successfully", topic_arn) + except Exception: + logger.exception("Unrecoverable exception raised") + raise diff --git a/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/lambda_src/pyproject.toml b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/lambda_src/pyproject.toml new file mode 100644 index 0000000000..ee028184c8 --- /dev/null +++ b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/lambda_src/pyproject.toml @@ -0,0 +1,78 @@ +[project] +# Support Python 3.13+. +requires-python = ">=3.13" +name = "ccw-manifests-verifier" +version = "1.0.0" +dependencies = [ + "aws-lambda-powertools[all]>=3.4.1", + "boto3>=1.36.3", + "psycopg[binary]>=3.2.4", + "pydantic>=2.10.5", +] + +[dependency-groups] +dev = [ + "boto3-stubs[rds,s3,sns]>=1.36.3", + "ruff>=0.9.2", + "uv>=0.5.22", +] + +[tool.ruff] +# Set the maximum line length to 100. +line-length = 100 + +[tool.ruff.lint] +select = [ + "D", # pydocstyle + "E501", + # pycodestyle + "E", + # Pyflakes + "F", + # pyupgrade + "UP", + # flake8-bugbear + "B", + # flake8-simplify + "SIM", + # isort + "I", + "ANN", + "LOG", + "G", + "PT", + "RSE", + "PIE", + "RET", + "SLF", + "ARG", + "PTH", + "PLE", + "PLW", + "PERF", + "FURB", + "RUF", +] + +[tool.ruff.lint.pydocstyle] +convention = "pep257" + +[tool.ruff.format] +quote-style = "double" +indent-style = "space" +docstring-code-format = true + +[tool.pyright] +# ... +typeCheckingMode = "strict" +venvPath = "." +venv = ".venv" +reportMissingTypeStubs = "none" +# Usage of _some_ of Powertools for AWS Lambda necessitates disabling some of Pyright's strict mode +# features, sadly. The Powertools team seems to be aware of this incompatibility, but it seems +# unlikely that any improvements will be made. +reportUnknownMemberType = false +reportUnknownVariableType = false +reportUnknownArgumentType = false +reportUnknownParameterType = false + diff --git a/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/lambda_src/uv.lock b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/lambda_src/uv.lock new file mode 100644 index 0000000000..544635d5dc --- /dev/null +++ b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/lambda_src/uv.lock @@ -0,0 +1,550 @@ +version = 1 +requires-python = ">=3.13" + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, +] + +[[package]] +name = "attrs" +version = "24.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/48/c8/6260f8ccc11f0917360fc0da435c5c9c7504e3db174d5a12a1494887b045/attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff", size = 805984 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/89/aa/ab0f7891a01eeb2d2e338ae8fecbe57fcebea1a24dbb64d45801bfab481d/attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308", size = 63397 }, +] + +[[package]] +name = "aws-encryption-sdk" +version = "4.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "boto3" }, + { name = "cryptography" }, + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/da/51/feccabe29a3ee9b5a9e85bc9a7b0c4967a75a38458643e034d9c3551b6fa/aws-encryption-sdk-4.0.0.tar.gz", hash = "sha256:57df8b5c1b9f18db4373c6e8e65563791063a71be93d0849950ed365272db354", size = 257055 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/b8/5c1fc95f2082eb946eddfd38430ec3b0a9b7f566456fd9cc6da17e2b57c8/aws_encryption_sdk-4.0.0-py2.py3-none-any.whl", hash = "sha256:a94483785dff2cd166ccb8f3a15cdfe5cba7a3717f6604543c816a3a32f7c412", size = 98448 }, +] + +[[package]] +name = "aws-lambda-powertools" +version = "3.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jmespath" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/64/c8/9822b65596e656ffc17240c76ed954eb956a90c6cae1a38b07273f459e3a/aws_lambda_powertools-3.4.1.tar.gz", hash = "sha256:c5cb323ef1a6669e80409cff9e7b5b0a63581b93a65f750984e71bc4de5f22b6", size = 651066 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/15/ef/d38ab06eddedd79d05b670b945c40645ee0e329ebf6ea238833e4462d9a7/aws_lambda_powertools-3.4.1-py3-none-any.whl", hash = "sha256:41f2898d90b0c21e09386cc7d1c0070c360dc877d3b24b2cc118df9534d8f759", size = 766154 }, +] + +[package.optional-dependencies] +all = [ + { name = "aws-encryption-sdk" }, + { name = "aws-xray-sdk" }, + { name = "fastjsonschema" }, + { name = "jsonpath-ng" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, +] + +[[package]] +name = "aws-xray-sdk" +version = "2.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e0/6c/8e7fb2a45f20afc5c19d52807b560793fb48b0feca1de7de116b62a7893e/aws_xray_sdk-2.14.0.tar.gz", hash = "sha256:aab843c331af9ab9ba5cefb3a303832a19db186140894a523edafc024cc0493c", size = 93976 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/69/b417833a8926fa5491e5346d7c233bf7d8a9b12ba1f4ef41ccea2494000c/aws_xray_sdk-2.14.0-py2.py3-none-any.whl", hash = "sha256:cfbe6feea3d26613a2a869d14c9246a844285c97087ad8f296f901633554ad94", size = 101922 }, +] + +[[package]] +name = "boto3" +version = "1.36.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, + { name = "jmespath" }, + { name = "s3transfer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/07/12/b9ad4c3dd6e6044243d08bae076795e41357651683f4fad99d5828c4291c/boto3-1.36.3.tar.gz", hash = "sha256:53a5307f6a3526ee2f8590e3c45efa504a3ea4532c1bfe4926c0c19bf188d141", size = 110987 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/97/4697aa8050e306d6139815996adeb263ddc83024399a188e8b42587665db/boto3-1.36.3-py3-none-any.whl", hash = "sha256:f9843a5d06f501d66ada06f5a5417f671823af2cf319e36ceefa1bafaaaaa953", size = 139165 }, +] + +[[package]] +name = "boto3-stubs" +version = "1.36.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore-stubs" }, + { name = "types-s3transfer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ea/38/635c362ec0060e2974d1e5c0daf80532097debe57fecad035e648be05483/boto3_stubs-1.36.3.tar.gz", hash = "sha256:f4a0ac68202e699486f7fb7283985edd1709300633ba29feb4c79ce488ce59fe", size = 98583 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/58/0a/43bb865ae3d9312b5f4068244aca3c8664a6ba9f28bd617c43e677f8fff8/boto3_stubs-1.36.3-py3-none-any.whl", hash = "sha256:aa89073b98a071fa05a080ec11d7912667dc157bd89dd5b7e323bd9ecc67e77e", size = 68234 }, +] + +[package.optional-dependencies] +rds = [ + { name = "mypy-boto3-rds" }, +] +s3 = [ + { name = "mypy-boto3-s3" }, +] +sns = [ + { name = "mypy-boto3-sns" }, +] + +[[package]] +name = "botocore" +version = "1.36.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jmespath" }, + { name = "python-dateutil" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3a/61/69eb06a803c83e0da733b60b2bc65880c18ef2dee19ee10cf8732794a3c1/botocore-1.36.3.tar.gz", hash = "sha256:775b835e979da5c96548ed1a0b798101a145aec3cd46541d62e27dda5a94d7f8", size = 13507880 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/14/f952fed35b9c04aa66453b5fb5d1262a5a9f5dfdcb396d387c1ff0c6da41/botocore-1.36.3-py3-none-any.whl", hash = "sha256:536ab828e6f90dbb000e3702ac45fd76642113ae2db1b7b1373ad24104e89255", size = 13304681 }, +] + +[[package]] +name = "botocore-stubs" +version = "1.36.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "types-awscrt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5a/ea/09d44698e081b3da7c967a090764386ca32469c416831f2a88236253c6e0/botocore_stubs-1.36.3.tar.gz", hash = "sha256:30437070ba1df6f0549b1ded723aca74d06850610c7df002d643e0aa9f4c4520", size = 41198 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e2/0b/2ab3c4aada20473f989aa7c69a85a70a5ad531c681392d7f649be96322d0/botocore_stubs-1.36.3-py3-none-any.whl", hash = "sha256:af32c6127f507b66762749c7c8a78ba2a22aac86097d15b2097f2bfb4faf1ac3", size = 64004 }, +] + +[[package]] +name = "ccw-manifests-verifier" +version = "1.0.0" +source = { virtual = "." } +dependencies = [ + { name = "aws-lambda-powertools", extra = ["all"] }, + { name = "boto3" }, + { name = "psycopg", extra = ["binary"] }, + { name = "pydantic" }, +] + +[package.dev-dependencies] +dev = [ + { name = "boto3-stubs", extra = ["rds", "s3", "sns"] }, + { name = "ruff" }, + { name = "uv" }, +] + +[package.metadata] +requires-dist = [ + { name = "aws-lambda-powertools", extras = ["all"], specifier = ">=3.4.1" }, + { name = "boto3", specifier = ">=1.36.3" }, + { name = "psycopg", extras = ["binary"], specifier = ">=3.2.4" }, + { name = "pydantic", specifier = ">=2.10.5" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "boto3-stubs", extras = ["rds", "s3", "sns"], specifier = ">=1.36.3" }, + { name = "ruff", specifier = ">=0.9.2" }, + { name = "uv", specifier = ">=0.5.22" }, +] + +[[package]] +name = "cffi" +version = "1.17.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989 }, + { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802 }, + { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792 }, + { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893 }, + { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810 }, + { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200 }, + { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447 }, + { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358 }, + { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469 }, + { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475 }, + { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009 }, +] + +[[package]] +name = "cryptography" +version = "44.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/91/4c/45dfa6829acffa344e3967d6006ee4ae8be57af746ae2eba1c431949b32c/cryptography-44.0.0.tar.gz", hash = "sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02", size = 710657 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/55/09/8cc67f9b84730ad330b3b72cf867150744bf07ff113cda21a15a1c6d2c7c/cryptography-44.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123", size = 6541833 }, + { url = "https://files.pythonhosted.org/packages/7e/5b/3759e30a103144e29632e7cb72aec28cedc79e514b2ea8896bb17163c19b/cryptography-44.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092", size = 3922710 }, + { url = "https://files.pythonhosted.org/packages/5f/58/3b14bf39f1a0cfd679e753e8647ada56cddbf5acebffe7db90e184c76168/cryptography-44.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f", size = 4137546 }, + { url = "https://files.pythonhosted.org/packages/98/65/13d9e76ca19b0ba5603d71ac8424b5694415b348e719db277b5edc985ff5/cryptography-44.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb", size = 3915420 }, + { url = "https://files.pythonhosted.org/packages/b1/07/40fe09ce96b91fc9276a9ad272832ead0fddedcba87f1190372af8e3039c/cryptography-44.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b", size = 4154498 }, + { url = "https://files.pythonhosted.org/packages/75/ea/af65619c800ec0a7e4034207aec543acdf248d9bffba0533342d1bd435e1/cryptography-44.0.0-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543", size = 3932569 }, + { url = "https://files.pythonhosted.org/packages/c7/af/d1deb0c04d59612e3d5e54203159e284d3e7a6921e565bb0eeb6269bdd8a/cryptography-44.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e", size = 4016721 }, + { url = "https://files.pythonhosted.org/packages/bd/69/7ca326c55698d0688db867795134bdfac87136b80ef373aaa42b225d6dd5/cryptography-44.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e", size = 4240915 }, + { url = "https://files.pythonhosted.org/packages/ef/d4/cae11bf68c0f981e0413906c6dd03ae7fa864347ed5fac40021df1ef467c/cryptography-44.0.0-cp37-abi3-win32.whl", hash = "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053", size = 2757925 }, + { url = "https://files.pythonhosted.org/packages/64/b1/50d7739254d2002acae64eed4fc43b24ac0cc44bf0a0d388d1ca06ec5bb1/cryptography-44.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd", size = 3202055 }, + { url = "https://files.pythonhosted.org/packages/11/18/61e52a3d28fc1514a43b0ac291177acd1b4de00e9301aaf7ef867076ff8a/cryptography-44.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591", size = 6542801 }, + { url = "https://files.pythonhosted.org/packages/1a/07/5f165b6c65696ef75601b781a280fc3b33f1e0cd6aa5a92d9fb96c410e97/cryptography-44.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7", size = 3922613 }, + { url = "https://files.pythonhosted.org/packages/28/34/6b3ac1d80fc174812486561cf25194338151780f27e438526f9c64e16869/cryptography-44.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc", size = 4137925 }, + { url = "https://files.pythonhosted.org/packages/d0/c7/c656eb08fd22255d21bc3129625ed9cd5ee305f33752ef2278711b3fa98b/cryptography-44.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289", size = 3915417 }, + { url = "https://files.pythonhosted.org/packages/ef/82/72403624f197af0db6bac4e58153bc9ac0e6020e57234115db9596eee85d/cryptography-44.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7", size = 4155160 }, + { url = "https://files.pythonhosted.org/packages/a2/cd/2f3c440913d4329ade49b146d74f2e9766422e1732613f57097fea61f344/cryptography-44.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c", size = 3932331 }, + { url = "https://files.pythonhosted.org/packages/7f/df/8be88797f0a1cca6e255189a57bb49237402b1880d6e8721690c5603ac23/cryptography-44.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64", size = 4017372 }, + { url = "https://files.pythonhosted.org/packages/af/36/5ccc376f025a834e72b8e52e18746b927f34e4520487098e283a719c205e/cryptography-44.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285", size = 4239657 }, + { url = "https://files.pythonhosted.org/packages/46/b0/f4f7d0d0bcfbc8dd6296c1449be326d04217c57afb8b2594f017eed95533/cryptography-44.0.0-cp39-abi3-win32.whl", hash = "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417", size = 2758672 }, + { url = "https://files.pythonhosted.org/packages/97/9b/443270b9210f13f6ef240eff73fd32e02d381e7103969dc66ce8e89ee901/cryptography-44.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede", size = 3202071 }, +] + +[[package]] +name = "fastjsonschema" +version = "2.21.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8b/50/4b769ce1ac4071a1ef6d86b1a3fb56cdc3a37615e8c5519e1af96cdac366/fastjsonschema-2.21.1.tar.gz", hash = "sha256:794d4f0a58f848961ba16af7b9c85a3e88cd360df008c59aac6fc5ae9323b5d4", size = 373939 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/2b/0817a2b257fe88725c25589d89aec060581aabf668707a8d03b2e9e0cb2a/fastjsonschema-2.21.1-py3-none-any.whl", hash = "sha256:c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667", size = 23924 }, +] + +[[package]] +name = "jmespath" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256 }, +] + +[[package]] +name = "jsonpath-ng" +version = "1.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ply" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6d/86/08646239a313f895186ff0a4573452038eed8c86f54380b3ebac34d32fb2/jsonpath-ng-1.7.0.tar.gz", hash = "sha256:f6f5f7fd4e5ff79c785f1573b394043b39849fb2bb47bcead935d12b00beab3c", size = 37838 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/5a/73ecb3d82f8615f32ccdadeb9356726d6cae3a4bbc840b437ceb95708063/jsonpath_ng-1.7.0-py3-none-any.whl", hash = "sha256:f3d7f9e848cba1b6da28c55b1c26ff915dc9e0b1ba7e752a53d6da8d5cbd00b6", size = 30105 }, +] + +[[package]] +name = "mypy-boto3-rds" +version = "1.36.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/68/9d/e4345ea340bda05bae47afcc1753be3bac0345bddf4fa68a82e0482725f5/mypy_boto3_rds-1.36.0.tar.gz", hash = "sha256:3d4ed0f364233b0315bbe2e42bcd373277c7a489687dfae5593238f26a6bfb53", size = 84298 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/29/d4b527a95bb3cf15075143a2584c7d670c1910344f8a0bcc96dfb2a40e5c/mypy_boto3_rds-1.36.0-py3-none-any.whl", hash = "sha256:47d6df5dc70f83d91139755675cefa95d2107e9d82efe51f70679b7c42b6d73e", size = 90223 }, +] + +[[package]] +name = "mypy-boto3-s3" +version = "1.36.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/fe/243fb2134226fe8b0dd1ba24e5b8eec5fd1cd14f37c1c16dec3620cfd778/mypy_boto3_s3-1.36.0.tar.gz", hash = "sha256:80a881847b0e1fbc5edcad8b2870c110e31e7ef128db42402b70c159b7e93d5a", size = 73116 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/d8/cef1025f6bf3b38d04afcfc2c27cbcfa202708ed97e20cf0e1282af205e4/mypy_boto3_s3-1.36.0-py3-none-any.whl", hash = "sha256:a65ccb6be7b7ebf907887268d44975e435b1fc1164fc0a25de310e2b832f7e91", size = 79692 }, +] + +[[package]] +name = "mypy-boto3-sns" +version = "1.36.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5d/f7/f244090974cf5cb4aeee01aa55ca29b85cc6453c0d3d1a899f1a556497e6/mypy_boto3_sns-1.36.3.tar.gz", hash = "sha256:d521f45f4788a4c11d1715dfe6c2af857eb94f7664b19753a3c656fb11bafa6f", size = 33151 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/35/3caccee6b1aa84a4f1ef5be3685e8a59c1445a12fef85f4da6ad7a202e7a/mypy_boto3_sns-1.36.3-py3-none-any.whl", hash = "sha256:af855273757693d9612f3a33d725d9084fcafdc1dd40975e7db00f2c5573e6d4", size = 40004 }, +] + +[[package]] +name = "ply" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e5/69/882ee5c9d017149285cab114ebeab373308ef0f874fcdac9beb90e0ac4da/ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3", size = 159130 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/58/35da89ee790598a0700ea49b2a66594140f44dec458c07e8e3d4979137fc/ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce", size = 49567 }, +] + +[[package]] +name = "psycopg" +version = "3.2.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e0/f2/954b1467b3e2ca5945b83b5e320268be1f4df486c3e8ffc90f4e4b707979/psycopg-3.2.4.tar.gz", hash = "sha256:f26f1346d6bf1ef5f5ef1714dd405c67fb365cfd1c6cea07de1792747b167b92", size = 156109 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/49/15114d5f7ee68983f4e1a24d47e75334568960352a07c6f0e796e912685d/psycopg-3.2.4-py3-none-any.whl", hash = "sha256:43665368ccd48180744cab26b74332f46b63b7e06e8ce0775547a3533883d381", size = 198716 }, +] + +[package.optional-dependencies] +binary = [ + { name = "psycopg-binary", marker = "implementation_name != 'pypy'" }, +] + +[[package]] +name = "psycopg-binary" +version = "3.2.4" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/e2/f56675aada063762f08559b6969e47e1313f269fc1682c16457c13da8186/psycopg_binary-3.2.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:81ab801c0d35830c876bf0d1edc8e7dd2f73aa2b04fe24eb812159c0b054d149", size = 3846854 }, + { url = "https://files.pythonhosted.org/packages/7b/8b/8c4a66b2b3db494367df0299535b7d2df78f303334228c517b8d00c411d5/psycopg_binary-3.2.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c09e02ce1124eb6638b3381df050a8cf88aedfad4522f939945cda49050a990c", size = 3932292 }, + { url = "https://files.pythonhosted.org/packages/84/e8/618d45f77cebce73d75497c95685a0902aea3783386d9335ce486c69e13a/psycopg_binary-3.2.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a249cdc6a5c2b5088a8677acba66b291e5237524739ab3d27498e1ef189312f5", size = 4493785 }, + { url = "https://files.pythonhosted.org/packages/c4/87/fc30318e6b97e723e017e7dc88d0f721bbfb749de1a6e414e52d4ac54c9a/psycopg_binary-3.2.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2960ba8a5c0ad75e184f6d8bf76bdf023708999efe75fe4e13445136c1cd206", size = 4304874 }, + { url = "https://files.pythonhosted.org/packages/91/30/1d127e651c21cd77befaf361c7c3b9001bfff51ac38027e8fce598ba0701/psycopg_binary-3.2.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dae2e50b0d3425c167eebbedc3553f7c811dbc0dbfc737b6877f68a03be7daf", size = 4541296 }, + { url = "https://files.pythonhosted.org/packages/0d/5e/22c824cb38745c1c744cec85d227190727c564afb75960ce0057ca15fd84/psycopg_binary-3.2.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03bf7ee7e0002c2cce43ecb923ec510358056eb2e44a96afaeb0424518f35206", size = 4255756 }, + { url = "https://files.pythonhosted.org/packages/b3/83/ae8783dec3f7e39df8a4056e4d383926ffec531970c0b415d48d9fd4a2c2/psycopg_binary-3.2.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5f5c85eeb63b1a8a6b026eef57f5da36ff215ce9a6a3bb8e20a409670d6cfbda", size = 3845918 }, + { url = "https://files.pythonhosted.org/packages/be/f7/fb7bffb0c4c45a5a82fe324e4f7b176075a4c5372e546a038858dd13c7ab/psycopg_binary-3.2.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8c7b95899d4d6d23c5cc46cb3419e8e6ca68d867509432ee1487042564a1ea55", size = 3315429 }, + { url = "https://files.pythonhosted.org/packages/81/a3/29f4993a239d6a3fb18ef8681d9990c007f5f73bdd2e21f65f07ac55ad6f/psycopg_binary-3.2.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fa4acea9ca20a567c3872a5afab2084751530bb57b8fb6b52820d5c54e7c8c3b", size = 3399388 }, + { url = "https://files.pythonhosted.org/packages/25/5b/925171cbfa2e3d1ccb7f4c005d0d5db609ba796c1d08a23c42825b09c554/psycopg_binary-3.2.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5c487f35a1905bb15da927c1fc05f70f3d29f0e21fb4ba21d360a0da9c755f20", size = 3436702 }, + { url = "https://files.pythonhosted.org/packages/b6/47/25b2b85b8fcabf99bfa92b4b0d587894c01576bf0b2bf137c243d1eb1070/psycopg_binary-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:80297c3a9f7b5a6afdb0d8f220661ccd796e5c9128c44b32c41267f7daefd37f", size = 2779196 }, +] + +[[package]] +name = "pycparser" +version = "2.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552 }, +] + +[[package]] +name = "pydantic" +version = "2.10.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6a/c7/ca334c2ef6f2e046b1144fe4bb2a5da8a4c574e7f2ebf7e16b34a6a2fa92/pydantic-2.10.5.tar.gz", hash = "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff", size = 761287 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/58/26/82663c79010b28eddf29dcdd0ea723439535fa917fce5905885c0e9ba562/pydantic-2.10.5-py3-none-any.whl", hash = "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53", size = 431426 }, +] + +[[package]] +name = "pydantic-core" +version = "2.27.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/01/f3e5ac5e7c25833db5eb555f7b7ab24cd6f8c322d3a3ad2d67a952dc0abc/pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", size = 413443 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/b1/9bc383f48f8002f99104e3acff6cba1231b29ef76cfa45d1506a5cad1f84/pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", size = 1892709 }, + { url = "https://files.pythonhosted.org/packages/10/6c/e62b8657b834f3eb2961b49ec8e301eb99946245e70bf42c8817350cbefc/pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", size = 1811273 }, + { url = "https://files.pythonhosted.org/packages/ba/15/52cfe49c8c986e081b863b102d6b859d9defc63446b642ccbbb3742bf371/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", size = 1823027 }, + { url = "https://files.pythonhosted.org/packages/b1/1c/b6f402cfc18ec0024120602bdbcebc7bdd5b856528c013bd4d13865ca473/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", size = 1868888 }, + { url = "https://files.pythonhosted.org/packages/bd/7b/8cb75b66ac37bc2975a3b7de99f3c6f355fcc4d89820b61dffa8f1e81677/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", size = 2037738 }, + { url = "https://files.pythonhosted.org/packages/c8/f1/786d8fe78970a06f61df22cba58e365ce304bf9b9f46cc71c8c424e0c334/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", size = 2685138 }, + { url = "https://files.pythonhosted.org/packages/a6/74/d12b2cd841d8724dc8ffb13fc5cef86566a53ed358103150209ecd5d1999/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", size = 1997025 }, + { url = "https://files.pythonhosted.org/packages/a0/6e/940bcd631bc4d9a06c9539b51f070b66e8f370ed0933f392db6ff350d873/pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", size = 2004633 }, + { url = "https://files.pythonhosted.org/packages/50/cc/a46b34f1708d82498c227d5d80ce615b2dd502ddcfd8376fc14a36655af1/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", size = 1999404 }, + { url = "https://files.pythonhosted.org/packages/ca/2d/c365cfa930ed23bc58c41463bae347d1005537dc8db79e998af8ba28d35e/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", size = 2130130 }, + { url = "https://files.pythonhosted.org/packages/f4/d7/eb64d015c350b7cdb371145b54d96c919d4db516817f31cd1c650cae3b21/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", size = 2157946 }, + { url = "https://files.pythonhosted.org/packages/a4/99/bddde3ddde76c03b65dfd5a66ab436c4e58ffc42927d4ff1198ffbf96f5f/pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", size = 1834387 }, + { url = "https://files.pythonhosted.org/packages/71/47/82b5e846e01b26ac6f1893d3c5f9f3a2eb6ba79be26eef0b759b4fe72946/pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", size = 1990453 }, + { url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186 }, +] + +[[package]] +name = "pydantic-settings" +version = "2.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "python-dotenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/73/7b/c58a586cd7d9ac66d2ee4ba60ca2d241fa837c02bca9bea80a9a8c3d22a9/pydantic_settings-2.7.1.tar.gz", hash = "sha256:10c9caad35e64bfb3c2fbf70a078c0e25cc92499782e5200747f942a065dec93", size = 79920 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b4/46/93416fdae86d40879714f72956ac14df9c7b76f7d41a4d68aa9f71a0028b/pydantic_settings-2.7.1-py3-none-any.whl", hash = "sha256:590be9e6e24d06db33a4262829edef682500ef008565a969c73d39d5f8bfb3fd", size = 29718 }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, +] + +[[package]] +name = "python-dotenv" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bc/57/e84d88dfe0aec03b7a2d4327012c1627ab5f03652216c63d49846d7a6c58/python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", size = 39115 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 }, +] + +[[package]] +name = "ruff" +version = "0.9.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/80/63/77ecca9d21177600f551d1c58ab0e5a0b260940ea7312195bd2a4798f8a8/ruff-0.9.2.tar.gz", hash = "sha256:b5eceb334d55fae5f316f783437392642ae18e16dcf4f1858d55d3c2a0f8f5d0", size = 3553799 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/b9/0e168e4e7fb3af851f739e8f07889b91d1a33a30fca8c29fa3149d6b03ec/ruff-0.9.2-py3-none-linux_armv6l.whl", hash = "sha256:80605a039ba1454d002b32139e4970becf84b5fee3a3c3bf1c2af6f61a784347", size = 11652408 }, + { url = "https://files.pythonhosted.org/packages/2c/22/08ede5db17cf701372a461d1cb8fdde037da1d4fa622b69ac21960e6237e/ruff-0.9.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b9aab82bb20afd5f596527045c01e6ae25a718ff1784cb92947bff1f83068b00", size = 11587553 }, + { url = "https://files.pythonhosted.org/packages/42/05/dedfc70f0bf010230229e33dec6e7b2235b2a1b8cbb2a991c710743e343f/ruff-0.9.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fbd337bac1cfa96be615f6efcd4bc4d077edbc127ef30e2b8ba2a27e18c054d4", size = 11020755 }, + { url = "https://files.pythonhosted.org/packages/df/9b/65d87ad9b2e3def67342830bd1af98803af731243da1255537ddb8f22209/ruff-0.9.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82b35259b0cbf8daa22a498018e300b9bb0174c2bbb7bcba593935158a78054d", size = 11826502 }, + { url = "https://files.pythonhosted.org/packages/93/02/f2239f56786479e1a89c3da9bc9391120057fc6f4a8266a5b091314e72ce/ruff-0.9.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b6a9701d1e371bf41dca22015c3f89769da7576884d2add7317ec1ec8cb9c3c", size = 11390562 }, + { url = "https://files.pythonhosted.org/packages/c9/37/d3a854dba9931f8cb1b2a19509bfe59e00875f48ade632e95aefcb7a0aee/ruff-0.9.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9cc53e68b3c5ae41e8faf83a3b89f4a5d7b2cb666dff4b366bb86ed2a85b481f", size = 12548968 }, + { url = "https://files.pythonhosted.org/packages/fa/c3/c7b812bb256c7a1d5553433e95980934ffa85396d332401f6b391d3c4569/ruff-0.9.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:8efd9da7a1ee314b910da155ca7e8953094a7c10d0c0a39bfde3fcfd2a015684", size = 13187155 }, + { url = "https://files.pythonhosted.org/packages/bd/5a/3c7f9696a7875522b66aa9bba9e326e4e5894b4366bd1dc32aa6791cb1ff/ruff-0.9.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3292c5a22ea9a5f9a185e2d131dc7f98f8534a32fb6d2ee7b9944569239c648d", size = 12704674 }, + { url = "https://files.pythonhosted.org/packages/be/d6/d908762257a96ce5912187ae9ae86792e677ca4f3dc973b71e7508ff6282/ruff-0.9.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a605fdcf6e8b2d39f9436d343d1f0ff70c365a1e681546de0104bef81ce88df", size = 14529328 }, + { url = "https://files.pythonhosted.org/packages/2d/c2/049f1e6755d12d9cd8823242fa105968f34ee4c669d04cac8cea51a50407/ruff-0.9.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c547f7f256aa366834829a08375c297fa63386cbe5f1459efaf174086b564247", size = 12385955 }, + { url = "https://files.pythonhosted.org/packages/91/5a/a9bdb50e39810bd9627074e42743b00e6dc4009d42ae9f9351bc3dbc28e7/ruff-0.9.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d18bba3d3353ed916e882521bc3e0af403949dbada344c20c16ea78f47af965e", size = 11810149 }, + { url = "https://files.pythonhosted.org/packages/e5/fd/57df1a0543182f79a1236e82a79c68ce210efb00e97c30657d5bdb12b478/ruff-0.9.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:b338edc4610142355ccf6b87bd356729b62bf1bc152a2fad5b0c7dc04af77bfe", size = 11479141 }, + { url = "https://files.pythonhosted.org/packages/dc/16/bc3fd1d38974f6775fc152a0554f8c210ff80f2764b43777163c3c45d61b/ruff-0.9.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:492a5e44ad9b22a0ea98cf72e40305cbdaf27fac0d927f8bc9e1df316dcc96eb", size = 12014073 }, + { url = "https://files.pythonhosted.org/packages/47/6b/e4ca048a8f2047eb652e1e8c755f384d1b7944f69ed69066a37acd4118b0/ruff-0.9.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:af1e9e9fe7b1f767264d26b1075ac4ad831c7db976911fa362d09b2d0356426a", size = 12435758 }, + { url = "https://files.pythonhosted.org/packages/c2/40/4d3d6c979c67ba24cf183d29f706051a53c36d78358036a9cd21421582ab/ruff-0.9.2-py3-none-win32.whl", hash = "sha256:71cbe22e178c5da20e1514e1e01029c73dc09288a8028a5d3446e6bba87a5145", size = 9796916 }, + { url = "https://files.pythonhosted.org/packages/c3/ef/7f548752bdb6867e6939489c87fe4da489ab36191525fadc5cede2a6e8e2/ruff-0.9.2-py3-none-win_amd64.whl", hash = "sha256:c5e1d6abc798419cf46eed03f54f2e0c3adb1ad4b801119dedf23fcaf69b55b5", size = 10773080 }, + { url = "https://files.pythonhosted.org/packages/0e/4e/33df635528292bd2d18404e4daabcd74ca8a9853b2e1df85ed3d32d24362/ruff-0.9.2-py3-none-win_arm64.whl", hash = "sha256:a1b63fa24149918f8b37cef2ee6fff81f24f0d74b6f0bdc37bc3e1f2143e41c6", size = 10001738 }, +] + +[[package]] +name = "s3transfer" +version = "0.11.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1a/aa/fdd958c626b00e3f046d4004363e7f1a2aba4354f78d65ceb3b217fa5eb8/s3transfer-0.11.1.tar.gz", hash = "sha256:3f25c900a367c8b7f7d8f9c34edc87e300bde424f779dc9f0a8ae4f9df9264f6", size = 146952 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/ce/22673f4a85ccc640735b4f8d12178a0f41b5d3c6eda7f33756d10ce56901/s3transfer-0.11.1-py3-none-any.whl", hash = "sha256:8fa0aa48177be1f3425176dfe1ab85dcd3d962df603c3dbfc585e6bf857ef0ff", size = 84111 }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, +] + +[[package]] +name = "types-awscrt" +version = "0.23.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dd/97/c62253e8ed65562c67b2138339444cc77507c8ee01c091e02ead1311e4b8/types_awscrt-0.23.6.tar.gz", hash = "sha256:405bce8c281f9e7c6c92a229225cc0bf10d30729a6a601123213389bd524b8b1", size = 15124 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/21/f1/0f0869d35c1b746df98d60016f898eb49db208747a4ed2de81b58f48ecd8/types_awscrt-0.23.6-py3-none-any.whl", hash = "sha256:fbf9c221af5607b24bf17f8431217ce8b9a27917139edbc984891eb63fd5a593", size = 19025 }, +] + +[[package]] +name = "types-s3transfer" +version = "0.11.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f0/01/0169c095070a8cb97baf075246b8804390082ee189d344a6767eb89849cd/types_s3transfer-0.11.1.tar.gz", hash = "sha256:6ab89d4d76bcbf6d494582949963b4672347e8daa397d9790f3684b4fcf873c4", size = 14055 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/87/2452812a3d57a13af13a23239da6c781a079e508bc70a44df576ce76b7c1/types_s3transfer-0.11.1-py3-none-any.whl", hash = "sha256:ddb20d103361c2d7cf95e9e73468cdd12f049f503b1512e6fdfe5a66fa086d2d", size = 19487 }, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, +] + +[[package]] +name = "tzdata" +version = "2025.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/0f/fa4723f22942480be4ca9527bbde8d43f6c3f2fe8412f00e7f5f6746bc8b/tzdata-2025.1.tar.gz", hash = "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694", size = 194950 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/dd/84f10e23edd882c6f968c21c2434fe67bd4a528967067515feca9e611e5e/tzdata-2025.1-py2.py3-none-any.whl", hash = "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639", size = 346762 }, +] + +[[package]] +name = "urllib3" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369 }, +] + +[[package]] +name = "uv" +version = "0.5.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ef/22/3e634cc4caf0a5acae08fc7ad80a76cf01a0be779ceb2cde3e14e164c1eb/uv-0.5.22.tar.gz", hash = "sha256:12f78366075bcff63e926f2beaf9dafe92f94368c736f4d63a64f4c6a2072af5", size = 2662375 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4f/40/f40aec432b7d53faa2e8a3bf155adaf2876ff8b327b7d2d43f5af7d7c213/uv-0.5.22-py3-none-linux_armv6l.whl", hash = "sha256:7b4024a82616e08f8e2361ae113bf74b8bef6f028835eb1300678eb9182e1bdc", size = 15317990 }, + { url = "https://files.pythonhosted.org/packages/be/36/a482fde2e4b762bc0838f5dcf195d2a7b5dd06ccdd5ab23004ac9451f34d/uv-0.5.22-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:32658bb5c8637a437b2a209b937e11beba7600dea600c672edef180b4748a729", size = 15474569 }, + { url = "https://files.pythonhosted.org/packages/bf/c7/462bc209bd6f9f4fc3db428b345a70fd59296ee914be090389c4f6f6a9f8/uv-0.5.22-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1ace09ab8028a2d596b84d8814ff78ce2a13f1e8a1e664523e6a6eeb9ef50aad", size = 14382343 }, + { url = "https://files.pythonhosted.org/packages/a0/e8/cc973a1fd0ebff01a7ddff903d2782a280f5588da4ed57ea70dad0a403e4/uv-0.5.22-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:9c9dda5ea4bcd49b0a7c36da6f1a0fd7a74fced354de3971f40c8176c5398d8a", size = 14836795 }, + { url = "https://files.pythonhosted.org/packages/8b/69/fa8ef336f799bd185e0a218ff28d39ca930295882edc972019abda23c166/uv-0.5.22-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f2f35104b3121d26bc1e2a19444cae589ec7307314d0b4788f1d784fab41748", size = 15052067 }, + { url = "https://files.pythonhosted.org/packages/23/18/ab10457abe0cac1cbee327c31c2a96001f4318451e0017f4727a3962045a/uv-0.5.22-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25e50a3216fd3370c8fad7c9c23539997e160cbc2e5121e0a8ca21d47a6bbcac", size = 15788379 }, + { url = "https://files.pythonhosted.org/packages/c2/24/c8b296df29cd92c825db8c60ae0799bd977fe1c91712599e1fa5d9bea8b5/uv-0.5.22-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:ead10e1c0f443cf9921d73c18c65935b502bd4eb3cc1bbbbb43e0e7435a31dbd", size = 16705352 }, + { url = "https://files.pythonhosted.org/packages/34/7f/2cdf72eb49b99d222e6eb264515ff8433572ff8574cafcf8a910c816c459/uv-0.5.22-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8674f547ddf9b988d12120fa14a8eca4730b019869a2bacf11a89a6de788e6e6", size = 16428333 }, + { url = "https://files.pythonhosted.org/packages/c8/a5/74b580945594dcc444f9a1bce64f3c081a04d9c9f435340ae044da2416d9/uv-0.5.22-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cedf06ebfa2b233450b7f71a16c90f103ea68f415f45e61ec691554c03cccdb", size = 20752598 }, + { url = "https://files.pythonhosted.org/packages/fc/86/fddff1dd7c894bb4de44a66bc4372c9b3d64138f63bced3e0f919ca8f0ab/uv-0.5.22-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2f1eb24426680a22ca9a824f2af83a5e9b2179d709cd1b48ddd10e81e249d9c", size = 16118825 }, + { url = "https://files.pythonhosted.org/packages/7d/ef/860249b83023dfbcb2dc4f4ef66082a8e45504138fdaf9631d96b0221e3d/uv-0.5.22-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:9b3e4bcee00b9f343c29bcd8251a739727f60c16870148336b5a97f94bb26a7b", size = 15122109 }, + { url = "https://files.pythonhosted.org/packages/e7/82/05ef1cf9de48a456969b40e08dae0d5afb9fc9b8ed6e25d42d4cdf2e4ab6/uv-0.5.22-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:82261745216bdb3faa80eab99fa7ebe7918fdde77b78a191e9f1a7f45450c405", size = 15043439 }, + { url = "https://files.pythonhosted.org/packages/9a/8a/782bdbbdd0d8623c807fedda6b11c3ab4c063dcf4940e7e88f3e652d51bb/uv-0.5.22-py3-none-musllinux_1_1_i686.whl", hash = "sha256:ee27c6bc80b59ec8680c7a9bff9716aaa082e403b03986425f6c4f7a4b2f2a7e", size = 15434092 }, + { url = "https://files.pythonhosted.org/packages/fa/fc/f267ef26fd75846f49a6e1e1ff61c18357046d6d0688409d70a16e21bae5/uv-0.5.22-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:4c03ad206af6c521d05a9b6c8f1f265b5a9390858e7095f0b7354bb2a86a33f1", size = 16247589 }, + { url = "https://files.pythonhosted.org/packages/7c/51/01277ba4e7139820921ffa09bca3143d854b38d77d1fc80dc7c6ab3a0c69/uv-0.5.22-py3-none-win32.whl", hash = "sha256:34235a5b50c8b03b7c4f4be8dc3f021802672bd3152812a7f05710d67459bf76", size = 15326817 }, + { url = "https://files.pythonhosted.org/packages/72/ee/f53d2f8f24b1f9420f85dec8d573772aa41b5a01211198112d9ce4cbb6df/uv-0.5.22-py3-none-win_amd64.whl", hash = "sha256:8c57f65b570508fb6a460001f187fffebbc7665e9c642cefbca3719bc48f078f", size = 16657665 }, +] + +[[package]] +name = "wrapt" +version = "1.17.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/fc/e91cc220803d7bc4db93fb02facd8461c37364151b8494762cc88b0fbcef/wrapt-1.17.2.tar.gz", hash = "sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3", size = 55531 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/b9/0ffd557a92f3b11d4c5d5e0c5e4ad057bd9eb8586615cdaf901409920b14/wrapt-1.17.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6ed6ffac43aecfe6d86ec5b74b06a5be33d5bb9243d055141e8cabb12aa08125", size = 53800 }, + { url = "https://files.pythonhosted.org/packages/c0/ef/8be90a0b7e73c32e550c73cfb2fa09db62234227ece47b0e80a05073b375/wrapt-1.17.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:35621ae4c00e056adb0009f8e86e28eb4a41a4bfa8f9bfa9fca7d343fe94f998", size = 38824 }, + { url = "https://files.pythonhosted.org/packages/36/89/0aae34c10fe524cce30fe5fc433210376bce94cf74d05b0d68344c8ba46e/wrapt-1.17.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a604bf7a053f8362d27eb9fefd2097f82600b856d5abe996d623babd067b1ab5", size = 38920 }, + { url = "https://files.pythonhosted.org/packages/3b/24/11c4510de906d77e0cfb5197f1b1445d4fec42c9a39ea853d482698ac681/wrapt-1.17.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cbabee4f083b6b4cd282f5b817a867cf0b1028c54d445b7ec7cfe6505057cf8", size = 88690 }, + { url = "https://files.pythonhosted.org/packages/71/d7/cfcf842291267bf455b3e266c0c29dcb675b5540ee8b50ba1699abf3af45/wrapt-1.17.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49703ce2ddc220df165bd2962f8e03b84c89fee2d65e1c24a7defff6f988f4d6", size = 80861 }, + { url = "https://files.pythonhosted.org/packages/d5/66/5d973e9f3e7370fd686fb47a9af3319418ed925c27d72ce16b791231576d/wrapt-1.17.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8112e52c5822fc4253f3901b676c55ddf288614dc7011634e2719718eaa187dc", size = 89174 }, + { url = "https://files.pythonhosted.org/packages/a7/d3/8e17bb70f6ae25dabc1aaf990f86824e4fd98ee9cadf197054e068500d27/wrapt-1.17.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9fee687dce376205d9a494e9c121e27183b2a3df18037f89d69bd7b35bcf59e2", size = 86721 }, + { url = "https://files.pythonhosted.org/packages/6f/54/f170dfb278fe1c30d0ff864513cff526d624ab8de3254b20abb9cffedc24/wrapt-1.17.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:18983c537e04d11cf027fbb60a1e8dfd5190e2b60cc27bc0808e653e7b218d1b", size = 79763 }, + { url = "https://files.pythonhosted.org/packages/4a/98/de07243751f1c4a9b15c76019250210dd3486ce098c3d80d5f729cba029c/wrapt-1.17.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:703919b1633412ab54bcf920ab388735832fdcb9f9a00ae49387f0fe67dad504", size = 87585 }, + { url = "https://files.pythonhosted.org/packages/f9/f0/13925f4bd6548013038cdeb11ee2cbd4e37c30f8bfd5db9e5a2a370d6e20/wrapt-1.17.2-cp313-cp313-win32.whl", hash = "sha256:abbb9e76177c35d4e8568e58650aa6926040d6a9f6f03435b7a522bf1c487f9a", size = 36676 }, + { url = "https://files.pythonhosted.org/packages/bf/ae/743f16ef8c2e3628df3ddfd652b7d4c555d12c84b53f3d8218498f4ade9b/wrapt-1.17.2-cp313-cp313-win_amd64.whl", hash = "sha256:69606d7bb691b50a4240ce6b22ebb319c1cfb164e5f6569835058196e0f3a845", size = 38871 }, + { url = "https://files.pythonhosted.org/packages/3d/bc/30f903f891a82d402ffb5fda27ec1d621cc97cb74c16fea0b6141f1d4e87/wrapt-1.17.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:4a721d3c943dae44f8e243b380cb645a709ba5bd35d3ad27bc2ed947e9c68192", size = 56312 }, + { url = "https://files.pythonhosted.org/packages/8a/04/c97273eb491b5f1c918857cd26f314b74fc9b29224521f5b83f872253725/wrapt-1.17.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:766d8bbefcb9e00c3ac3b000d9acc51f1b399513f44d77dfe0eb026ad7c9a19b", size = 40062 }, + { url = "https://files.pythonhosted.org/packages/4e/ca/3b7afa1eae3a9e7fefe499db9b96813f41828b9fdb016ee836c4c379dadb/wrapt-1.17.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e496a8ce2c256da1eb98bd15803a79bee00fc351f5dfb9ea82594a3f058309e0", size = 40155 }, + { url = "https://files.pythonhosted.org/packages/89/be/7c1baed43290775cb9030c774bc53c860db140397047cc49aedaf0a15477/wrapt-1.17.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d615e4fe22f4ad3528448c193b218e077656ca9ccb22ce2cb20db730f8d306", size = 113471 }, + { url = "https://files.pythonhosted.org/packages/32/98/4ed894cf012b6d6aae5f5cc974006bdeb92f0241775addad3f8cd6ab71c8/wrapt-1.17.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a5aaeff38654462bc4b09023918b7f21790efb807f54c000a39d41d69cf552cb", size = 101208 }, + { url = "https://files.pythonhosted.org/packages/ea/fd/0c30f2301ca94e655e5e057012e83284ce8c545df7661a78d8bfca2fac7a/wrapt-1.17.2-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a7d15bbd2bc99e92e39f49a04653062ee6085c0e18b3b7512a4f2fe91f2d681", size = 109339 }, + { url = "https://files.pythonhosted.org/packages/75/56/05d000de894c4cfcb84bcd6b1df6214297b8089a7bd324c21a4765e49b14/wrapt-1.17.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e3890b508a23299083e065f435a492b5435eba6e304a7114d2f919d400888cc6", size = 110232 }, + { url = "https://files.pythonhosted.org/packages/53/f8/c3f6b2cf9b9277fb0813418e1503e68414cd036b3b099c823379c9575e6d/wrapt-1.17.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8c8b293cd65ad716d13d8dd3624e42e5a19cc2a2f1acc74b30c2c13f15cb61a6", size = 100476 }, + { url = "https://files.pythonhosted.org/packages/a7/b1/0bb11e29aa5139d90b770ebbfa167267b1fc548d2302c30c8f7572851738/wrapt-1.17.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c82b8785d98cdd9fed4cac84d765d234ed3251bd6afe34cb7ac523cb93e8b4f", size = 106377 }, + { url = "https://files.pythonhosted.org/packages/6a/e1/0122853035b40b3f333bbb25f1939fc1045e21dd518f7f0922b60c156f7c/wrapt-1.17.2-cp313-cp313t-win32.whl", hash = "sha256:13e6afb7fe71fe7485a4550a8844cc9ffbe263c0f1a1eea569bc7091d4898555", size = 37986 }, + { url = "https://files.pythonhosted.org/packages/09/5e/1655cf481e079c1f22d0cabdd4e51733679932718dc23bf2db175f329b76/wrapt-1.17.2-cp313-cp313t-win_amd64.whl", hash = "sha256:eaf675418ed6b3b31c7a989fd007fa7c3be66ce14e5c3b27336383604c9da85c", size = 40750 }, + { url = "https://files.pythonhosted.org/packages/2d/82/f56956041adef78f849db6b289b282e72b55ab8045a75abad81898c28d19/wrapt-1.17.2-py3-none-any.whl", hash = "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8", size = 23594 }, +] diff --git a/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/main.tf b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/main.tf new file mode 100644 index 0000000000..2f814c3271 --- /dev/null +++ b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/main.tf @@ -0,0 +1,111 @@ +locals { + env = terraform.workspace + service = "pipeline" + layer = "app" + service_name_prefix = "bfd-${local.env}-${local.service}" + + account_id = data.aws_caller_identity.current.account_id + region = data.aws_region.current.name + vpc_id = data.aws_vpc.main.id + kms_key_id = data.aws_kms_key.cmk.arn + kms_config_key_arns = flatten( + [ + for v in data.aws_kms_key.config_cmk.multi_region_configuration : + concat(v.primary_key[*].arn, v.replica_keys[*].arn) + ] + ) + + lambda_name = "ccw-manifests-verifier" + lambda_full_name = "${local.service_name_prefix}-${local.lambda_name}" + lambda_src = replace(local.lambda_name, "-", "_") + lambda_image_uri = "${data.aws_ecr_repository.ecr.repository_url}:${var.bfd_version}" + + alert_topics = [for v in split(",", nonsensitive(data.aws_ssm_parameter.alert_topics.value)) : trimspace(v)] +} + + +resource "aws_scheduler_schedule_group" "this" { + name = "${local.lambda_full_name}-lambda-schedules" +} + +resource "aws_scheduler_schedule" "this" { + name = "${local.lambda_full_name}-mon-9am-et" + group_name = aws_scheduler_schedule_group.this.name + + flexible_time_window { + mode = "OFF" + } + + # Schedule specifies to run every Monday at 9 AM ET + schedule_expression = "cron(0 9 ? * MON *)" + schedule_expression_timezone = "America/New_York" + + target { + arn = aws_lambda_function.this.arn + role_arn = aws_iam_role.scheduler_assume_role.arn + } +} + +resource "aws_lambda_function" "this" { + depends_on = [aws_iam_role_policy_attachment.this] + + function_name = local.lambda_full_name + + description = join("", [ + "Lambda that reconciles the state of manifest files in S3 in the Incoming paths against their ", + "state in the database verifying that they have been loaded. If any are unloaded, an alert is ", + "sent" + ]) + + kms_key_arn = local.kms_key_id + image_uri = local.lambda_image_uri + source_code_hash = trimprefix(data.aws_ecr_image.this.id, "sha256:") + architectures = ["arm64"] + package_type = "Image" + memory_size = 128 + timeout = 60 + + tags = { + Name = local.lambda_full_name + } + + environment { + variables = { + BFD_ENVIRONMENT = local.env + DB_CLUSTER_NAME = var.db_cluster_identifier + ETL_BUCKET_ID = var.etl_bucket_id + ALERT_TOPIC_ARNS = join(",", data.aws_sns_topic.alert_topic[*].arn) + } + } + + role = aws_iam_role.this.arn + + vpc_config { + security_group_ids = [aws_security_group.this.id] + subnet_ids = data.aws_subnets.main.ids + } +} + +resource "aws_security_group" "this" { + description = "Allow egress from ${local.lambda_full_name} Lambda" + name = local.lambda_full_name + tags = { Name = local.lambda_full_name } + vpc_id = data.aws_vpc.main.id + + egress { + from_port = 0 + protocol = "-1" + to_port = 0 + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "aws_security_group_rule" "rds" { + type = "ingress" + from_port = 5432 + to_port = 5432 + protocol = "tcp" + description = "Allow ${local.lambda_full_name} access to ${var.db_cluster_identifier}" + security_group_id = data.aws_security_group.rds.id + source_security_group_id = aws_security_group.this.id +} diff --git a/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/variables.tf b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/variables.tf new file mode 100644 index 0000000000..c162f3175d --- /dev/null +++ b/ops/terraform/services/pipeline/modules/bfd_pipeline_ccw_manifests_verifier/variables.tf @@ -0,0 +1,29 @@ +variable "vpc_name" { + type = string + description = "Name of the current VPC" +} + +variable "bfd_version" { + type = string + description = "BFD Lambda version to deploy" +} + +variable "kms_key_alias" { + type = string + description = "Alias/ID of the main CMK" +} + +variable "kms_config_key_alias" { + type = string + description = "Alias/ID of the config CMK" +} + +variable "db_cluster_identifier" { + type = string + description = "Cluster ID of the target database" +} + +variable "etl_bucket_id" { + type = string + description = "Bucket ID of the Pipeline ETL S3 Bucket" +} diff --git a/ops/terraform/services/pipeline/user-data.sh.tftpl b/ops/terraform/services/pipeline/user-data.sh.tftpl index 1afde5f50d..672bc6137c 100644 --- a/ops/terraform/services/pipeline/user-data.sh.tftpl +++ b/ops/terraform/services/pipeline/user-data.sh.tftpl @@ -18,20 +18,20 @@ aws ssm get-parameters-by-path \ --path "/bfd/${env}/pipeline/nonsensitive/${pipeline_instance}" \ --recursive \ --region us-east-1 \ - --query 'Parameters' | jq 'map({(.Name|split("/")|last): .Value})|add' > pipeline_vars.json + --query 'Parameters' | jq 'map({(.Name|split("/")[6:]|join("_")): .Value})|add' > pipeline_vars.json # shared pipeline variables aws ssm get-parameters-by-path \ --path "/bfd/${env}/pipeline/nonsensitive/" \ --region us-east-1 \ - --query 'Parameters' | jq 'map({(.Name|split("/")|last): .Value})|add' > shared_pipeline_vars.json + --query 'Parameters' | jq 'map({(.Name|split("/")[5:]|join("_")): .Value})|add' > shared_pipeline_vars.json # common service variables aws ssm get-parameters-by-path \ --path "/bfd/${env}/common/nonsensitive/" \ --recursive \ --region us-east-1 \ - --query 'Parameters' | jq 'map({(.Name|split("/")|last): .Value})|add' > common_vars.json + --query 'Parameters' | jq 'map({(.Name|split("/")[5:]|join("_")): .Value})|add' > common_vars.json new_relic_sensitive="$(aws ssm get-parameters-by-path \ --with-decryption \