afterhours-shift-manager/tests/slack_bot
Adam Moussa bdff6bee30
Some checks failed
Deploy / deploy (push) Has been cancelled
Deploy / release (push) Has been cancelled
INFRA-106: nightly-sweep security remediation (auth/race/IAM) (#125)
* Fix auth and race-condition flaws in shift commands

Four confirmed findings from the 2026-06-17 security sweep:

- register_user let any Slack user overwrite an extension already
  bound to a different user (account takeover). Add a DynamoDB
  ConditionExpression so a write only succeeds when the extension is
  unclaimed or already this user's; raise ExtensionAlreadyRegistered
  otherwise and surface a clear Slack message.
- The `rate` subcommand was routed without the is_admin flag, so any
  user could set $0 pay rates. Gate _handle_rate on is_admin, matching
  the admin-command guard.
- `/oncall pick` used a plain put_item (TOCTOU): two concurrent picks
  both won. Use the atomic claim_open_shift conditional claim so the
  loser gets an "already picked up" message.
- swap-accept overwrote a shift independently claimed after the swap
  was initiated. Add reassign_if_held_by, a conditional write that only
  applies the swap while the override is still the requester's (or on
  the weekly fallback), and notify the accepter otherwise.

Add tests for the register-ownership guard and the rate admin guard.

Refs: INFRA

* Scope shift-manager Lambda IAM to least privilege

The nightly sweep flagged four over-broad permissions. Scope each to
only what the function actually reads (verified against source):

- WeeklyPost: secrets to slack-bot-token-* only (was the whole
  afterhours-shift-manager/* namespace); SES SendEmail to the single
  noreply@seahaven.com identity (was identity/*).
- RosterSync and RingScheduler: secrets to 3cx-* only (was the whole
  namespace); both read only the 3cx domain/client-id/client-secret.

SlackBotFunction and HolidayRouter wildcards are left unchanged — out
of scope for this sweep.

Refs: INFRA

* fix: re-validate shift holder on swap-accept (sh-security-review RIHB-1)

reassign_if_held_by trusted 'no override row' as 'still the requester's',
but a weekly-held shift also has no override row. An admin clear or weekly
edit between swap-init and accept could move the shift to a third party
with no override, letting the accept steal it (CWE-367, confirmed HIGH).
Re-resolve the current holder at accept and abort if it is no longer the
requester. Adds regression test + seeds the holder in existing accept tests.

* fix: complete IAM least-privilege sweep (sh-security-review)

HolidayRouter secrets scope afterhours-shift-manager/* -> /3cx-* (reads
only 3cx secrets); RingScheduler DynamoDBCrudPolicy -> DynamoDBReadPolicy
(read-only at runtime). SlackBot wildcard left as-is (reads across all
sub-prefixes; verified defensible).
2026-06-18 12:05:25 -04:00
..
conftest.py Add pytest suite and wire it into CI (#85) (#86) 2026-06-01 19:07:08 -04:00
test_app_home.py Add changelog-driven releases and App Home tab (#112) 2026-06-11 19:41:31 -04:00
test_handle_admin.py Add pytest suite and wire it into CI (#85) (#86) 2026-06-01 19:07:08 -04:00
test_handle_drop.py Lock shift drops within 24h of start (#84) (#88) 2026-06-01 19:32:40 -04:00
test_handle_holiday.py Add holiday shifts with 3CX routing and late-pickup approval (#121) 2026-06-17 11:14:29 -04:00
test_handle_holiday_actions.py Add holiday shifts with 3CX routing and late-pickup approval (#121) 2026-06-17 11:14:29 -04:00
test_handle_pick.py Add pytest suite and wire it into CI (#85) (#86) 2026-06-01 19:07:08 -04:00
test_handle_register_rate.py INFRA-106: nightly-sweep security remediation (auth/race/IAM) (#125) 2026-06-18 12:05:25 -04:00
test_handle_swap.py Add swap-acceptance (verified-swap) flow (#87) 2026-06-01 19:22:55 -04:00
test_helpers.py Lock shift drops within 24h of start (#84) (#88) 2026-06-01 19:32:40 -04:00
test_late_pickup.py Add holiday shifts with 3CX routing and late-pickup approval (#121) 2026-06-17 11:14:29 -04:00
test_parse_date.py Add pytest suite and wire it into CI (#85) (#86) 2026-06-01 19:07:08 -04:00
test_pickup_button.py Add pytest suite and wire it into CI (#85) (#86) 2026-06-01 19:07:08 -04:00
test_swap_accept_decline.py INFRA-106: nightly-sweep security remediation (auth/race/IAM) (#125) 2026-06-18 12:05:25 -04:00