diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 1b7ef7b..4f05232 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -43,17 +43,23 @@ jobs: - name: SAM deploy env: ALERT_EMAIL: ${{ secrets.ALERT_EMAIL }} + STACK_ENV: prod run: | + set -euo pipefail + # EventBridge Scheduler can't resolve {{resolve:ssm-secure}} in + # HttpInvokeArgs.HeaderParameters; fetch and pass as a NoEcho param. + 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: | diff --git a/template.yaml b/template.yaml index ce818c3..9734447 100644 --- a/template.yaml +++ b/template.yaml @@ -40,6 +40,19 @@ Parameters: Default: "" Description: Email for $1 budget alert. Leave empty to skip the budget resource. + # CFN does not allow {{resolve:ssm-secure:...}} inside + # AWS::Scheduler::Schedule HttpInvokeArgs.HeaderParameters (documented + # CloudFormation limitation — secure-string dynamic refs have a fixed + # property allowlist that excludes Scheduler header parameters). CI fetches + # /miti99bot/${StackEnv}/cron-shared-secret from SSM at deploy time and + # passes it here via --parameter-overrides. NoEcho masks the value in the + # CloudFormation console. + CronSharedSecret: + Type: String + NoEcho: true + Default: "" + Description: Shared secret EventBridge Scheduler attaches as the X-Cron-Token header. Sourced from SSM by CI. + Conditions: HasAlertEmail: !Not [!Equals [!Ref AlertEmail, ""]] @@ -199,7 +212,7 @@ Resources: EndpointUrl: !Sub "${BotFunctionUrl.FunctionUrl}cron/lolschedule_daily_push" HttpMethod: POST HeaderParameters: - X-Cron-Token: !Sub "{{resolve:ssm-secure:/miti99bot/${StackEnv}/cron-shared-secret}}" + X-Cron-Token: !Ref CronSharedSecret # --- Cost guard -----------------------------------------------------------