chore(meals): remove email_report payroll SES path (PLAT-135) (#187)
Some checks failed
Build Lambda Layer / build (push) Has been cancelled

* chore(meals): remove email_report payroll SES path (PLAT-135)

Stop Monday SES deduction emails now that Flex checkcomponents owns payroll posting.

* chore(meals): delete email_report handler and SAM resources

Remove the leftover SES Lambda source so it cannot be redeployed from template.yaml.
This commit is contained in:
Adam Moussa 2026-09-10 19:29:58 +00:00 • committed by GitHub
parent aceb174c4b
commit c1552f0bd3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 69 additions and 316 deletions

View file

@ -18,16 +18,15 @@ Monday 7:30am ET Employees (Mon–Thu) Thursda
│ - Slack notify │ └──────────────────┘ │ │ - Slack summary │ │ - Slack notify │ └──────────────────┘ │ │ - Slack summary │
└─────────────────┘ ▼ └──────────────────┘ └─────────────────┘ ▼ └──────────────────┘
┌──────────┐ ┌──────────┐
Monday 7am ET │ API GW + │ Thu 10am: Slack DM │ API GW + │
┌──────────────────┐ │ Lambda │ reminders to employees │ Lambda │
│ EventBridge │ │ submit │ who haven't ordered │ submit │
│ - Email payroll │ └────┬─────┘ └────┬─────┘
│ deductions │ ▼ ▼
└──────────────────┘ ┌──────────┐ ┌──────────┐
│ DynamoDB │ │ DynamoDB │
Thu 10am: Slack DM │ orders │ │ orders │
reminders to employees └──────────┘ └──────────┘
who haven't ordered
``` ```
### Form frontend decisions ### Form frontend decisions
@ -44,7 +43,6 @@ the generated HTML, and the generated deployment artifact remains self-contained
| When | What | How | | When | What | How |
|------|------|-----| |------|------|-----|
| Monday 6:55am ET | Sync employee roster from Slack channel membership | EventBridge → Lambda → DynamoDB | | Monday 6:55am ET | Sync employee roster from Slack channel membership | EventBridge → Lambda → DynamoDB |
| Monday 7am ET | Email previous week's payroll deductions to `payroll@` | EventBridge → Lambda → SES |
| Monday 7:30am ET | Scrape menu, generate form, upload to S3, post link to Slack | GitHub Actions cron | | Monday 7:30am ET | Scrape menu, generate form, upload to S3, post link to Slack | GitHub Actions cron |
| Mon–Thu | Employees visit `orders.seahaven.com` and submit orders | S3 static form → API Gateway → Lambda → DynamoDB | | Mon–Thu | Employees visit `orders.seahaven.com` and submit orders | S3 static form → API Gateway → Lambda → DynamoDB |
| Thursday 10am ET | DM employees who haven't ordered yet | EventBridge → Lambda → Slack DM | | Thursday 10am ET | DM employees who haven't ordered yet | EventBridge → Lambda → Slack DM |
@ -85,11 +83,10 @@ Stack name: `meal-order-manager` (us-east-1)
- **CloudFront** — HTTPS distribution with custom domain `orders.seahaven.com` - **CloudFront** — HTTPS distribution with custom domain `orders.seahaven.com`
- **DynamoDB** — `meal-order-manager-orders` (orders, menu, roster, config) - **DynamoDB** — `meal-order-manager-orders` (orders, menu, roster, config)
- **API Gateway** — HttpApi for order submission and admin operations - **API Gateway** — HttpApi for order submission and admin operations
- **Lambda** — 7 functions: submit-order, admin-authorizer, close-form, aggregate-orders, slack-notifier, sync-roster, email-report - **Lambda** — 6 functions: submit-order, admin-authorizer, close-form, aggregate-orders, slack-notifier, sync-roster
- **EventBridge** — scheduled rules (dual EST/EDT) for close, reminders, payroll email - **EventBridge** — scheduled rules (dual EST/EDT) for close, reminders, roster sync
- **Secrets Manager** — Slack bot token - **Secrets Manager** — Slack bot token
- Migration note: the existing `meal-order-manager/form-api-key` secret remains until this change is deployed and verified, then must be deleted during post-deploy cleanup. - Migration note: the existing `meal-order-manager/form-api-key` secret remains until this change is deployed and verified, then must be deleted during post-deploy cleanup.
- **SES** — payroll deduction emails
- **CloudWatch Alarms** — coverage across the stack, all notifying the shared `site-alerts` SNS topic (see Monitoring) - **CloudWatch Alarms** — coverage across the stack, all notifying the shared `site-alerts` SNS topic (see Monitoring)
## Monitoring ## Monitoring
@ -99,7 +96,7 @@ CloudWatch alarms are defined in `template.yaml`. Every alarm sends to the share
OKActions, and treats missing data as not breaching (so idle/cron functions don't OKActions, and treats missing data as not breaching (so idle/cron functions don't
sit in ALARM between runs). Alarm names follow `meal-order-manager-<fn>-<signal>`. sit in ALARM between runs). Alarm names follow `meal-order-manager-<fn>-<signal>`.
- **Lambda Errors / Throttles** — one alarm each per function (7 functions), Sum - **Lambda Errors / Throttles** — one alarm each per function (6 functions), Sum
over 5 min, fires on any error/throttle (threshold 0). over 5 min, fires on any error/throttle (threshold 0).
- **Lambda Duration** — p99 over 5 min at ~80% of each function's timeout. - **Lambda Duration** — p99 over 5 min at ~80% of each function's timeout.
API-fronted functions (submit-order, admin-authorizer) evaluate 3/3 datapoints; API-fronted functions (submit-order, admin-authorizer) evaluate 3/3 datapoints;
@ -168,9 +165,8 @@ sam deploy
1. Create the Slack bot token secret: `aws secretsmanager create-secret --name meal-order-manager/slack-bot-token --secret-string "xoxb-..."` 1. Create the Slack bot token secret: `aws secretsmanager create-secret --name meal-order-manager/slack-bot-token --secret-string "xoxb-..."`
2. Set the Google OAuth client ID: `aws ssm put-parameter --name /meal-order-manager/google-client-id --type String --value "<YOUR_GOOGLE_CLIENT_ID>" --overwrite` 2. Set the Google OAuth client ID: `aws ssm put-parameter --name /meal-order-manager/google-client-id --type String --value "<YOUR_GOOGLE_CLIENT_ID>" --overwrite`
3. Update the Slack channel SSM parameter: `aws ssm put-parameter --name /meal-order-manager/slack-channel-id --value "C0XXXXXXX" --overwrite` 3. Update the Slack channel SSM parameter: `aws ssm put-parameter --name /meal-order-manager/slack-channel-id --value "C0XXXXXXX" --overwrite`
4. Verify SES sender identity for `adam@seahavenind.com` 4. Set up DNS: CNAME `orders.seahaven.com` → CloudFront distribution domain
5. Set up DNS: CNAME `orders.seahaven.com` → CloudFront distribution domain 5. Roster syncs automatically from Slack channel members (runs Monday 6:55am ET), or seed manually: `python3 scripts/seed_roster.py`
6. Roster syncs automatically from Slack channel members (runs Monday 6:55am ET), or seed manually: `python3 scripts/seed_roster.py`
## Local Workflow (no AWS) ## Local Workflow (no AWS)
@ -210,8 +206,7 @@ meal-order-manager/
│ ├── close_form/ │ ├── close_form/
│ ├── aggregate_orders/ │ ├── aggregate_orders/
│ ├── slack_notifier/ │ ├── slack_notifier/
│ ├── sync_roster/ │ └── sync_roster/
│ └── email_report/
├── scripts/ # CI/CD helper scripts ├── scripts/ # CI/CD helper scripts
│ ├── upload_menu.py │ ├── upload_menu.py
│ ├── notify_slack.py │ ├── notify_slack.py

View file

@ -1,58 +0,0 @@
import os
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import boto3
from shared.db import get_summary, previous_week
_ses = boto3.client("ses")
_s3 = boto3.client("s3")
def lambda_handler(event, context):
week = event.get("week", previous_week())
summary = get_summary(week)
if not summary:
return {"status": "no_summary", "week": week}
payroll_key = summary.get("payroll_csv_s3_key")
if not payroll_key:
return {"status": "no_payroll_csv", "week": week}
bucket = os.environ["REPORTS_BUCKET"]
csv_obj = _s3.get_object(Bucket=bucket, Key=payroll_key)
csv_content = csv_obj["Body"].read()
total_employees = int(summary.get("total_employees", 0))
grand_total = float(summary.get("grand_total", 0))
msg = MIMEMultipart("mixed")
msg["Subject"] = f"Meal Order Payroll Deductions — {week}"
msg["From"] = os.environ["SENDER_EMAIL"]
msg["To"] = os.environ["PAYROLL_EMAIL"]
body = MIMEText(
f"Attached is the meal order payroll deduction report for {week}.\n\n"
f"Employees: {total_employees}\n"
f"Total deductions: ${grand_total:.2f}\n\n"
f"Please apply these deductions in the next pay period.\n",
"plain",
)
msg.attach(body)
attachment = MIMEApplication(csv_content)
attachment.add_header(
"Content-Disposition", "attachment", filename=f"payroll-deductions-{week}.csv"
)
msg.attach(attachment)
_ses.send_raw_email(
Source=os.environ["SENDER_EMAIL"],
Destinations=[os.environ["PAYROLL_EMAIL"]],
RawMessage={"Data": msg.as_string()},
)
return {"status": "sent", "week": week, "to": os.environ["PAYROLL_EMAIL"]}

View file

@ -1 +0,0 @@
boto3==1.43.78

View file

@ -7,4 +7,4 @@ s3_prefix = "meal-order-manager"
region = "us-east-1" region = "us-east-1"
confirm_changeset = true confirm_changeset = true
capabilities = "CAPABILITY_IAM" capabilities = "CAPABILITY_IAM"
parameter_overrides = "CustomDomain=orders.seahaven.com CertificateArn=arn:aws:acm:us-east-1:328440206208:certificate/CHANGE-ME PayrollEmail=payroll@seahavenind.com SenderEmail=adam@seahavenind.com" parameter_overrides = "CustomDomain=orders.seahaven.com CertificateArn=arn:aws:acm:us-east-1:328440206208:certificate/CHANGE-ME"

View file

@ -13,14 +13,6 @@ Parameters:
Type: String Type: String
Default: '' Default: ''
Description: ACM certificate ARN for the custom domain (us-east-1) Description: ACM certificate ARN for the custom domain (us-east-1)
PayrollEmail:
Type: String
Default: payroll@seahavenind.com
Description: Email address for payroll deduction reports
SenderEmail:
Type: String
Default: adam@seahavenind.com
Description: SES verified sender email for payroll reports
# Shared CloudFront WAF WebACL ARN (audit M-17), published to SSM by # Shared CloudFront WAF WebACL ARN (audit M-17), published to SSM by
# seahaven-account-baseline. Resolved at deploy time. # seahaven-account-baseline. Resolved at deploy time.
WebAclArn: WebAclArn:
@ -543,42 +535,6 @@ Resources:
Description: 'Sync roster Monday 6:55am EDT (10:55 UTC) — before menu publish' Description: 'Sync roster Monday 6:55am EDT (10:55 UTC) — before menu publish'
Enabled: true Enabled: true
EmailReportFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: meal-order-manager-email-report
Handler: handler.lambda_handler
CodeUri: functions/email_report/
MemorySize: 128
Timeout: 30
Environment:
Variables:
PAYROLL_EMAIL: !Ref PayrollEmail
SENDER_EMAIL: !Ref SenderEmail
Policies:
- DynamoDBReadPolicy:
TableName: !Ref OrdersTable
- S3ReadPolicy:
BucketName: !Ref ReportsBucket
- Statement:
- Effect: Allow
Action:
- ses:SendRawEmail
Resource: '*'
Events:
PayrollEmailEST:
Type: Schedule
Properties:
Schedule: cron(0 12 ? * MON *)
Description: 'Email payroll deductions Monday 7am EST (12:00 UTC)'
Enabled: true
PayrollEmailEDT:
Type: Schedule
Properties:
Schedule: cron(0 11 ? * MON *)
Description: 'Email payroll deductions Monday 7am EDT (11:00 UTC)'
Enabled: true
# ─── CloudWatch Log Groups (60-day retention) ────────────────── # ─── CloudWatch Log Groups (60-day retention) ──────────────────
SubmitOrderLogGroup: SubmitOrderLogGroup:
@ -605,12 +561,6 @@ Resources:
LogGroupName: !Sub '/aws/lambda/${SlackNotifierFunction}' LogGroupName: !Sub '/aws/lambda/${SlackNotifierFunction}'
RetentionInDays: 60 RetentionInDays: 60
EmailReportLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub '/aws/lambda/${EmailReportFunction}'
RetentionInDays: 60
SyncRosterLogGroup: SyncRosterLogGroup:
Type: AWS::Logs::LogGroup Type: AWS::Logs::LogGroup
Properties: Properties:
@ -744,25 +694,6 @@ Resources:
AlarmActions: AlarmActions:
- arn:aws:sns:us-east-1:328440206208:site-alerts - arn:aws:sns:us-east-1:328440206208:site-alerts
EmailReportErrorsAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName: meal-order-manager-email-report-errors
AlarmDescription: email-report Lambda reported one or more errors in 5 minutes.
Namespace: AWS/Lambda
MetricName: Errors
Dimensions:
- Name: FunctionName
Value: !Ref EmailReportFunction
Statistic: Sum
Period: 300
EvaluationPeriods: 1
Threshold: 0
ComparisonOperator: GreaterThanThreshold
TreatMissingData: notBreaching
AlarmActions:
- arn:aws:sns:us-east-1:328440206208:site-alerts
# Lambda Throttles (Sum, 5min, any throttle breaches) # Lambda Throttles (Sum, 5min, any throttle breaches)
SubmitOrderThrottlesAlarm: SubmitOrderThrottlesAlarm:
Type: AWS::CloudWatch::Alarm Type: AWS::CloudWatch::Alarm
@ -878,25 +809,6 @@ Resources:
AlarmActions: AlarmActions:
- arn:aws:sns:us-east-1:328440206208:site-alerts - arn:aws:sns:us-east-1:328440206208:site-alerts
EmailReportThrottlesAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName: meal-order-manager-email-report-throttles
AlarmDescription: email-report Lambda was throttled in the last 5 minutes.
Namespace: AWS/Lambda
MetricName: Throttles
Dimensions:
- Name: FunctionName
Value: !Ref EmailReportFunction
Statistic: Sum
Period: 300
EvaluationPeriods: 1
Threshold: 0
ComparisonOperator: GreaterThanThreshold
TreatMissingData: notBreaching
AlarmActions:
- arn:aws:sns:us-east-1:328440206208:site-alerts
# Lambda Duration p99 (~80% of timeout) # Lambda Duration p99 (~80% of timeout)
# Synchronous (API-fronted) functions: eval 3 / datapoints 3. # Synchronous (API-fronted) functions: eval 3 / datapoints 3.
SubmitOrderDurationAlarm: SubmitOrderDurationAlarm:
@ -1020,26 +932,6 @@ Resources:
AlarmActions: AlarmActions:
- arn:aws:sns:us-east-1:328440206208:site-alerts - arn:aws:sns:us-east-1:328440206208:site-alerts
EmailReportDurationAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName: meal-order-manager-email-report-duration
AlarmDescription: email-report p99 duration exceeded 24000ms (80% of 30s timeout).
Namespace: AWS/Lambda
MetricName: Duration
Dimensions:
- Name: FunctionName
Value: !Ref EmailReportFunction
ExtendedStatistic: p99
Period: 300
EvaluationPeriods: 1
DatapointsToAlarm: 1
Threshold: 24000
ComparisonOperator: GreaterThanThreshold
TreatMissingData: notBreaching
AlarmActions:
- arn:aws:sns:us-east-1:328440206208:site-alerts
# DynamoDB orders table. # DynamoDB orders table.
# NOTE: DynamoDB does NOT publish ThrottledRequests or SystemErrors at the # NOTE: DynamoDB does NOT publish ThrottledRequests or SystemErrors at the
# TableName-only dimension (verified via cloudwatch list-metrics on # TableName-only dimension (verified via cloudwatch list-metrics on
@ -1202,6 +1094,3 @@ Outputs:
SyncRosterFunctionArn: SyncRosterFunctionArn:
Description: Sync Roster Lambda ARN Description: Sync Roster Lambda ARN
Value: !GetAtt SyncRosterFunction.Arn Value: !GetAtt SyncRosterFunction.Arn
EmailReportFunctionArn:
Description: Email Report Lambda ARN
Value: !GetAtt EmailReportFunction.Arn

View file

@ -49,12 +49,6 @@ locals {
duration_timeout = "60s" duration_timeout = "60s"
duration_datapoints = 1 duration_datapoints = 1
} }
"email-report" = {
function_name = aws_lambda_function.email_report.function_name
duration_threshold = 24000
duration_timeout = "30s"
duration_datapoints = 1
}
} }
} }

View file

@ -13,7 +13,6 @@ FUNCTIONS=(
admin_authorizer admin_authorizer
aggregate_orders aggregate_orders
close_form close_form
email_report
slack_notifier slack_notifier
submit_order submit_order
sync_roster sync_roster

View file

@ -53,20 +53,6 @@ locals {
function_name = aws_lambda_function.sync_roster.function_name function_name = aws_lambda_function.sync_roster.function_name
input = null input = null
} }
"payroll-email-est" = {
description = "Email payroll deductions Monday 7am EST (12:00 UTC)"
schedule = "cron(0 12 ? * MON *)"
function_arn = aws_lambda_function.email_report.arn
function_name = aws_lambda_function.email_report.function_name
input = null
}
"payroll-email-edt" = {
description = "Email payroll deductions Monday 7am EDT (11:00 UTC)"
schedule = "cron(0 11 ? * MON *)"
function_arn = aws_lambda_function.email_report.arn
function_name = aws_lambda_function.email_report.function_name
input = null
}
} }
} }

View file

@ -1,4 +1,4 @@
# Execution roles for the seven Lambda functions plus the API Gateway role that # Execution roles for the six Lambda functions plus the API Gateway role that
# invokes the admin authorizer. # invokes the admin authorizer.
# #
# Every Lambda execution role is created under the /tf-managed/ path and # Every Lambda execution role is created under the /tf-managed/ path and
@ -325,55 +325,3 @@ resource "aws_iam_role_policy" "sync_roster" {
role = aws_iam_role.sync_roster.id role = aws_iam_role.sync_roster.id
policy = data.aws_iam_policy_document.sync_roster.json policy = data.aws_iam_policy_document.sync_roster.json
} }
# ---------------------------------------------------------------------------
# email-report
# ---------------------------------------------------------------------------
resource "aws_iam_role" "email_report" {
name = "${local.project}-email-report"
path = "/tf-managed/"
assume_role_policy = data.aws_iam_policy_document.lambda_assume.json
permissions_boundary = local.boundary_arn
}
resource "aws_iam_role_policy_attachment" "email_report_basic" {
role = aws_iam_role.email_report.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}
data "aws_iam_policy_document" "email_report" {
source_policy_documents = [data.aws_iam_policy_document.dynamodb_read.json]
statement {
sid = "ReportsBucketRead"
effect = "Allow"
actions = ["s3:GetObject", "s3:GetObjectVersion"]
resources = ["${aws_s3_bucket.reports.arn}/*"]
}
statement {
sid = "ReportsBucketList"
effect = "Allow"
actions = ["s3:GetBucketLocation", "s3:ListBucket"]
resources = [aws_s3_bucket.reports.arn]
}
# Scope SendRawEmail to the verified sender domain/identity rather than "*".
# SES still enforces verification; IAM pins the From identity ARNs.
statement {
sid = "SendPayrollReport"
effect = "Allow"
actions = ["ses:SendRawEmail"]
resources = [
"arn:aws:ses:${var.aws_region}:${local.account_id}:identity/${var.sender_email}",
"arn:aws:ses:${var.aws_region}:${local.account_id}:identity/seahavenind.com",
]
}
}
resource "aws_iam_role_policy" "email_report" {
name = "email-report"
role = aws_iam_role.email_report.id
policy = data.aws_iam_policy_document.email_report.json
}

View file

@ -1,4 +1,4 @@
# The shared layer and the seven functions. # The shared layer and the six functions.
# #
# Packages come from the artifacts bucket (see artifacts.tf). Function packages # Packages come from the artifacts bucket (see artifacts.tf). Function packages
# contain the handler only: boto3 comes from the runtime, and fpdf2 plus the # contain the handler only: boto3 comes from the runtime, and fpdf2 plus the
@ -205,36 +205,3 @@ resource "aws_lambda_function" "sync_roster" {
aws_iam_role_policy_attachment.sync_roster_basic, aws_iam_role_policy_attachment.sync_roster_basic,
] ]
} }
# ---------------------------------------------------------------------------
# email-report — emails the weekly payroll deduction report
# ---------------------------------------------------------------------------
resource "aws_lambda_function" "email_report" {
function_name = "${local.project}-email-report"
role = aws_iam_role.email_report.arn
handler = "handler.lambda_handler"
runtime = "python3.12"
architectures = ["arm64"]
memory_size = 128
timeout = 30
s3_bucket = aws_s3_bucket.artifacts.id
s3_key = aws_s3_object.function["email_report"].key
source_code_hash = data.archive_file.function["email_report"].output_base64sha256
layers = [aws_lambda_layer_version.shared.arn]
environment {
variables = merge(local.common_env, {
PAYROLL_EMAIL = var.payroll_email
SENDER_EMAIL = var.sender_email
})
}
depends_on = [
aws_cloudwatch_log_group.function,
aws_iam_role_policy.email_report,
aws_iam_role_policy_attachment.email_report_basic,
]
}

View file

@ -34,7 +34,6 @@ locals {
"admin_authorizer", "admin_authorizer",
"aggregate_orders", "aggregate_orders",
"close_form", "close_form",
"email_report",
"slack_notifier", "slack_notifier",
"submit_order", "submit_order",
"sync_roster", "sync_roster",

View file

@ -54,7 +54,6 @@ output "function_arns" {
admin_authorizer = aws_lambda_function.admin_authorizer.arn admin_authorizer = aws_lambda_function.admin_authorizer.arn
aggregate_orders = aws_lambda_function.aggregate_orders.arn aggregate_orders = aws_lambda_function.aggregate_orders.arn
close_form = aws_lambda_function.close_form.arn close_form = aws_lambda_function.close_form.arn
email_report = aws_lambda_function.email_report.arn
slack_notifier = aws_lambda_function.slack_notifier.arn slack_notifier = aws_lambda_function.slack_notifier.arn
submit_order = aws_lambda_function.submit_order.arn submit_order = aws_lambda_function.submit_order.arn
sync_roster = aws_lambda_function.sync_roster.arn sync_roster = aws_lambda_function.sync_roster.arn

View file

@ -9,10 +9,6 @@ aws_region = "us-east-1"
domain_name = "orders.seahaven.com" domain_name = "orders.seahaven.com"
attach_custom_domain = false attach_custom_domain = false
# Payroll deduction report recipient and SES-verified sender.
payroll_email = "payroll@seahavenind.com"
sender_email = "adam@seahavenind.com"
# ARN of the out-of-band Secrets Manager secret holding the Slack bot token. # ARN of the out-of-band Secrets Manager secret holding the Slack bot token.
# Only the ARN is used; the value never enters Terraform state. # Only the ARN is used; the value never enters Terraform state.
slack_bot_secret_arn = "arn:aws:secretsmanager:us-east-1:011934824531:secret:meal-order-manager/slack-bot-token-XXXXXX" slack_bot_secret_arn = "arn:aws:secretsmanager:us-east-1:011934824531:secret:meal-order-manager/slack-bot-token-XXXXXX"

View file

@ -16,18 +16,6 @@ variable "attach_custom_domain" {
default = false default = false
} }
variable "payroll_email" {
description = "Recipient of the weekly payroll deduction report."
type = string
default = "payroll@seahavenind.com"
}
variable "sender_email" {
description = "SES-verified From address for the payroll deduction report."
type = string
default = "adam@seahavenind.com"
}
variable "slack_bot_secret_arn" { variable "slack_bot_secret_arn" {
description = "ARN of the Secrets Manager secret holding the Slack bot token. The secret and its value are managed out-of-band; only the ARN enters this configuration." description = "ARN of the Secrets Manager secret holding the Slack bot token. The secret and its value are managed out-of-band; only the ARN enters this configuration."
type = string type = string

View file

@ -0,0 +1,52 @@
"""email_report is removed from Terraform, SAM, and the functions tree (PLAT-135)."""
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
TERRAFORM = ROOT / "terraform"
def _read(name: str) -> str:
return (TERRAFORM / name).read_text()
def test_email_report_handler_removed():
assert not (ROOT / "functions" / "email_report").exists()
def test_email_report_not_in_function_packages():
locals_tf = _read("locals.tf")
assert '"email_report"' not in locals_tf
packages_sh = _read("build_packages.sh")
assert "email_report" not in packages_sh
def test_payroll_email_schedules_removed():
events = _read("events.tf")
assert "payroll-email-est" not in events
assert "payroll-email-edt" not in events
assert "email_report" not in events
def test_email_report_lambda_and_role_removed():
lambda_tf = _read("lambda.tf")
iam_tf = _read("iam.tf")
alarms = _read("alarms.tf")
outputs = _read("outputs.tf")
variables = _read("variables.tf")
assert "aws_lambda_function.email_report" not in lambda_tf
assert "aws_iam_role.email_report" not in iam_tf
assert "ses:SendRawEmail" not in iam_tf
assert "email-report" not in alarms
assert "email_report" not in outputs
assert "payroll_email" not in variables
assert "sender_email" not in variables
def test_email_report_removed_from_sam_template():
template = (ROOT / "template.yaml").read_text()
assert "EmailReportFunction" not in template
assert "functions/email_report/" not in template
assert "PayrollEmail" not in template
assert "SenderEmail" not in template
assert "ses:SendRawEmail" not in template