mirror of
https://github.com/Sea-Haven-Industries/afterhours-shift-manager.git
synced 2026-09-30 06:43:12 +00:00
Fix payroll summary email (SES config-set permission) + isolate failures (#114)
* Fix payroll email: grant SES config-set permission + isolate failures The weekly pay-summary email to payroll has been failing with SES AccessDenied since 2026-06-08. The sending identity (seahaven.com) gained a default configuration set (seahaven-email-events), and SES authorizes SendEmail against the config-set ARN as well as the identity — but the WeeklyPostFunction role only granted ses:SendEmail on identity/*. - template.yaml: add the configuration-set ARN (scoped to the known set name) to the SES policy so sends are authorized again. - weekly-post/app.py: wrap _send_pay_email in try/except so a delivery failure can never abort the handler before the Slack schedule post. Previously the SES error also blocked the two-week schedule post. - Add a regression test covering the isolation. Cross-family GPT-4.1 IAM review: APPROVE. * Bump to v1.10.1 in CHANGELOG and sync App Home copy
This commit is contained in:
parent
8e90d41b6c
commit
1e1e5176a3
5 changed files with 54 additions and 2 deletions
|
|
@ -10,6 +10,15 @@ fine and still supported.
|
|||
|
||||
---
|
||||
|
||||
## v1.10.1 — June 15, 2026
|
||||
|
||||
**Payroll summary emails are sending again.** The automated weekly pay summary
|
||||
to payroll had stopped going out (an email-permissions change on our side blocked
|
||||
it from June 8 onward). Fixed the permission so the emails send, and made the
|
||||
Monday job sturdier: if the payroll email ever fails again, it no longer stops
|
||||
the on-call schedule from being posted in Slack. The two missed summaries were
|
||||
re-sent by hand.
|
||||
|
||||
## v1.10.0 — June 11, 2026
|
||||
|
||||
**The bot now tells you what's new.** Two things:
|
||||
|
|
|
|||
|
|
@ -10,6 +10,15 @@ fine and still supported.
|
|||
|
||||
---
|
||||
|
||||
## v1.10.1 — June 15, 2026
|
||||
|
||||
**Payroll summary emails are sending again.** The automated weekly pay summary
|
||||
to payroll had stopped going out (an email-permissions change on our side blocked
|
||||
it from June 8 onward). Fixed the permission so the emails send, and made the
|
||||
Monday job sturdier: if the payroll email ever fails again, it no longer stops
|
||||
the on-call schedule from being posted in Slack. The two missed summaries were
|
||||
re-sent by hand.
|
||||
|
||||
## v1.10.0 — June 11, 2026
|
||||
|
||||
**The bot now tells you what's new.** Two things:
|
||||
|
|
|
|||
|
|
@ -183,8 +183,16 @@ def handler(event, context):
|
|||
else:
|
||||
logger.warning("PAY_REPORT_USER not set — skipping Slack pay summary")
|
||||
|
||||
# Email pay summary to payroll
|
||||
_send_pay_email(week_label, pay_record)
|
||||
# Email pay summary to payroll. Isolated so a delivery failure (e.g.
|
||||
# an SES permission/identity issue) can never abort the rest of the
|
||||
# handler — the Slack schedule post below must still go out.
|
||||
try:
|
||||
_send_pay_email(week_label, pay_record)
|
||||
except Exception:
|
||||
logger.exception(
|
||||
"Failed to send pay summary email to payroll for week of %s",
|
||||
week_key,
|
||||
)
|
||||
|
||||
# --- Delete previous week's schedule post ---
|
||||
old_post = schedule.get_schedule_post(channel_id)
|
||||
|
|
|
|||
|
|
@ -138,6 +138,11 @@ Resources:
|
|||
- ses:SendEmail
|
||||
Resource:
|
||||
- !Sub "arn:aws:ses:${AWS::Region}:${AWS::AccountId}:identity/*"
|
||||
# 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"
|
||||
Events:
|
||||
# EST: 7am ET = 12:00 UTC (Nov-Mar)
|
||||
WeeklyPostEST:
|
||||
|
|
|
|||
|
|
@ -60,6 +60,27 @@ def test_calculates_and_dms_pay(weeklypost_app, schedule, seed, slack, env):
|
|||
assert dm_calls
|
||||
|
||||
|
||||
@freeze_time(MON_0800)
|
||||
def test_pay_email_failure_does_not_block_schedule_post(
|
||||
weeklypost_app, schedule, seed, slack, env, monkeypatch
|
||||
):
|
||||
# Previous week has an assigned shift, so the pay/email path runs.
|
||||
seed.config(shift_rate="50")
|
||||
seed.weekly("Monday", "114", "Alice")
|
||||
# SES delivery blows up (e.g. a permission/identity issue).
|
||||
monkeypatch.setattr(
|
||||
weeklypost_app,
|
||||
"_send_pay_email",
|
||||
MagicMock(side_effect=Exception("SES AccessDenied")),
|
||||
)
|
||||
|
||||
result = weeklypost_app.handler({"force": True}, None)
|
||||
|
||||
# The email failure is swallowed; the schedule post still goes out.
|
||||
assert result["posted"] is True
|
||||
assert schedule.get_schedule_post("C_TEST")["message_ts"] == "999.000"
|
||||
|
||||
|
||||
@freeze_time(MON_0800)
|
||||
def test_deletes_previous_schedule_post(weeklypost_app, schedule, seed, slack, env):
|
||||
seed.schedule_post("C_TEST", "111.111")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue