The abri lambda ships with its queue, DLQ and UAT-pointed staging config 🟩

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Daniel Roth 2026-07-07 10:29:01 +00:00
parent 58199a1c03
commit 7b2fe80688
8 changed files with 248 additions and 1 deletions

View file

@ -100,6 +100,15 @@ on:
TF_VAR_open_epc_api_token: TF_VAR_open_epc_api_token:
required: false required: false
TF_VAR_abri_relay_url:
required: false
TF_VAR_abri_relay_username:
required: false
TF_VAR_abri_relay_password:
required: false
TF_VAR_abri_relay_default_resource:
required: false
jobs: jobs:
deploy: deploy:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -175,6 +184,10 @@ jobs:
TF_VAR_magicplan_api_key: ${{ secrets.TF_VAR_magicplan_api_key }} TF_VAR_magicplan_api_key: ${{ secrets.TF_VAR_magicplan_api_key }}
TF_VAR_openai_api_key: ${{ secrets.TF_VAR_openai_api_key }} TF_VAR_openai_api_key: ${{ secrets.TF_VAR_openai_api_key }}
TF_VAR_open_epc_api_token: ${{ secrets.TF_VAR_open_epc_api_token }} TF_VAR_open_epc_api_token: ${{ secrets.TF_VAR_open_epc_api_token }}
TF_VAR_abri_relay_url: ${{ secrets.TF_VAR_abri_relay_url }}
TF_VAR_abri_relay_username: ${{ secrets.TF_VAR_abri_relay_username }}
TF_VAR_abri_relay_password: ${{ secrets.TF_VAR_abri_relay_password }}
TF_VAR_abri_relay_default_resource: ${{ secrets.TF_VAR_abri_relay_default_resource }}
run: | run: |
ECR_REPO_URL_VAR="" ECR_REPO_URL_VAR=""
if [[ -n "${{ inputs.ecr_repo }}" ]]; then if [[ -n "${{ inputs.ecr_repo }}" ]]; then
@ -228,6 +241,10 @@ jobs:
TF_VAR_magicplan_api_key: ${{ secrets.TF_VAR_magicplan_api_key }} TF_VAR_magicplan_api_key: ${{ secrets.TF_VAR_magicplan_api_key }}
TF_VAR_openai_api_key: ${{ secrets.TF_VAR_openai_api_key }} TF_VAR_openai_api_key: ${{ secrets.TF_VAR_openai_api_key }}
TF_VAR_open_epc_api_token: ${{ secrets.TF_VAR_open_epc_api_token }} TF_VAR_open_epc_api_token: ${{ secrets.TF_VAR_open_epc_api_token }}
TF_VAR_abri_relay_url: ${{ secrets.TF_VAR_abri_relay_url }}
TF_VAR_abri_relay_username: ${{ secrets.TF_VAR_abri_relay_username }}
TF_VAR_abri_relay_password: ${{ secrets.TF_VAR_abri_relay_password }}
TF_VAR_abri_relay_default_resource: ${{ secrets.TF_VAR_abri_relay_default_resource }}
run: | run: |
EXTRA_VARS="" EXTRA_VARS=""
if [[ -n "${{ inputs.ecr_repo }}" ]]; then if [[ -n "${{ inputs.ecr_repo }}" ]]; then

View file

@ -700,6 +700,49 @@ jobs:
TF_VAR_magicplan_customer_id: ${{ secrets.MAGICPLAN_CUSTOMER_ID }} TF_VAR_magicplan_customer_id: ${{ secrets.MAGICPLAN_CUSTOMER_ID }}
TF_VAR_magicplan_api_key: ${{ secrets.MAGICPLAN_API_KEY }} TF_VAR_magicplan_api_key: ${{ secrets.MAGICPLAN_API_KEY }}
# ============================================================
# Build Abri Lambda image
# ============================================================
abri_image:
needs: [determine_stage, shared_terraform]
uses: ./.github/workflows/_build_image.yml
with:
ecr_repo: abri-${{ needs.determine_stage.outputs.stage }}
dockerfile_path: applications/abri/handler/Dockerfile
build_context: .
secrets:
AWS_ACCESS_KEY_ID: ${{ secrets.DEV_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.DEV_AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ secrets.DEV_AWS_REGION }}
# ============================================================
# Deploy Abri Lambda
# ============================================================
abri_lambda:
needs: [abri_image, determine_stage]
uses: ./.github/workflows/_deploy_lambda.yml
with:
lambda_name: abri
lambda_path: deployment/terraform/lambda/abri
stage: ${{ needs.determine_stage.outputs.stage }}
ecr_repo: abri-${{ needs.determine_stage.outputs.stage }}
image_digest: ${{ needs.abri_image.outputs.image_digest }}
terraform_apply: ${{ needs.determine_stage.outputs.terraform_apply }}
secrets:
AWS_ACCESS_KEY_ID: ${{ secrets.DEV_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.DEV_AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ secrets.DEV_AWS_REGION }}
TF_VAR_db_host: ${{ secrets.DEV_DB_HOST }}
TF_VAR_db_name: ${{ secrets.DEV_DB_NAME }}
TF_VAR_db_port: ${{ secrets.DEV_DB_PORT }}
TF_VAR_hubspot_api_key: ${{ secrets.HUBSPOT_API_KEY }}
# Staging points at Abri's UAT relay endpoint; production values are
# pending from Abri (prod apply is blocked until they exist).
TF_VAR_abri_relay_url: ${{ secrets.ABRI_RELAY_URL }}
TF_VAR_abri_relay_username: ${{ secrets.ABRI_RELAY_USERNAME }}
TF_VAR_abri_relay_password: ${{ secrets.ABRI_RELAY_PASSWORD }}
TF_VAR_abri_relay_default_resource: ${{ secrets.ABRI_RELAY_DEFAULT_RESOURCE }}
# ============================================================ # ============================================================
# Build Audit Generator image # Build Audit Generator image
# ============================================================ # ============================================================
@ -778,7 +821,7 @@ jobs:
# Deploy Hubspot ETL Lambda # Deploy Hubspot ETL Lambda
# ============================================================ # ============================================================
hubspot_etl_lambda: hubspot_etl_lambda:
needs: [hubspot_etl_image, determine_stage, pashub_to_ara_lambda, magic_plan_lambda] needs: [hubspot_etl_image, determine_stage, pashub_to_ara_lambda, magic_plan_lambda, abri_lambda]
uses: ./.github/workflows/_deploy_lambda.yml uses: ./.github/workflows/_deploy_lambda.yml
with: with:
lambda_name: hubspot-etl-to-ara lambda_name: hubspot-etl-to-ara

View file

@ -0,0 +1,40 @@
data "aws_secretsmanager_secret_version" "db_credentials" {
secret_id = "${var.stage}/assessment_model/db_credentials"
}
locals {
db_credentials = jsondecode(data.aws_secretsmanager_secret_version.db_credentials.secret_string)
}
module "lambda" {
source = "../../modules/lambda_with_sqs"
name = "abri"
stage = var.stage
image_uri = local.image_uri
maximum_concurrency = var.maximum_concurrency
reserved_concurrent_executions = var.reserved_concurrent_executions
batch_size = var.batch_size
environment = {
STAGE = var.stage
LOG_LEVEL = "info"
# Abri relay credentials are per-stage: the dev/staging stage points at
# Abri's UAT relay endpoint; production values are pending from Abri.
ABRI_RELAY_URL = var.abri_relay_url
ABRI_RELAY_USERNAME = var.abri_relay_username
ABRI_RELAY_PASSWORD = var.abri_relay_password
ABRI_RELAY_DEFAULT_RESOURCE = var.abri_relay_default_resource
HUBSPOT_API_KEY = var.hubspot_api_key
POSTGRES_USERNAME = local.db_credentials.db_assessment_model_username
POSTGRES_PASSWORD = local.db_credentials.db_assessment_model_password
POSTGRES_HOST = var.db_host
POSTGRES_DATABASE = var.db_name
POSTGRES_PORT = var.db_port
}
}

View file

@ -0,0 +1,9 @@
output "abri_queue_url" {
value = module.lambda.queue_url
description = "URL of the Abri SQS queue"
}
output "abri_queue_arn" {
value = module.lambda.queue_arn
description = "ARN of the Abri SQS queue"
}

View file

@ -0,0 +1,16 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.0"
}
}
backend "s3" {
bucket = "abri-terraform-state"
key = "terraform.tfstate"
region = "eu-west-2"
}
required_version = ">= 1.2.0"
}

View file

@ -0,0 +1,84 @@
variable "lambda_name" {
type = string
description = "Logical name of the lambda"
default = "abri"
}
variable "stage" {
description = "Deployment stage (e.g. dev, prod)"
type = string
}
variable "ecr_repo_url" {
type = string
description = "ECR repository URL (no tag, no digest)"
}
variable "image_digest" {
type = string
description = "Image digest (sha256:...)"
}
variable "maximum_concurrency" {
type = number
default = null
description = "Maximum number of concurrent Lambda invocations from SQS (2-1000). null = no limit."
}
variable "reserved_concurrent_executions" {
type = number
default = 1
}
variable "batch_size" {
type = number
default = 1
}
locals {
image_uri = "${var.ecr_repo_url}@${var.image_digest}"
}
output "resolved_image_uri" {
value = local.image_uri
}
variable "abri_relay_url" {
type = string
sensitive = true
}
variable "abri_relay_username" {
type = string
sensitive = true
}
variable "abri_relay_password" {
type = string
sensitive = true
}
variable "abri_relay_default_resource" {
type = string
sensitive = true
}
variable "hubspot_api_key" {
type = string
sensitive = true
}
variable "db_host" {
type = string
sensitive = true
}
variable "db_name" {
type = string
sensitive = true
}
variable "db_port" {
type = string
sensitive = true
}

View file

@ -25,6 +25,15 @@ data "terraform_remote_state" "magic_plan" {
} }
} }
data "terraform_remote_state" "abri" {
backend = "s3"
config = {
bucket = "abri-terraform-state"
key = "env:/${var.stage}/terraform.tfstate"
region = "eu-west-2"
}
}
data "aws_secretsmanager_secret_version" "db_credentials" { data "aws_secretsmanager_secret_version" "db_credentials" {
secret_id = "${var.stage}/assessment_model/db_credentials" secret_id = "${var.stage}/assessment_model/db_credentials"
} }
@ -59,6 +68,7 @@ module "hubspot_deal_etl" {
PASHUB_TO_ARA_SQS_URL = data.terraform_remote_state.pashub_to_ara.outputs.pashub_to_ara_queue_url PASHUB_TO_ARA_SQS_URL = data.terraform_remote_state.pashub_to_ara.outputs.pashub_to_ara_queue_url
MAGICPLAN_SQS_URL = data.terraform_remote_state.magic_plan.outputs.magic_plan_queue_url MAGICPLAN_SQS_URL = data.terraform_remote_state.magic_plan.outputs.magic_plan_queue_url
ABRI_SQS_URL = data.terraform_remote_state.abri.outputs.abri_queue_url
} }
} }
@ -100,4 +110,18 @@ module "hubspot_deal_etl_magicplan_sqs_policy" {
resource "aws_iam_role_policy_attachment" "hubspot_deal_etl_magicplan_sqs_send" { resource "aws_iam_role_policy_attachment" "hubspot_deal_etl_magicplan_sqs_send" {
role = module.hubspot_deal_etl.role_name role = module.hubspot_deal_etl.role_name
policy_arn = module.hubspot_deal_etl_magicplan_sqs_policy.policy_arn policy_arn = module.hubspot_deal_etl_magicplan_sqs_policy.policy_arn
}
module "hubspot_deal_etl_abri_sqs_policy" {
source = "../../modules/general_iam_policy"
policy_name = "hubspot-deal-etl-abri-sqs-send-${var.stage}"
policy_description = "Allow HubSpot ETL Lambda to send messages to the Abri queue"
actions = ["sqs:SendMessage"]
resources = [data.terraform_remote_state.abri.outputs.abri_queue_arn]
}
resource "aws_iam_role_policy_attachment" "hubspot_deal_etl_abri_sqs_send" {
role = module.hubspot_deal_etl.role_name
policy_arn = module.hubspot_deal_etl_abri_sqs_policy.policy_arn
} }

View file

@ -894,3 +894,17 @@ output "modelling_e2e_ecr_url" {
value = module.modelling_e2e_registry.repository_url value = module.modelling_e2e_registry.repository_url
} }
################################################
# Abri OpenHousing Lambda
################################################
module "abri_state_bucket" {
source = "../modules/tf_state_bucket"
bucket_name = "abri-terraform-state"
}
module "abri_registry" {
source = "../modules/container_registry"
name = "abri"
stage = var.stage
}