feat(deploy): wire lolschedule cron via EventBridge Rule + ApiDestination

CloudFormation's AWS::Scheduler::Schedule Target schema has no property
for HTTPS universal invocation (URL, method, headers) — confirmed
against AWS docs. Switch to the legacy EventBridge Rule path which
supports HTTP targets natively via ApiDestination:

- AWS::Events::Connection: API_KEY auth, presents X-Cron-Token header.
  ApiKeyValue stored in EventBridge service-linked secret on stack
  update (no per-invoke SSM fetch, AWS-managed secret fees).
- AWS::Events::ApiDestination: POST to ${FunctionUrl}cron/lolschedule_daily_push.
- AWS::Events::Rule: cron(0 1 * * ? *) — daily 01:00 UTC / 08:00 ICT.
  Targets ApiDestination with retry x2, 600s max age, DLQ to CronDLQ.
- EventBridgeInvokeRole replaces SchedulerExecutionRole (events.amazonaws.com
  principal, events:InvokeApiDestination scoped to this destination only).

NoEcho CronSharedSecret CFN parameter restored; GHA fetches the SSM
SecureString and passes via --parameter-overrides so the value never
appears in template source or stack events.

Free-tier preserved: 1 invocation/day, well under EventBridge Rules +
ApiDestinations free quotas.
This commit is contained in:
2026-05-18 15:14:06 +07:00
parent e93a2750a2
commit 539e5bbefa
5 changed files with 410 additions and 18 deletions
+16 -8
View File
@@ -43,17 +43,25 @@ jobs:
- name: SAM deploy
env:
ALERT_EMAIL: ${{ secrets.ALERT_EMAIL }}
STACK_ENV: prod
run: |
set -euo pipefail
# EventBridge Connection consumes ApiKeyValue at stack-update time
# and stores it in a service-linked secret. SSM holds the canonical
# value; fetch here and pass as a NoEcho CFN parameter so it never
# appears in template source or stack events.
CRON_SECRET=$(aws ssm get-parameter \
--name "/miti99bot/${STACK_ENV}/cron-shared-secret" \
--with-decryption --query Parameter.Value --output text)
echo "::add-mask::$CRON_SECRET"
OVERRIDES="CronSharedSecret=$CRON_SECRET"
if [ -n "$ALERT_EMAIL" ]; then
sam deploy --template-file template.yaml \
--no-confirm-changeset \
--no-fail-on-empty-changeset \
--parameter-overrides "AlertEmail=$ALERT_EMAIL"
else
sam deploy --template-file template.yaml \
--no-confirm-changeset \
--no-fail-on-empty-changeset
OVERRIDES="$OVERRIDES AlertEmail=$ALERT_EMAIL"
fi
sam deploy --template-file template.yaml \
--no-confirm-changeset \
--no-fail-on-empty-changeset \
--parameter-overrides "$OVERRIDES"
- name: Smoke test (Function URL responds)
run: |