diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 540fe1294..d47cc2e52 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -154,7 +154,7 @@ jobs: BAKEFILE_PATH: ${{ steps.meta.outputs.bake-file }} - name: Build and push Docker image id: build-push - uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0 + uses: docker/build-push-action@af5a7ed5ba88268d5278f7203fb52cd833f66d6e # v5.2.0 with: context: . github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml index 06f797a56..928341739 100644 --- a/.github/workflows/qa.yml +++ b/.github/workflows/qa.yml @@ -279,4 +279,4 @@ jobs: env: GITHUB_TOKEN: ${{ github.token }} - name: Run TFLint - run: tflint --format compact --recursive --minimum-failure-severity=error + run: tflint --format compact --recursive --minimum-failure-severity=warning diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 269dc29a6..04b3201e0 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,3 +1,9 @@ { - "recommendations": ["Vue.volar", "dbaeumer.vscode-eslint"] + "recommendations": [ + "Vue.volar", + "hashicorp.terraform", + "ms-azuretools.vscode-docker", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode" + ] } diff --git a/docs/decisions/0007-adopt-vue-recommended-linting.md b/docs/decisions/0007-adopt-vue-recommended-linting.md index 949f29d91..be1e85d32 100644 --- a/docs/decisions/0007-adopt-vue-recommended-linting.md +++ b/docs/decisions/0007-adopt-vue-recommended-linting.md @@ -1,7 +1,7 @@ # 0007. Adopt vue/recommended linting Date: 2024-02-26 -Status: Proposed +Status: Accepted ## Context and Problem Statement diff --git a/packages/client/.eslintrc.js b/packages/client/.eslintrc.js index 8c9ef6b4e..4d36214bb 100644 --- a/packages/client/.eslintrc.js +++ b/packages/client/.eslintrc.js @@ -5,7 +5,7 @@ module.exports = { es6: true, }, extends: [ - 'plugin:vue/essential', + 'plugin:vue/recommended', '@vue/airbnb', ], parserOptions: { @@ -24,11 +24,116 @@ module.exports = { 'no-restricted-syntax': 'off', 'import/prefer-default-export': 'off', - - 'vue/multi-word-component-names': 'off', - 'vue/no-mutating-props': 'off', }, overrides: [ + // This override is part of the process of upgrading plugin:vue/essential -> plugin:vue/recommended. + // In order to avoid a huge stop-the-world PR, we're introducing the plugin upgrade and a file list here + // that ignores the added rules. That way, we can bring individual files into compliance in smaller, less + // disruptive PRs. We'll plan to burn down the list of files in this list until we're done and can remove + // this override entirely. + { + files: [ + // File list to ignore generated by `yarn run lint --no-fix --format unix | sed -E 's/:.+//g' | uniq` + './src/App.vue', + './src/arpa_reporter/App.vue', + './src/arpa_reporter/components/AlertBox.vue', + './src/arpa_reporter/components/DownloadButton.vue', + './src/arpa_reporter/components/DownloadFileButton.vue', + './src/arpa_reporter/components/DownloadFileButtonSmall.vue', + './src/arpa_reporter/components/DownloadTemplateBtn.vue', + './src/arpa_reporter/components/Navigation.vue', + './src/arpa_reporter/components/StandardForm.vue', + './src/arpa_reporter/views/Agencies.vue', + './src/arpa_reporter/views/Agency.vue', + './src/arpa_reporter/views/Home.vue', + './src/arpa_reporter/views/Login.vue', + './src/arpa_reporter/views/NewTemplate.vue', + './src/arpa_reporter/views/NewUpload.vue', + './src/arpa_reporter/views/ReportingPeriod.vue', + './src/arpa_reporter/views/ReportingPeriods.vue', + './src/arpa_reporter/views/Subrecipient.vue', + './src/arpa_reporter/views/Subrecipients.vue', + './src/arpa_reporter/views/Upload.vue', + './src/arpa_reporter/views/Uploads.vue', + './src/arpa_reporter/views/User.vue', + './src/arpa_reporter/views/Users.vue', + './src/arpa_reporter/views/Validation.vue', + './src/components/GrantsTable.vue', + './src/components/Layout.vue', + './src/components/Modals/AddKeyword.vue', + './src/components/Modals/AddOrganization.vue', + './src/components/Modals/AddTeam.vue', + './src/components/Modals/AddUser.vue', + './src/components/Modals/EditOrganization.vue', + './src/components/Modals/EditTeam.vue', + './src/components/Modals/EditUser.vue', + './src/components/Modals/GrantDetailsLegacy.vue', + './src/components/Modals/ImportTeams.vue', + './src/components/Modals/ImportUsers.vue', + './src/components/Modals/ProfileSettings.vue', + './src/components/Modals/SavedSearchPanel.vue', + './src/components/Modals/SearchPanel.vue', + './src/components/SearchFilter.vue', + './src/components/Uploader.vue', + './src/components/UserAvatar.vue', + './src/main.js', + './src/views/ArpaAnnualPerformanceReporter.vue', + './src/views/Dashboard.vue', + './src/views/EligibilityCodes.vue', + './src/views/GrantDetails.vue', + './src/views/Grants.vue', + './src/views/Home.vue', + './src/views/Keywords.vue', + './src/views/Login.vue', + './src/views/MyGrants.vue', + './src/views/MyProfile.vue', + './src/views/NotFound.vue', + './src/views/Organizations.vue', + './src/views/RecentActivity.vue', + './src/views/Teams.vue', + './src/views/UpcomingClosingDates.vue', + './src/views/Users.vue', + ], + rules: { + // List of essential rules we previously had turned off + 'vue/multi-word-component-names': 'off', + 'vue/no-mutating-props': 'off', + // List of strongly recommended rules introduced (https://eslint.vuejs.org/rules/#priority-b-strongly-recommended-improving-readability) + 'vue/attribute-hyphenation': 'off', + 'vue/component-definition-name-casing': 'off', + 'vue/first-attribute-linebreak': 'off', + 'vue/html-closing-bracket-newline': 'off', + 'vue/html-closing-bracket-spacing': 'off', + 'vue/html-end-tags': 'off', + 'vue/html-indent': 'off', + 'vue/html-quotes': 'off', + 'vue/html-self-closing': 'off', + 'vue/max-attributes-per-line': 'off', + 'vue/multiline-html-element-content-newline': 'off', + 'vue/mustache-interpolation-spacing': 'off', + 'vue/no-multi-spaces': 'off', + 'vue/no-spaces-around-equal-signs-in-attribute': 'off', + 'vue/no-template-shadow': 'off', + 'vue/one-component-per-file': 'off', + 'vue/prop-name-casing': 'off', + 'vue/require-default-prop': 'off', + 'vue/require-explicit-emits': 'off', + 'vue/require-prop-types': 'off', + 'vue/singleline-html-element-content-newline': 'off', + 'vue/v-bind-style': 'off', + 'vue/v-on-event-hyphenation': 'off', + 'vue/v-on-style': 'off', + 'vue/v-slot-style': 'off', + // List of recommended rules introduced (https://eslint.vuejs.org/rules/#priority-b-strongly-recommended-improving-readability) + 'vue/attributes-order': 'off', + 'vue/component-tags-order': 'off', + 'vue/no-lone-template': 'off', + 'vue/no-multiple-slot-args': 'off', + 'vue/no-v-html': 'off', + 'vue/order-in-components': 'off', + 'vue/this-in-template': 'off', + }, + }, { files: [ '**/__tests__/*.{j,t}s?(x)', diff --git a/packages/server/__tests__/email/email.test.js b/packages/server/__tests__/email/email.test.js index 552f8fd22..5d4e5f3d4 100644 --- a/packages/server/__tests__/email/email.test.js +++ b/packages/server/__tests__/email/email.test.js @@ -427,6 +427,21 @@ describe('Email sender', () => { expect(body).to.include(name); expect(body).to.include(moment(openDate).format('MMMM Do YYYY')); }); + it('links to Grants.gov when Grant Details page is not live', async () => { + const agencies = await db.getAgency(fixtures.agencies.accountancy.id); + const agency = agencies[0]; + agency.matched_grants = [fixtures.grants.healthAide]; + const body = await email.buildDigestBody({ name: 'Saved search test', openDate: '2021-08-05', matchedGrants: agency.matched_grants }); + expect(body).to.include(`https://www.grants.gov/search-results-detail/${fixtures.grants.healthAide.grant_id}`); + }); + it('links to Grant Finder when Grant Details page is live', async () => { + process.env.NEW_GRANT_DETAILS_PAGE_ENABLED = 'true'; + const agencies = await db.getAgency(fixtures.agencies.accountancy.id); + const agency = agencies[0]; + agency.matched_grants = [fixtures.grants.healthAide]; + const body = await email.buildDigestBody({ name: 'Saved search test', openDate: '2021-08-05', matchedGrants: agency.matched_grants }); + expect(body).to.include(`${process.env.WEBSITE_DOMAIN}/grants/${fixtures.grants.healthAide.grant_id}`); + }); }); context('getAndSendGrantForSavedSearch', () => { it('Sends an email for a saved search', async () => { diff --git a/packages/server/src/lib/email.js b/packages/server/src/lib/email.js index d375af5fd..320611d3d 100644 --- a/packages/server/src/lib/email.js +++ b/packages/server/src/lib/email.js @@ -153,10 +153,17 @@ function sendWelcomeEmail(email, httpOrigin) { }); } -function getGrantDetail(grant, emailNotificationType) { - const grantDetailTemplate = fileSystem.readFileSync(path.join(__dirname, '../static/email_templates/_grant_detail.html')); +function buildGrantDetailUrlSafe(grantId, emailNotificationType) { + const grantDetailUrl = new URL(process.env.WEBSITE_DOMAIN); + grantDetailUrl.pathname = `grants/${mustache.escape(grantId)}`; + grantDetailUrl.searchParams.set('utm_source', 'usdr-grants'); + grantDetailUrl.searchParams.set('utm_medium', 'email'); + grantDetailUrl.searchParams.set('utm_campaign', mustache.escape(emailNotificationType)); + grantDetailUrl.searchParams.set('utm_content', 'grant-details'); + return grantDetailUrl.toString(); +} - const description = grant.description?.substring(0, 380).replace(/(<([^>]+)>)/ig, ''); +function buildGrantsUrlSafe(emailNotificationType) { const grantsUrl = new URL(process.env.WEBSITE_DOMAIN); if (emailNotificationType === notificationType.grantDigest) { grantsUrl.pathname = 'grants'; @@ -165,7 +172,13 @@ function getGrantDetail(grant, emailNotificationType) { } grantsUrl.searchParams.set('utm_source', 'subscription'); grantsUrl.searchParams.set('utm_medium', 'email'); - grantsUrl.searchParams.set('utm_campaign', emailNotificationType); + grantsUrl.searchParams.set('utm_campaign', mustache.escape(emailNotificationType)); + return grantsUrl.toString(); +} + +function getGrantDetail(grant, emailNotificationType) { + const grantDetailTemplate = fileSystem.readFileSync(path.join(__dirname, '../static/email_templates/_grant_detail.html')); + const description = grant.description?.substring(0, 380).replace(/(<([^>]+)>)/ig, ''); const grantDetail = mustache.render( grantDetailTemplate.toString(), { title: grant.title, @@ -178,8 +191,13 @@ function getGrantDetail(grant, emailNotificationType) { award_ceiling: grant.award_ceiling || 'Not available', // estimated_funding: grant.estimated_funding, TODO: add once field is available in the database. cost_sharing: grant.cost_sharing, - link_url: `https://www.grants.gov/search-results-detail/${grant.grant_id}`, - grants_url: grantsUrl.toString(), + link_url_safe: process.env.NEW_GRANT_DETAILS_PAGE_ENABLED === 'true' + ? buildGrantDetailUrlSafe(grant.grant_id, emailNotificationType) + : `https://www.grants.gov/search-results-detail/${mustache.escape(grant.grant_id)}`, + link_description: process.env.NEW_GRANT_DETAILS_PAGE_ENABLED === 'true' + ? 'Grant Finder' + : 'Grants.gov', + grants_url_safe: buildGrantsUrlSafe(emailNotificationType), view_grant_label: emailNotificationType === notificationType.grantDigest ? undefined : 'View My Grants', }, ); @@ -219,10 +237,10 @@ async function sendGrantAssignedNotficationForAgency(assignee_agency, grantDetai // TODO: add plain text version of the email const emailPlain = emailHTML.replace(/<[^>]+>/g, ''); const emailSubject = `Grant Assigned to ${assignee_agency.name}`; - const assginees = await db.getSubscribersForNotification(assignee_agency.id, notificationType.grantAssignment); + const assignees = await db.getSubscribersForNotification(assignee_agency.id, notificationType.grantAssignment); const inputs = []; - assginees.forEach((assignee) => inputs.push( + assignees.forEach((assignee) => inputs.push( { toAddress: assignee.email, emailHTML, diff --git a/packages/server/src/static/email_templates/_grant_detail.html b/packages/server/src/static/email_templates/_grant_detail.html index 7bc698c1d..82506e575 100644 --- a/packages/server/src/static/email_templates/_grant_detail.html +++ b/packages/server/src/static/email_templates/_grant_detail.html @@ -19,7 +19,7 @@ - +

{{title}}

@@ -31,7 +31,7 @@ style="Margin:0;padding-bottom:16px;">

- {{{description}}}... View on Grants.gov + {{{description}}}... View on {{ link_description }}

@@ -60,8 +60,8 @@ - {{view_grant_label}} diff --git a/terraform/main.tf b/terraform/main.tf index bb65fb73e..a8acedd4f 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -143,7 +143,7 @@ resource "aws_ecs_cluster" "default" { } resource "aws_ecs_cluster_capacity_providers" "default" { - count = length(aws_ecs_cluster.default.*) + count = length(aws_ecs_cluster.default[*]) cluster_name = aws_ecs_cluster.default[count.index].name capacity_providers = ["FARGATE"] @@ -166,8 +166,8 @@ module "api" { ] # Cluster - ecs_cluster_id = join("", aws_ecs_cluster.default.*.id) - ecs_cluster_name = join("", aws_ecs_cluster.default.*.name) + ecs_cluster_id = join("", aws_ecs_cluster.default[*].id) + ecs_cluster_name = join("", aws_ecs_cluster.default[*].name) # Task configuration docker_tag = var.api_container_image_tag @@ -219,7 +219,7 @@ module "consume_grants" { security_group_ids = [module.api_to_postgres_security_group.id] # Task configuration - ecs_cluster_name = join("", aws_ecs_cluster.default.*.name) + ecs_cluster_name = join("", aws_ecs_cluster.default[*].name) docker_tag = var.api_container_image_tag unified_service_tags = local.unified_service_tags datadog_environment_variables = var.consume_grants_datadog_environment_variables @@ -260,7 +260,7 @@ module "arpa_audit_report" { security_group_ids = [module.arpa_audit_report_security_group.id] # Task configuration - ecs_cluster_name = join("", aws_ecs_cluster.default.*.name) + ecs_cluster_name = join("", aws_ecs_cluster.default[*].name) docker_tag = var.api_container_image_tag unified_service_tags = local.unified_service_tags stop_timeout_seconds = 120 @@ -348,7 +348,7 @@ module "arpa_treasury_report" { security_group_ids = [module.arpa_treasury_report_security_group.id] # Task configuration - ecs_cluster_name = join("", aws_ecs_cluster.default.*.name) + ecs_cluster_name = join("", aws_ecs_cluster.default[*].name) docker_tag = var.api_container_image_tag unified_service_tags = local.unified_service_tags stop_timeout_seconds = 120 diff --git a/terraform/modules/gost_api/autoscaling.tf b/terraform/modules/gost_api/autoscaling.tf index d680f72aa..543e959c5 100644 --- a/terraform/modules/gost_api/autoscaling.tf +++ b/terraform/modules/gost_api/autoscaling.tf @@ -3,7 +3,7 @@ resource "aws_appautoscaling_target" "desired_count" { service_namespace = "ecs" scalable_dimension = "ecs:service:DesiredCount" - resource_id = "service/${var.ecs_cluster_name}/${join("", aws_ecs_service.default.*.name)}" + resource_id = "service/${var.ecs_cluster_name}/${join("", aws_ecs_service.default[*].name)}" min_capacity = var.autoscaling_desired_count_minimum max_capacity = var.autoscaling_desired_count_maximum @@ -14,9 +14,9 @@ resource "aws_appautoscaling_policy" "average_cpu_target_tracking" { name = "${var.namespace}-api-CPU-TargetTrackingScaling" policy_type = "TargetTrackingScaling" - service_namespace = join("", aws_appautoscaling_target.desired_count.*.service_namespace) - resource_id = join("", aws_appautoscaling_target.desired_count.*.resource_id) - scalable_dimension = join("", aws_appautoscaling_target.desired_count.*.scalable_dimension) + service_namespace = join("", aws_appautoscaling_target.desired_count[*].service_namespace) + resource_id = join("", aws_appautoscaling_target.desired_count[*].resource_id) + scalable_dimension = join("", aws_appautoscaling_target.desired_count[*].scalable_dimension) target_tracking_scaling_policy_configuration { predefined_metric_specification { diff --git a/terraform/modules/gost_api/ecs_exec.tf b/terraform/modules/gost_api/ecs_exec.tf index a0758324b..2edcde74a 100644 --- a/terraform/modules/gost_api/ecs_exec.tf +++ b/terraform/modules/gost_api/ecs_exec.tf @@ -29,7 +29,7 @@ module "ecs_exec_policy" { "logs:PutLogEvents", ] resources = [ - for arn in aws_cloudwatch_log_group.default.*.arn : "${arn}:log-stream:*" + for arn in aws_cloudwatch_log_group.default[*].arn : "${arn}:log-stream:*" ] } } diff --git a/terraform/modules/gost_api/gateway.tf b/terraform/modules/gost_api/gateway.tf index 7b8ffe282..a70678dc1 100644 --- a/terraform/modules/gost_api/gateway.tf +++ b/terraform/modules/gost_api/gateway.tf @@ -67,7 +67,7 @@ module "api_gateway" { max_age = 86400 // 24 hours, in seconds } - default_stage_access_log_destination_arn = join("", aws_cloudwatch_log_group.default.*.arn) + default_stage_access_log_destination_arn = join("", aws_cloudwatch_log_group.default[*].arn) default_stage_access_log_format = jsonencode({ requestId = "$context.requestId" ip = "$context.identity.sourceIp" @@ -93,7 +93,7 @@ module "api_gateway" { "$default" = { connection_type = "VPC_LINK" vpc_link = "api-service" - integration_uri = join("", aws_service_discovery_service.default.*.arn) + integration_uri = join("", aws_service_discovery_service.default[*].arn) integration_type = "HTTP_PROXY" integration_method = "ANY" } diff --git a/terraform/modules/gost_api/logs.tf b/terraform/modules/gost_api/logs.tf index a7756cfea..b4bd09250 100644 --- a/terraform/modules/gost_api/logs.tf +++ b/terraform/modules/gost_api/logs.tf @@ -21,7 +21,7 @@ module "write_api_logs_policy" { "logs:PutLogEvents", ] resources = flatten([ - for arn in aws_cloudwatch_log_group.default.*.arn : + for arn in aws_cloudwatch_log_group.default[*].arn : [ arn, "${arn}:log-stream:*" diff --git a/terraform/modules/gost_api/main.tf b/terraform/modules/gost_api/main.tf index f68a2c3f2..92e83a11a 100644 --- a/terraform/modules/gost_api/main.tf +++ b/terraform/modules/gost_api/main.tf @@ -1,7 +1,21 @@ data "aws_region" "current" {} -data "aws_partition" "current" {} data "aws_caller_identity" "current" {} +terraform { + required_version = "1.3.6" + + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 4.67.0" + } + random = { + source = "hashicorp/random" + version = "~> 3.6.0" + } + } +} + module "this" { source = "cloudposse/label/null" version = "0.25.0" diff --git a/terraform/modules/gost_api/outputs.tf b/terraform/modules/gost_api/outputs.tf index 1ec9f1772..7f2777286 100644 --- a/terraform/modules/gost_api/outputs.tf +++ b/terraform/modules/gost_api/outputs.tf @@ -9,7 +9,7 @@ output "base_url_alias" { Note that externally-managed DNS authorities may not always point this URL to the base_url; use base_url if you need to ensure that requests target this particular deployment. EOF - value = var.enabled ? "https://${join("", aws_route53_record.alias.*.fqdn)}" : null + value = var.enabled ? "https://${join("", aws_route53_record.alias[*].fqdn)}" : null } output "ecs_cluster_name" { @@ -17,15 +17,15 @@ output "ecs_cluster_name" { } output "ecs_service_name" { - value = join("", aws_ecs_service.default.*.name) + value = join("", aws_ecs_service.default[*].name) } output "ecs_service_arn" { - value = join("", aws_ecs_service.default.*.id) + value = join("", aws_ecs_service.default[*].id) } output "ecs_task_role_name" { - value = join("", aws_iam_role.task.*.name) + value = join("", aws_iam_role.task[*].name) } output "arpa_audit_reports_bucket_id" { diff --git a/terraform/modules/gost_api/scraper.tf b/terraform/modules/gost_api/scraper.tf index 96a73c915..f40f37e04 100644 --- a/terraform/modules/gost_api/scraper.tf +++ b/terraform/modules/gost_api/scraper.tf @@ -19,13 +19,13 @@ module "grants_scraper" { retry_policy_max_event_age = { hours = 4 } // Permissions - task_role_arn = join("", aws_ecs_task_definition.default.*.task_role_arn) - task_execution_role_arn = join("", aws_ecs_task_definition.default.*.execution_role_arn) + task_role_arn = join("", aws_ecs_task_definition.default[*].task_role_arn) + task_execution_role_arn = join("", aws_ecs_task_definition.default[*].execution_role_arn) permissions_boundary_arn = var.permissions_boundary_arn // Task settings - cluster_arn = join("", data.aws_ecs_cluster.default.*.arn) - task_definition_arn = join("", aws_ecs_task_definition.default.*.arn) + cluster_arn = join("", data.aws_ecs_cluster.default[*].arn) + task_definition_arn = join("", aws_ecs_task_definition.default[*].arn) task_revision = "LATEST" launch_type = "FARGATE" enable_ecs_managed_tags = true diff --git a/terraform/modules/gost_api/secrets.tf b/terraform/modules/gost_api/secrets.tf index 6c910e248..2f8ea7866 100644 --- a/terraform/modules/gost_api/secrets.tf +++ b/terraform/modules/gost_api/secrets.tf @@ -65,9 +65,9 @@ module "decrypt_secrets_policy" { "secretsmanager:GetSecretValue", ] resources = compact([ - join("", data.aws_ssm_parameter.datadog_api_key.*.arn), - join("", aws_ssm_parameter.postgres_connection_string.*.arn), - join("", aws_ssm_parameter.cookie_secret.*.arn), + join("", data.aws_ssm_parameter.datadog_api_key[*].arn), + join("", aws_ssm_parameter.postgres_connection_string[*].arn), + join("", aws_ssm_parameter.cookie_secret[*].arn), ]) } } diff --git a/terraform/modules/gost_api/service.tf b/terraform/modules/gost_api/service.tf index c08101282..086e924ed 100644 --- a/terraform/modules/gost_api/service.tf +++ b/terraform/modules/gost_api/service.tf @@ -12,7 +12,7 @@ resource "aws_service_discovery_service" "default" { name = "${var.namespace}-api" dns_config { - namespace_id = join("", aws_service_discovery_private_dns_namespace.default.*.id) + namespace_id = join("", aws_service_discovery_private_dns_namespace.default[*].id) dns_records { type = "SRV" @@ -30,7 +30,7 @@ resource "aws_ecs_service" "default" { name = "${var.namespace}-api" cluster = var.ecs_cluster_id - task_definition = join("", aws_ecs_task_definition.default.*.arn) + task_definition = join("", aws_ecs_task_definition.default[*].arn) desired_count = var.default_desired_task_count launch_type = "FARGATE" enable_execute_command = true @@ -42,7 +42,7 @@ resource "aws_ecs_service" "default" { } service_registries { - registry_arn = join("", aws_service_discovery_service.default.*.arn) + registry_arn = join("", aws_service_discovery_service.default[*].arn) port = local.api_container_port } diff --git a/terraform/modules/gost_api/storage.tf b/terraform/modules/gost_api/storage.tf index cc590fa91..2d1c1573e 100644 --- a/terraform/modules/gost_api/storage.tf +++ b/terraform/modules/gost_api/storage.tf @@ -1,6 +1,6 @@ module "efs_data_volume" { source = "cloudposse/efs/aws" - version = "0.35.0" + version = "1.1.0" context = module.this.context name = "${var.namespace}-data_volume" diff --git a/terraform/modules/gost_api/task.tf b/terraform/modules/gost_api/task.tf index c7f90dea8..c7748e499 100644 --- a/terraform/modules/gost_api/task.tf +++ b/terraform/modules/gost_api/task.tf @@ -65,8 +65,8 @@ module "api_container_definition" { ) map_secrets = { - COOKIE_SECRET = join("", aws_ssm_parameter.cookie_secret.*.arn) - POSTGRES_URL = join("", aws_ssm_parameter.postgres_connection_string.*.arn) + COOKIE_SECRET = join("", aws_ssm_parameter.cookie_secret[*].arn) + POSTGRES_URL = join("", aws_ssm_parameter.postgres_connection_string[*].arn) } docker_labels = local.datadog_docker_labels @@ -88,7 +88,7 @@ module "api_container_definition" { log_configuration = { logDriver = "awslogs" options = { - awslogs-group = join("", aws_cloudwatch_log_group.default.*.name) + awslogs-group = join("", aws_cloudwatch_log_group.default[*].name) awslogs-region = data.aws_region.current.name awslogs-stream-prefix = "ecs" } @@ -113,7 +113,7 @@ module "datadog_container_definition" { local.datadog_env_vars, ) map_secrets = { - DD_API_KEY = join("", data.aws_ssm_parameter.datadog_api_key.*.arn), + DD_API_KEY = join("", data.aws_ssm_parameter.datadog_api_key[*].arn), } docker_labels = local.datadog_docker_labels } @@ -144,7 +144,7 @@ resource "aws_iam_role_policy" "execution" { } name = each.key - role = join("", aws_iam_role.execution.*.name) + role = join("", aws_iam_role.execution[*].name) policy = each.value } @@ -152,8 +152,8 @@ resource "aws_ecs_task_definition" "default" { count = var.enabled ? 1 : 0 family = "${var.namespace}-api" - execution_role_arn = join("", aws_iam_role.execution.*.arn) - task_role_arn = join("", aws_iam_role.task.*.arn) + execution_role_arn = join("", aws_iam_role.execution[*].arn) + task_role_arn = join("", aws_iam_role.task[*].arn) network_mode = "awsvpc" requires_compatibilities = ["FARGATE"] @@ -224,6 +224,6 @@ resource "aws_iam_role_policy" "task" { } name = each.key - role = join("", aws_iam_role.task.*.name) + role = join("", aws_iam_role.task[*].name) policy = each.value } diff --git a/terraform/modules/gost_consume_grants/main.tf b/terraform/modules/gost_consume_grants/main.tf index b85fd937e..753e1584b 100644 --- a/terraform/modules/gost_consume_grants/main.tf +++ b/terraform/modules/gost_consume_grants/main.tf @@ -1,10 +1,14 @@ data "aws_region" "current" {} -data "aws_partition" "current" {} data "aws_caller_identity" "current" {} terraform { + required_version = "1.3.6" + required_providers { - aws = "~> 4.67.0" + aws = { + source = "hashicorp/aws" + version = "~> 4.67.0" + } } } diff --git a/terraform/modules/gost_networking/main.tf b/terraform/modules/gost_networking/main.tf index 1cf04408b..cee4dc815 100644 --- a/terraform/modules/gost_networking/main.tf +++ b/terraform/modules/gost_networking/main.tf @@ -1,7 +1,10 @@ terraform { + required_version = "1.3.6" + required_providers { aws = { - source = "hashicorp/aws" + source = "hashicorp/aws" + version = "~> 4.67.0" } } } diff --git a/terraform/modules/gost_postgres/main.tf b/terraform/modules/gost_postgres/main.tf index c5213ebe1..8fc65842e 100644 --- a/terraform/modules/gost_postgres/main.tf +++ b/terraform/modules/gost_postgres/main.tf @@ -7,6 +7,21 @@ data "aws_rds_engine_version" "postgres13_8" { version = "13.8" } +terraform { + required_version = "1.3.6" + + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 4.67.0" + } + random = { + source = "hashicorp/random" + version = "~> 3.6.0" + } + } +} + resource "aws_db_parameter_group" "postgres13" { name = "${var.namespace}-aurora-postgres13-db" family = "aurora-postgresql13" diff --git a/terraform/modules/gost_website/cdn.tf b/terraform/modules/gost_website/cdn.tf index 91ddf6328..8f874254e 100644 --- a/terraform/modules/gost_website/cdn.tf +++ b/terraform/modules/gost_website/cdn.tf @@ -90,7 +90,7 @@ module "cdn" { function_association = { viewer-request = { - function_arn = join("", aws_cloudfront_function.arpa_reporter_uri_rewriter.*.arn) + function_arn = join("", aws_cloudfront_function.arpa_reporter_uri_rewriter[*].arn) } } } diff --git a/terraform/modules/gost_website/main.tf b/terraform/modules/gost_website/main.tf index b2c88bc04..2761b5d00 100644 --- a/terraform/modules/gost_website/main.tf +++ b/terraform/modules/gost_website/main.tf @@ -1,7 +1,17 @@ data "aws_region" "current" {} -data "aws_partition" "current" {} data "aws_caller_identity" "current" {} +terraform { + required_version = "1.3.6" + + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 4.67.0" + } + } +} + provider "aws" { region = "us-east-1" alias = "us-east-1" diff --git a/terraform/modules/gost_website/storage.tf b/terraform/modules/gost_website/storage.tf index 618955d7d..e580523d4 100644 --- a/terraform/modules/gost_website/storage.tf +++ b/terraform/modules/gost_website/storage.tf @@ -11,19 +11,6 @@ module "s3_label" { } locals { - sync_website_to_origin_bucket_policy = { - actions = [ - "s3:DeleteObject", - "s3:GetBucketLocation", - "s3:GetObject", - "s3:ListBucket", - "s3:PutObject", - ] - resources = [ - - "${module.origin_bucket.bucket_arn}${var.origin_bucket_dist_path}/*", - ] - } } module "cloudfront_to_origin_bucket_access_policy" { diff --git a/terraform/modules/gost_website/variables.tf b/terraform/modules/gost_website/variables.tf index bee1b7c7e..8ff4bbc2e 100644 --- a/terraform/modules/gost_website/variables.tf +++ b/terraform/modules/gost_website/variables.tf @@ -14,6 +14,9 @@ variable "tags" { default = {} } +# We include this variable in all packages as convention to help enforce our permissions boundaries. +# If this module ever needs to create an IAM role, it should utilize this, and we can remove the tflint ignore. +# tflint-ignore: terraform_unused_declarations variable "permissions_boundary_arn" { description = "ARN of the managed policy to set as the permissions boundary for all roles." type = string @@ -103,6 +106,7 @@ variable "managed_waf_rules" { variable "origin_bucket_dist_path" { description = "Path to the directory where website build files should be stored in the S3 origin bucket." + type = string default = "/dist" validation { condition = startswith(var.origin_bucket_dist_path, "/") @@ -121,6 +125,7 @@ variable "origin_artifacts_dist_path" { variable "origin_bucket_config_path" { description = "Path to the directory where non-build configuration files should be stored in the S3 origin bucket." + type = string default = "/config" validation { condition = startswith(var.origin_bucket_config_path, "/") @@ -134,6 +139,7 @@ variable "origin_bucket_config_path" { variable "origin_config_filename" { description = "Filename (relative to origin_bucket_config_path) from which the website loads non-build, deployment configuration directives." + type = string default = "deploy-config.js" validation { condition = endswith(var.origin_config_filename, ".js") diff --git a/terraform/modules/scheduled_ecs_task/main.tf b/terraform/modules/scheduled_ecs_task/main.tf index dd0493786..86040af1c 100644 --- a/terraform/modules/scheduled_ecs_task/main.tf +++ b/terraform/modules/scheduled_ecs_task/main.tf @@ -1,5 +1,16 @@ data "aws_caller_identity" "current" { count = var.enabled ? 1 : 0 } +terraform { + required_version = "1.3.6" + + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 4.67.0" + } + } +} + locals { create_role = var.enabled && var.role_arn == null @@ -50,7 +61,7 @@ data "aws_iam_policy_document" "trust" { condition { test = "StringEquals" variable = "aws:SourceAccount" - values = data.aws_caller_identity.current.*.account_id + values = data.aws_caller_identity.current[*].account_id } } } @@ -118,7 +129,7 @@ resource "aws_scheduler_schedule" "default" { target { arn = var.cluster_arn - role_arn = coalesce(var.role_arn, join("", aws_iam_role.default.*.arn)) + role_arn = coalesce(var.role_arn, join("", aws_iam_role.default[*].arn)) input = var.task_override diff --git a/terraform/modules/scheduled_ecs_task/outputs.tf b/terraform/modules/scheduled_ecs_task/outputs.tf index d5be198af..81cac742a 100644 --- a/terraform/modules/scheduled_ecs_task/outputs.tf +++ b/terraform/modules/scheduled_ecs_task/outputs.tf @@ -1,23 +1,23 @@ output "role_arn" { - value = join("", aws_iam_role.default.*.arn) + value = join("", aws_iam_role.default[*].arn) } output "role_name" { - value = join("", aws_iam_role.default.*.id) + value = join("", aws_iam_role.default[*].id) } output "schedule_arn" { - value = join("", aws_scheduler_schedule.default.*.arn) + value = join("", aws_scheduler_schedule.default[*].arn) } output "schedule_name" { - value = join("", aws_scheduler_schedule.default.*.id) + value = join("", aws_scheduler_schedule.default[*].id) } output "trust_policy_json" { - value = join("", data.aws_iam_policy_document.trust.*.json) + value = join("", data.aws_iam_policy_document.trust[*].json) } output "permissions_policy_json" { - value = join("", data.aws_iam_policy_document.permissions.*.json) + value = join("", data.aws_iam_policy_document.permissions[*].json) } diff --git a/terraform/modules/scheduled_ecs_task/variables.tf b/terraform/modules/scheduled_ecs_task/variables.tf index c70388d52..8170cf261 100644 --- a/terraform/modules/scheduled_ecs_task/variables.tf +++ b/terraform/modules/scheduled_ecs_task/variables.tf @@ -254,8 +254,3 @@ variable "retry_policy_max_attempts" { default = null } -variable "kms_key_arn" { - description = "ARN for the customer-managed KMS key that EventBridge Scheduler will use to encrypt/decrypt your data." - type = string - default = null -} diff --git a/terraform/modules/sqs_consumer_task/compute.tf b/terraform/modules/sqs_consumer_task/compute.tf index 7ff2b3622..bb5254bb3 100644 --- a/terraform/modules/sqs_consumer_task/compute.tf +++ b/terraform/modules/sqs_consumer_task/compute.tf @@ -69,7 +69,7 @@ module "consumer_container_definition" { }, local.datadog_env_vars, var.consumer_container_environment, - { "${var.queue_url_environment_variable_name}" = module.sqs_queue.queue_url }, + { (var.queue_url_environment_variable_name) = module.sqs_queue.queue_url }, ) docker_labels = local.datadog_docker_labels diff --git a/terraform/modules/sqs_consumer_task/main.tf b/terraform/modules/sqs_consumer_task/main.tf index 22ab07d89..76cdc5c47 100644 --- a/terraform/modules/sqs_consumer_task/main.tf +++ b/terraform/modules/sqs_consumer_task/main.tf @@ -1,10 +1,14 @@ data "aws_region" "current" {} -data "aws_partition" "current" {} data "aws_caller_identity" "current" {} terraform { + required_version = "1.3.6" + required_providers { - aws = "~> 4.67.0" + aws = { + source = "hashicorp/aws" + version = "~> 4.67.0" + } } } diff --git a/terraform/prod.tfvars b/terraform/prod.tfvars index ce5832bbb..31c2f40ab 100644 --- a/terraform/prod.tfvars +++ b/terraform/prod.tfvars @@ -72,6 +72,9 @@ api_log_retention_in_days = 30 api_datadog_environment_variables = { DD_PROFILING_ENABLED = true, } +api_container_environment = { + NEW_GRANT_DETAILS_PAGE_ENABLED = false, +} // Postgres postgres_enabled = true diff --git a/terraform/staging.tfvars b/terraform/staging.tfvars index 79095a43d..5498752f9 100644 --- a/terraform/staging.tfvars +++ b/terraform/staging.tfvars @@ -69,6 +69,9 @@ api_log_retention_in_days = 14 api_datadog_environment_variables = { DD_PROFILING_ENABLED = true, } +api_container_environment = { + NEW_GRANT_DETAILS_PAGE_ENABLED = true, +} // Postgres postgres_enabled = true diff --git a/terraform/variables.tf b/terraform/variables.tf index 65263417e..fa5faf10c 100644 --- a/terraform/variables.tf +++ b/terraform/variables.tf @@ -48,17 +48,6 @@ variable "datadog_draft" { default = true } -variable "datadog_metrics_metadata" { - description = "Map of metadata describing custom Datadog metrics, keyed by the metric name. All metrics are automatically prefixed with grants_ingest." - type = map(object({ - short_name = optional(string) - description = optional(string) - unit = optional(string) # https://docs.datadoghq.com/metrics/units/ - per_unit = optional(string) - })) - default = {} -} - // Common variable "permissions_boundary_policy_name" { description = "Name of the permissions boundary for service roles" @@ -227,18 +216,23 @@ variable "api_maximum_task_count" { // Postgres variable "postgres_enabled" { + type = bool default = true } variable "postgres_prevent_destroy" { + type = bool default = true } variable "postgres_snapshot_before_destroy" { + type = bool default = true } variable "postgres_apply_changes_immediately" { + type = bool default = false } variable "postgres_query_logging_enabled" { + type = bool default = false } diff --git a/usdr-gost.code-workspace b/usdr-gost.code-workspace index 7532fbbd1..afa1cfefa 100644 --- a/usdr-gost.code-workspace +++ b/usdr-gost.code-workspace @@ -18,12 +18,14 @@ "diffEditor.ignoreTrimWhitespace": false, "editor.columnSelection": false, "editor.find.cursorMoveOnType": true, - "eslint.debug":true, "javascript.format.enable": false, - "editor.formatOnSaveMode": "modifications", - "eslint.alwaysShowStatus": true, "editor.codeActionsOnSave": { - "source.fixAll.eslint": true + "source.fixAll.eslint": "explicit" }, + // We need to explicitly turn this off at the worksplace level to avoid + // competing user settings and workplace settings. We use VSCode's "codeActionsOnSave" + // to manage linting/fixing, but users can have other settings via "formatOnSave". + // If both are on, the editor can "fix" things that are immediately flagged as lint failures. + "editor.formatOnSave": false, } } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 61a1a97e1..9603a14ca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -221,16 +221,16 @@ "@aws-sdk/util-utf8-browser" "^3.0.0" tslib "^1.11.1" -"@aws-sdk/client-cognito-identity@3.525.0": - version "3.525.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.525.0.tgz#ff9fa4a6b71cac23a632f8fa31cb865cf068fa8a" - integrity sha512-LxI9rfn6Vy/EX6I7as14PAKqAhUwVQviaMV/xCLQIubgdVj1xfexVURdiSk7GQshpcwtrs+GQWV21yP+3AX/7A== +"@aws-sdk/client-cognito-identity@3.529.1": + version "3.529.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.529.1.tgz#09aaab807ded1b29414aee4e745e0f4a5819a695" + integrity sha512-ebdEdtHrzP/xnLkVq2ei3e5jkfm2YBmdePIWy6Jb8P1nLYgZsKmprqTxHrW1oM7YcIpqMsBao2r1AJf+orEy0A== dependencies: "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" - "@aws-sdk/client-sts" "3.525.0" - "@aws-sdk/core" "3.525.0" - "@aws-sdk/credential-provider-node" "3.525.0" + "@aws-sdk/client-sts" "3.529.1" + "@aws-sdk/core" "3.529.1" + "@aws-sdk/credential-provider-node" "3.529.1" "@aws-sdk/middleware-host-header" "3.523.0" "@aws-sdk/middleware-logger" "3.523.0" "@aws-sdk/middleware-recursion-detection" "3.523.0" @@ -268,16 +268,16 @@ tslib "^2.5.0" "@aws-sdk/client-s3@^3.312.0": - version "3.525.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-s3/-/client-s3-3.525.0.tgz#965ed5b70c067d74c7a3c4aea26dfce53db4cd06" - integrity sha512-hoMGH8G9rezZDiJPsMjsyRVNfVHHa4u6lcZ09SQMmtFHWK0FUcC0DIKR5ripV5qGDbnV54i2JotXlLzAv0aNCQ== + version "3.529.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-s3/-/client-s3-3.529.1.tgz#12be8ac86cd4676790957745b20bef9eb2c14247" + integrity sha512-ZpvyO4w3XWo/OjXLd3fm7CLcKUUYcyady9qzTnKKSnp8a2NqO7UvU/1zhYdm+yyy8TR/9t7sDy+q6AYd4Nsr8g== dependencies: "@aws-crypto/sha1-browser" "3.0.0" "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" - "@aws-sdk/client-sts" "3.525.0" - "@aws-sdk/core" "3.525.0" - "@aws-sdk/credential-provider-node" "3.525.0" + "@aws-sdk/client-sts" "3.529.1" + "@aws-sdk/core" "3.529.1" + "@aws-sdk/credential-provider-node" "3.529.1" "@aws-sdk/middleware-bucket-endpoint" "3.525.0" "@aws-sdk/middleware-expect-continue" "3.523.0" "@aws-sdk/middleware-flexible-checksums" "3.523.0" @@ -328,19 +328,18 @@ "@smithy/util-stream" "^2.1.3" "@smithy/util-utf8" "^2.1.1" "@smithy/util-waiter" "^2.1.3" - fast-xml-parser "4.2.5" tslib "^2.5.0" "@aws-sdk/client-ses@^3.312.0": - version "3.525.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-ses/-/client-ses-3.525.0.tgz#ffb4c21a82e07f36d7dc24c2203d7e18bde6f9f7" - integrity sha512-wvsj/NiEyweJYns14RDwg4UCbCAba4rYgW9ESpCVZ3cx+deUqNUbfU+YcYrfZNcqApq42LPcSubU1Ynh/QHEsg== + version "3.529.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-ses/-/client-ses-3.529.1.tgz#b9cbf444995e5e2d024e0e95c834b6d77c17ca5c" + integrity sha512-YWB45PyXnbWy9m02wcKpxDuaynr1LHGCkBaJe4Oaxk9b2xbAZMo6CTWalOCw1JunQDKZUDJ0I3shuBLE24b3xA== dependencies: "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" - "@aws-sdk/client-sts" "3.525.0" - "@aws-sdk/core" "3.525.0" - "@aws-sdk/credential-provider-node" "3.525.0" + "@aws-sdk/client-sts" "3.529.1" + "@aws-sdk/core" "3.529.1" + "@aws-sdk/credential-provider-node" "3.529.1" "@aws-sdk/middleware-host-header" "3.523.0" "@aws-sdk/middleware-logger" "3.523.0" "@aws-sdk/middleware-recursion-detection" "3.523.0" @@ -376,19 +375,18 @@ "@smithy/util-retry" "^2.1.3" "@smithy/util-utf8" "^2.1.1" "@smithy/util-waiter" "^2.1.3" - fast-xml-parser "4.2.5" tslib "^2.5.0" "@aws-sdk/client-sqs@^3.345.0": - version "3.525.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-sqs/-/client-sqs-3.525.0.tgz#28e81bc637f53e8c2694487fdaa3b8bd749fcea1" - integrity sha512-a38nL1/jnPzUkAvYMSPKJFfJFppGs6aaxUXIuYYEDns6DvIrnXNKljAA8FBrCqWZ8D5SScB2sit3nRYhGN2b4A== + version "3.529.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sqs/-/client-sqs-3.529.1.tgz#f3e74d256107b8ce2981ce6c049d68a94bc04dff" + integrity sha512-TBQWhf/9tWw5b6xZ0l9TtQUyB8WVIOmS4t6enr6zWsf/MJ9rjEcGJh6gyoF71URL2Bv5/x7qzLVPzxT/NRE+Ag== dependencies: "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" - "@aws-sdk/client-sts" "3.525.0" - "@aws-sdk/core" "3.525.0" - "@aws-sdk/credential-provider-node" "3.525.0" + "@aws-sdk/client-sts" "3.529.1" + "@aws-sdk/core" "3.529.1" + "@aws-sdk/credential-provider-node" "3.529.1" "@aws-sdk/middleware-host-header" "3.523.0" "@aws-sdk/middleware-logger" "3.523.0" "@aws-sdk/middleware-recursion-detection" "3.523.0" @@ -427,15 +425,15 @@ "@smithy/util-utf8" "^2.1.1" tslib "^2.5.0" -"@aws-sdk/client-sso-oidc@3.525.0": - version "3.525.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.525.0.tgz#0f80242d997adc7cf259f50f9e590d515a123fac" - integrity sha512-zz13k/6RkjPSLmReSeGxd8wzGiiZa4Odr2Tv3wTcxClM4wOjD+zOgGv4Fe32b9AMqaueiCdjbvdu7AKcYxFA4A== +"@aws-sdk/client-sso-oidc@3.529.1": + version "3.529.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.529.1.tgz#40440af993f0d2c1d7fdc3ef5840867a223e773b" + integrity sha512-bimxCWAvRnVcluWEQeadXvHyzWlBWsuGVligsaVZaGF0TLSn0eLpzpN9B1EhHzTf7m0Kh/wGtPSH1JxO6PpB+A== dependencies: "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" - "@aws-sdk/client-sts" "3.525.0" - "@aws-sdk/core" "3.525.0" + "@aws-sdk/client-sts" "3.529.1" + "@aws-sdk/core" "3.529.1" "@aws-sdk/middleware-host-header" "3.523.0" "@aws-sdk/middleware-logger" "3.523.0" "@aws-sdk/middleware-recursion-detection" "3.523.0" @@ -472,14 +470,14 @@ "@smithy/util-utf8" "^2.1.1" tslib "^2.5.0" -"@aws-sdk/client-sso@3.525.0": - version "3.525.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso/-/client-sso-3.525.0.tgz#2af5028a56a72a8067cb6b149ca1cc433beb9fa4" - integrity sha512-6KwGQWFoNLH1UupdWPFdKPfTgjSz1kN8/r8aCzuvvXBe4Pz+iDUZ6FEJzGWNc9AapjvZDNO1hs23slomM9rTaA== +"@aws-sdk/client-sso@3.529.1": + version "3.529.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso/-/client-sso-3.529.1.tgz#012a4c1861d586c2a96bef5e442bd505bdf3ca5f" + integrity sha512-KT1U/ZNjDhVv2ZgjzaeAn9VM7l667yeSguMrRYC8qk5h91/61MbjZypi6eOuKuVM+0fsQvzKScTQz0Lio0eYag== dependencies: "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" - "@aws-sdk/core" "3.525.0" + "@aws-sdk/core" "3.529.1" "@aws-sdk/middleware-host-header" "3.523.0" "@aws-sdk/middleware-logger" "3.523.0" "@aws-sdk/middleware-recursion-detection" "3.523.0" @@ -516,14 +514,14 @@ "@smithy/util-utf8" "^2.1.1" tslib "^2.5.0" -"@aws-sdk/client-sts@3.525.0": - version "3.525.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-sts/-/client-sts-3.525.0.tgz#5c59c39950f24d9fb4a42b226ada6a72955c0672" - integrity sha512-a8NUGRvO6rkfTZCbMaCsjDjLbERCwIUU9dIywFYcRgbFhkupJ7fSaZz3Het98U51M9ZbTEpaTa3fz0HaJv8VJw== +"@aws-sdk/client-sts@3.529.1": + version "3.529.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sts/-/client-sts-3.529.1.tgz#ad57e10868f5a89557dada02d2f951989e277ec6" + integrity sha512-Rvk2Sr3MACQTOtngUU+omlf4E17k47dRVXR7OFRD6Ow5iGgC9tkN2q/ExDPW/ktPOmM0lSgzWyQ6/PC/Zq3HUg== dependencies: "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" - "@aws-sdk/core" "3.525.0" + "@aws-sdk/core" "3.529.1" "@aws-sdk/middleware-host-header" "3.523.0" "@aws-sdk/middleware-logger" "3.523.0" "@aws-sdk/middleware-recursion-detection" "3.523.0" @@ -558,27 +556,27 @@ "@smithy/util-middleware" "^2.1.3" "@smithy/util-retry" "^2.1.3" "@smithy/util-utf8" "^2.1.1" - fast-xml-parser "4.2.5" tslib "^2.5.0" -"@aws-sdk/core@3.525.0": - version "3.525.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/core/-/core-3.525.0.tgz#710740ff96551e04f595fc156a40b54793a37b01" - integrity sha512-E3LtEtMWCriQOFZpVKpLYzbdw/v2PAOEAMhn2VRRZ1g0/g1TXzQrfhEU2yd8l/vQEJaCJ82ooGGg7YECviBUxA== +"@aws-sdk/core@3.529.1": + version "3.529.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/core/-/core-3.529.1.tgz#378bf215f3bf407158b4743e4d94bed4fa2e2594" + integrity sha512-Sj42sYPfaL9PHvvciMICxhyrDZjqnnvFbPKDmQL5aFKyXy122qx7RdVqUOQERDmMQfvJh6+0W1zQlLnre89q4Q== dependencies: "@smithy/core" "^1.3.5" "@smithy/protocol-http" "^3.2.1" "@smithy/signature-v4" "^2.1.3" "@smithy/smithy-client" "^2.4.2" "@smithy/types" "^2.10.1" + fast-xml-parser "4.2.5" tslib "^2.5.0" -"@aws-sdk/credential-provider-cognito-identity@3.525.0": - version "3.525.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.525.0.tgz#21bbc150e2fc7171ba245b922fc033eadb50de93" - integrity sha512-0djjCN/zN6QFQt1xU64VBOSRP4wJckU6U7FjLPrGpL6w03hF0dUmVUXjhQZe5WKNPCicVc2S3BYPohl/PzCx1w== +"@aws-sdk/credential-provider-cognito-identity@3.529.1": + version "3.529.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.529.1.tgz#224544fe8f1afcccfc34766167617554311d3acf" + integrity sha512-5cF7lPjkMQzTO/FFB1D7W8B661Jr+njjRkJMzNkD9+KdgNIihlLQT4wd3cVWsHZLAfSByzPMk2kUiUeYDeiJbw== dependencies: - "@aws-sdk/client-cognito-identity" "3.525.0" + "@aws-sdk/client-cognito-identity" "3.529.1" "@aws-sdk/types" "3.523.0" "@smithy/property-provider" "^2.1.3" "@smithy/types" "^2.10.1" @@ -609,16 +607,16 @@ "@smithy/util-stream" "^2.1.3" tslib "^2.5.0" -"@aws-sdk/credential-provider-ini@3.525.0": - version "3.525.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.525.0.tgz#e672842bfdc3bcde221def0284f4a8af30bee2bb" - integrity sha512-JDnccfK5JRb9jcgpc9lirL9PyCwGIqY0nKdw3LlX5WL5vTpTG4E1q7rLAlpNh7/tFD1n66Itarfv2tsyHMIqCw== +"@aws-sdk/credential-provider-ini@3.529.1": + version "3.529.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.529.1.tgz#b2ca21746585079ab9cc0e7d212417ee92cc83e2" + integrity sha512-RjHsuTvHIwXG7a/3ERexemiD3c9riKMCZQzY2/b0Gg0ButEVbBcMfERtUzWmQ0V4ufe/PEZjP68MH1gupcoF9A== dependencies: - "@aws-sdk/client-sts" "3.525.0" + "@aws-sdk/client-sts" "3.529.1" "@aws-sdk/credential-provider-env" "3.523.0" "@aws-sdk/credential-provider-process" "3.523.0" - "@aws-sdk/credential-provider-sso" "3.525.0" - "@aws-sdk/credential-provider-web-identity" "3.525.0" + "@aws-sdk/credential-provider-sso" "3.529.1" + "@aws-sdk/credential-provider-web-identity" "3.529.1" "@aws-sdk/types" "3.523.0" "@smithy/credential-provider-imds" "^2.2.3" "@smithy/property-provider" "^2.1.3" @@ -626,17 +624,17 @@ "@smithy/types" "^2.10.1" tslib "^2.5.0" -"@aws-sdk/credential-provider-node@3.525.0": - version "3.525.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.525.0.tgz#fde02124df4f8afd4a58475452c9cd7f91a60b01" - integrity sha512-RJXlO8goGXpnoHQAyrCcJ0QtWEOFa34LSbfdqBIjQX/fwnjUuEmiGdXTV3AZmwYQ7juk49tfBneHbtOP3AGqsQ== +"@aws-sdk/credential-provider-node@3.529.1": + version "3.529.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.529.1.tgz#4c53c47320cf440be55786287a7d33b7364d2316" + integrity sha512-mvY7F3dMmk/0dZOCfl5sUI1bG0osureBjxhELGCF0KkJqhWI0hIzh8UnPkYytSg3vdc97CMv7pTcozxrdA3b0g== dependencies: "@aws-sdk/credential-provider-env" "3.523.0" "@aws-sdk/credential-provider-http" "3.525.0" - "@aws-sdk/credential-provider-ini" "3.525.0" + "@aws-sdk/credential-provider-ini" "3.529.1" "@aws-sdk/credential-provider-process" "3.523.0" - "@aws-sdk/credential-provider-sso" "3.525.0" - "@aws-sdk/credential-provider-web-identity" "3.525.0" + "@aws-sdk/credential-provider-sso" "3.529.1" + "@aws-sdk/credential-provider-web-identity" "3.529.1" "@aws-sdk/types" "3.523.0" "@smithy/credential-provider-imds" "^2.2.3" "@smithy/property-provider" "^2.1.3" @@ -655,46 +653,46 @@ "@smithy/types" "^2.10.1" tslib "^2.5.0" -"@aws-sdk/credential-provider-sso@3.525.0": - version "3.525.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.525.0.tgz#b79f263fcde291250b35af41ee83743bdfec7d13" - integrity sha512-7V7ybtufxdD3plxeIeB6aqHZeFIUlAyPphXIUgXrGY10iNcosL970rQPBeggsohe4gCM6UvY2TfMeEcr+ZE8FA== +"@aws-sdk/credential-provider-sso@3.529.1": + version "3.529.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.529.1.tgz#ee685cfbb87d2aa138d46d6c115adac850e78ba7" + integrity sha512-KFMKkaoTGDgSJG+o9Ii7AglWG5JQeF6IFw9cXLMwDdIrp3KUmRcUIqe0cjOoCqeQEDGy0VHsimHmKKJ3894i/A== dependencies: - "@aws-sdk/client-sso" "3.525.0" - "@aws-sdk/token-providers" "3.525.0" + "@aws-sdk/client-sso" "3.529.1" + "@aws-sdk/token-providers" "3.529.1" "@aws-sdk/types" "3.523.0" "@smithy/property-provider" "^2.1.3" "@smithy/shared-ini-file-loader" "^2.3.3" "@smithy/types" "^2.10.1" tslib "^2.5.0" -"@aws-sdk/credential-provider-web-identity@3.525.0": - version "3.525.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.525.0.tgz#f71a7a322209468de89b2dee6acd961e386a89cc" - integrity sha512-sAukOjR1oKb2JXG4nPpuBFpSwGUhrrY17PG/xbTy8NAoLLhrqRwnErcLfdTfmj6tH+3094k6ws/Sh8a35ae7fA== +"@aws-sdk/credential-provider-web-identity@3.529.1": + version "3.529.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.529.1.tgz#84fe00b22b4a4377a637c5ee2c628ba3a696152a" + integrity sha512-AGuZDOKN+AttjwTjrF47WLqzeEut2YynyxjkXZhxZF/xn8i5Y51kUAUdXsXw1bgR25pAeXQIdhsrQlRa1Pm5kw== dependencies: - "@aws-sdk/client-sts" "3.525.0" + "@aws-sdk/client-sts" "3.529.1" "@aws-sdk/types" "3.523.0" "@smithy/property-provider" "^2.1.3" "@smithy/types" "^2.10.1" tslib "^2.5.0" -"@aws-sdk/credential-providers@3.525.0": - version "3.525.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-providers/-/credential-providers-3.525.0.tgz#9548710bc3b463c95de164f0eb084eb52a34cef8" - integrity sha512-zj439Ok1s44nahIJKpBM4jhAxnSw20flXQpMD2aeGdvUuKm2xmzZP0lX5z9a+XQWFtNh251ZcSt2p+RwtLKtiw== +"@aws-sdk/credential-providers@3.529.1": + version "3.529.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-providers/-/credential-providers-3.529.1.tgz#954e182b27ca47b9787ceb5c46db6df632e752dc" + integrity sha512-M85w4w5HU/nSaf8OSOV61sFFvQGn97dsGt8TcEJhx/s8d44coE+DGo9qCKdsG6B4dRQtl1NJmaFXNYl089JKRQ== dependencies: - "@aws-sdk/client-cognito-identity" "3.525.0" - "@aws-sdk/client-sso" "3.525.0" - "@aws-sdk/client-sts" "3.525.0" - "@aws-sdk/credential-provider-cognito-identity" "3.525.0" + "@aws-sdk/client-cognito-identity" "3.529.1" + "@aws-sdk/client-sso" "3.529.1" + "@aws-sdk/client-sts" "3.529.1" + "@aws-sdk/credential-provider-cognito-identity" "3.529.1" "@aws-sdk/credential-provider-env" "3.523.0" "@aws-sdk/credential-provider-http" "3.525.0" - "@aws-sdk/credential-provider-ini" "3.525.0" - "@aws-sdk/credential-provider-node" "3.525.0" + "@aws-sdk/credential-provider-ini" "3.529.1" + "@aws-sdk/credential-provider-node" "3.529.1" "@aws-sdk/credential-provider-process" "3.523.0" - "@aws-sdk/credential-provider-sso" "3.525.0" - "@aws-sdk/credential-provider-web-identity" "3.525.0" + "@aws-sdk/credential-provider-sso" "3.529.1" + "@aws-sdk/credential-provider-web-identity" "3.529.1" "@aws-sdk/types" "3.523.0" "@smithy/credential-provider-imds" "^2.2.3" "@smithy/property-provider" "^2.1.3" @@ -837,13 +835,13 @@ tslib "^2.5.0" "@aws-sdk/rds-signer@^3.315.0": - version "3.525.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/rds-signer/-/rds-signer-3.525.0.tgz#aa023ea56827d879571f8d58b69b5419917d3d22" - integrity sha512-vvBFGvv5IFiayYODGBJ0QrWzKOKp0DpPyY2S7sVluzGy03+DvOrcCAh74Q4yJW34pY8S/naK9iI/DAE+XgFgww== + version "3.529.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/rds-signer/-/rds-signer-3.529.1.tgz#381cb7802b0bf46e83f3cc58f4a577b9566b0008" + integrity sha512-Ooc5c7SofJXA/8/exWS1/Rofe7DfEe1QsUTABy+D95p0x/fd75xpbmL4UvpoTnJrTurifOr/xGok47eclXT15w== dependencies: "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" - "@aws-sdk/credential-providers" "3.525.0" + "@aws-sdk/credential-providers" "3.529.1" "@aws-sdk/util-format-url" "3.523.0" "@smithy/config-resolver" "^2.1.4" "@smithy/hash-node" "^2.1.3" @@ -867,9 +865,9 @@ tslib "^2.5.0" "@aws-sdk/s3-request-presigner@^3.312.0": - version "3.525.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.525.0.tgz#8c56b44431bfea57946e6e6c479d7dd371b357aa" - integrity sha512-EllqWqzzzLs8QgUENgOF8qlSuZI6QiPypazSVbCuaAR5B6+s6E8XuBPlX99bV28pGbmtG06d/qqwu2pzXORbBg== + version "3.529.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.529.1.tgz#5534792cc5c16669e97b82dee88204205dedfbe3" + integrity sha512-54nNN/LjqlyUDTLO3U9D7xkYK4/UttcqfKoHQuPI6QabqZGT1hMFs5SzsyihNchgxci6ZTo4pqQQ3lGfE/HHOA== dependencies: "@aws-sdk/signature-v4-multi-region" "3.525.0" "@aws-sdk/types" "3.523.0" @@ -892,12 +890,12 @@ "@smithy/types" "^2.10.1" tslib "^2.5.0" -"@aws-sdk/token-providers@3.525.0": - version "3.525.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.525.0.tgz#370d206a06e77e29ec0f76408654b16d6612f0d2" - integrity sha512-puVjbxuK0Dq7PTQ2HdddHy2eQjOH8GZbump74yWJa6JVpRW84LlOcNmP+79x4Kscvz2ldWB8XDFw/pcCiSDe5A== +"@aws-sdk/token-providers@3.529.1": + version "3.529.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.529.1.tgz#0d86e0edb50cfff51ac063410fde60edf3ae4b2d" + integrity sha512-NpgMjsfpqiugbxrYGXtta914N43Mx/H0niidqv8wKMTgWQEtsJvYtOni+kuLXB+LmpjaMFNlpadooFU/bK4buA== dependencies: - "@aws-sdk/client-sso-oidc" "3.525.0" + "@aws-sdk/client-sso-oidc" "3.529.1" "@aws-sdk/types" "3.523.0" "@smithy/property-provider" "^2.1.3" "@smithy/shared-ini-file-loader" "^2.3.3" @@ -2405,25 +2403,25 @@ debug "^3.1.0" lodash.once "^4.1.1" -"@datadog/browser-core@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@datadog/browser-core/-/browser-core-5.10.0.tgz#e0a074dec7270512480abfe3245371a7cb5e7754" - integrity sha512-fHTay/sPuh7tuGnXhnOkjMUuWewmkNJPlZOf+aVgUKPpv3uHYusl7j8l+YO2QUl86b1wtw487xpEVrlxsPA0aA== +"@datadog/browser-core@5.11.0": + version "5.11.0" + resolved "https://registry.yarnpkg.com/@datadog/browser-core/-/browser-core-5.11.0.tgz#93d56a1a02940269894558a93a3fb125a991d2d3" + integrity sha512-s5ak4Wf0xrxtlyruYtHZELEil+6ido+Zb/owpaYYU4ca05BDo4slIS03ztRCTYBv1dWpKJ6QkedvfklgWWAn6Q== -"@datadog/browser-rum-core@5.10.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@datadog/browser-rum-core/-/browser-rum-core-5.10.0.tgz#f8a949ca4de41937a5a4d6d975fa5002f3047810" - integrity sha512-yI2o3/l7t4MxiKv6KGZhKAFmjsde2DPRi2Yz7pBSgoFx6m8D2F1ivpyv44598x39siEHlKbn6CbSSToRpw0gIQ== +"@datadog/browser-rum-core@5.11.0": + version "5.11.0" + resolved "https://registry.yarnpkg.com/@datadog/browser-rum-core/-/browser-rum-core-5.11.0.tgz#0705bdcbf70c60c270a05124704ec8fcf85980bc" + integrity sha512-PKWPcrqNawk8Rl6n8orM7creaBwm7dl3hc907+BCI6ZY/kc7Vyu/gxOjqDDRyrkux+xFf0OUNkPdNMtc1w+eHA== dependencies: - "@datadog/browser-core" "5.10.0" + "@datadog/browser-core" "5.11.0" "@datadog/browser-rum@^5.5.0": - version "5.10.0" - resolved "https://registry.yarnpkg.com/@datadog/browser-rum/-/browser-rum-5.10.0.tgz#4a2d95e6a7c6ced4d6f1b7e192bdcf3e2e8c4e51" - integrity sha512-Z/cWdgFsdA1kOaijw4kS2+8HPqda11L567ZDJLYswwO4Cbg2SDrMPVJNOJnq7qLW7D+bJomRkor8298IJh9nog== + version "5.11.0" + resolved "https://registry.yarnpkg.com/@datadog/browser-rum/-/browser-rum-5.11.0.tgz#53158b1378c11f9ef8ea2d21fc7d281bf2f5189d" + integrity sha512-A+2e34ectIMRAEmhHF53gvGvt/TCgtB7kwSall5mPWIAK+qpb5T4haZPJx6MvLPjC6dTZmlXL4OT7NRgu+7cgA== dependencies: - "@datadog/browser-core" "5.10.0" - "@datadog/browser-rum-core" "5.10.0" + "@datadog/browser-core" "5.11.0" + "@datadog/browser-rum-core" "5.11.0" "@datadog/native-appsec@7.1.0": version "7.1.0" @@ -12028,9 +12026,9 @@ node-releases@^2.0.14: integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== nodemailer@^6.6.3: - version "6.9.11" - resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.9.11.tgz#900703bd6dc62855d9cea962acf261926841f825" - integrity sha512-UiAkgiERuG94kl/3bKfE8o10epvDnl0vokNEtZDPTq9BWzIl6EFT9336SbIT4oaTBD8NmmUTLsQyXHV82eXSWg== + version "6.9.12" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.9.12.tgz#48560eaf3575f8b0215eb38a45ca9025ffad2314" + integrity sha512-pnLo7g37Br3jXbF0bl5DekBJihm2q+3bB3l2o/B060sWmb5l+VqeScAQCBqaQ+5ezRZFzW5SciZNGdRDEbq89w== nodemon@2.0.15: version "2.0.15"