chore(pay): disable weekly-post payroll SES email (PLAT-135) (#248)
Some checks are pending
Deploy / deploy (push) Waiting to run
Deploy / release (push) Blocked by required conditions

Empty PAYROLL_RECIPIENTS and drop ses:SendEmail so Monday Slack posts stay, SES pay mail stops.
This commit is contained in:
Adam Moussa 2026-09-10 19:30:00 +00:00 • committed by GitHub
parent 23bad9bee6
commit 2dbe99ef0b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 23 additions and 25 deletions

View file

@ -166,7 +166,7 @@ Resources:
SLACK_BOT_TOKEN_SECRET: afterhours-shift-manager/slack-bot-token
SHIFT_CHANNEL: !Ref ShiftChannel
SES_SENDER: noreply@seahaven.com
PAYROLL_RECIPIENTS: payroll@seahaven.com
PAYROLL_RECIPIENTS: ""
PAY_REPORT_USER: U0A3SC48T47
TZ: !Ref Timezone
CHECKCOMPONENTS_QUEUE_URL: !Ref CheckcomponentsQueueUrl
@ -180,30 +180,6 @@ Resources:
- secretsmanager:GetSecretValue
Resource:
- !Sub "arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:afterhours-shift-manager/slack-bot-token-*"
- Effect: Allow
Action:
- ses:SendEmail
Resource:
# The From address (noreply@seahaven.com) is NOT a standalone
# verified SES identity — it is covered by the verified DOMAIN
# identity seahaven.com, which is the identity SES authorizes
# SendEmail against. Granting identity/noreply@seahaven.com (a
# non-existent identity) caused AccessDenied; the domain ARN is
# the correct least-privilege resource. Scoped to this one domain,
# not identity/* (every identity in the account).
- !Sub "arn:aws:ses:${AWS::Region}:${AWS::AccountId}:identity/seahaven.com"
# The sending identity has a default configuration set
# (seahaven-email-events); SES authorizes SendEmail against the
# config-set resource too, so it must be granted alongside the
# identity or the send is denied. Scoped to the known set name.
- !Sub "arn:aws:ses:${AWS::Region}:${AWS::AccountId}:configuration-set/seahaven-email-events"
# The domain identity covers every address under seahaven.com, so
# without this the role could send-as any @seahaven.com mailbox.
# Pin the From to the one legitimate sender (matches SES_SENDER) so
# a compromised function can't spoof internal senders (BEC).
Condition:
StringEquals:
ses:FromAddress: noreply@seahaven.com
- Effect: Allow
Action:
- sqs:SendMessage

View file

@ -1,6 +1,7 @@
"""Tests for the weekly-post Lambda handler orchestration."""
import json
from pathlib import Path
from unittest.mock import MagicMock
import pytest
@ -253,3 +254,24 @@ def test_payload_skips_fallback_and_zero(weeklypost_app):
assert payload["windowEnd"] == "2026-06-07"
assert payload["lines"] == [{"extension": "114", "amount": "75.50"}]
assert "payPeriodId" not in payload
def test_send_pay_email_skips_when_recipients_empty(weeklypost_app, monkeypatch):
monkeypatch.setenv("PAYROLL_RECIPIENTS", "")
ses = MagicMock(name="ses")
def client(svc, **kw):
if svc == "ses":
return ses
return MagicMock(name=svc)
monkeypatch.setattr(weeklypost_app.boto3, "client", client)
weeklypost_app._send_pay_email("Jun 1 to Jun 7", {"totals": {}, "breakdown": []})
ses.send_email.assert_not_called()
def test_weekly_post_payroll_recipients_empty_and_no_ses_grant():
text = (Path(__file__).resolve().parents[2] / "template.yaml").read_text()
assert 'PAYROLL_RECIPIENTS: ""' in text
assert "PAYROLL_RECIPIENTS: payroll@seahaven.com" not in text
assert "ses:SendEmail" not in text