Skip to content

Commit fb1cdf4

Browse files
authored
Add push crisis alert runtime config (#88)
1 parent 4beb1fa commit fb1cdf4

6 files changed

Lines changed: 187 additions & 8 deletions

File tree

.github/workflows/sync-cloud-run-env.yml

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ jobs:
5151
LONGBRIDGE_MIN_RESERVED_CASH_USD: ${{ vars.LONGBRIDGE_MIN_RESERVED_CASH_USD }}
5252
LONGBRIDGE_RESERVED_CASH_RATIO: ${{ vars.LONGBRIDGE_RESERVED_CASH_RATIO }}
5353
LONGBRIDGE_SAFE_HAVEN_CASH_SUBSTITUTE_THRESHOLD_USD: ${{ vars.LONGBRIDGE_SAFE_HAVEN_CASH_SUBSTITUTE_THRESHOLD_USD }}
54+
CRISIS_ALERT_CHANNELS: ${{ vars.CRISIS_ALERT_CHANNELS }}
5455
CRISIS_ALERT_EMAIL_RECIPIENTS: ${{ vars.CRISIS_ALERT_EMAIL_RECIPIENTS }}
5556
CRISIS_ALERT_EMAIL_SENDER_EMAIL: ${{ vars.CRISIS_ALERT_EMAIL_SENDER_EMAIL }}
5657
CRISIS_ALERT_EMAIL_SENDER_PASSWORD_SECRET_NAME: ${{ vars.CRISIS_ALERT_EMAIL_SENDER_PASSWORD_SECRET_NAME }}
@@ -65,6 +66,15 @@ jobs:
6566
CRISIS_ALERT_SMS_MESSAGING_SERVICE_ID: ${{ vars.CRISIS_ALERT_SMS_MESSAGING_SERVICE_ID }}
6667
CRISIS_ALERT_SMS_API_BASE_URL: ${{ vars.CRISIS_ALERT_SMS_API_BASE_URL }}
6768
CRISIS_ALERT_SMS_BODY_MAX_CHARS: ${{ vars.CRISIS_ALERT_SMS_BODY_MAX_CHARS }}
69+
CRISIS_ALERT_PUSH_RECIPIENTS: ${{ vars.CRISIS_ALERT_PUSH_RECIPIENTS }}
70+
CRISIS_ALERT_PUSH_PROVIDER: ${{ vars.CRISIS_ALERT_PUSH_PROVIDER }}
71+
CRISIS_ALERT_PUSH_APP_TOKEN_SECRET_NAME: ${{ vars.CRISIS_ALERT_PUSH_APP_TOKEN_SECRET_NAME }}
72+
CRISIS_ALERT_PUSH_ACCESS_TOKEN_SECRET_NAME: ${{ vars.CRISIS_ALERT_PUSH_ACCESS_TOKEN_SECRET_NAME }}
73+
CRISIS_ALERT_PUSH_API_BASE_URL: ${{ vars.CRISIS_ALERT_PUSH_API_BASE_URL }}
74+
CRISIS_ALERT_PUSH_DEVICE: ${{ vars.CRISIS_ALERT_PUSH_DEVICE }}
75+
CRISIS_ALERT_PUSH_PRIORITY: ${{ vars.CRISIS_ALERT_PUSH_PRIORITY }}
76+
CRISIS_ALERT_PUSH_TAGS: ${{ vars.CRISIS_ALERT_PUSH_TAGS }}
77+
CRISIS_ALERT_PUSH_BODY_MAX_CHARS: ${{ vars.CRISIS_ALERT_PUSH_BODY_MAX_CHARS }}
6878
# Optional strategy overrides; leave unset to inherit the UsEquityStrategies profile defaults.
6979
INCOME_THRESHOLD_USD: ${{ vars.INCOME_THRESHOLD_USD }}
7080
QQQI_INCOME_RATIO: ${{ vars.QQQI_INCOME_RATIO }}
@@ -75,6 +85,8 @@ jobs:
7585
TELEGRAM_TOKEN: ${{ secrets.TELEGRAM_TOKEN }}
7686
CRISIS_ALERT_EMAIL_SENDER_PASSWORD: ${{ secrets.CRISIS_ALERT_EMAIL_SENDER_PASSWORD }}
7787
CRISIS_ALERT_SMS_AUTH_TOKEN: ${{ secrets.CRISIS_ALERT_SMS_AUTH_TOKEN }}
88+
CRISIS_ALERT_PUSH_APP_TOKEN: ${{ secrets.CRISIS_ALERT_PUSH_APP_TOKEN }}
89+
CRISIS_ALERT_PUSH_ACCESS_TOKEN: ${{ secrets.CRISIS_ALERT_PUSH_ACCESS_TOKEN }}
7890
steps:
7991
- name: Check whether env sync is enabled
8092
id: config
@@ -363,6 +375,28 @@ jobs:
363375
remove_secret_vars+=("CRISIS_ALERT_SMS_AUTH_TOKEN")
364376
fi
365377
378+
if [ -n "${CRISIS_ALERT_PUSH_APP_TOKEN_SECRET_NAME:-}" ]; then
379+
secret_pairs+=("CRISIS_ALERT_PUSH_APP_TOKEN=${CRISIS_ALERT_PUSH_APP_TOKEN_SECRET_NAME}:latest")
380+
remove_env_vars+=("CRISIS_ALERT_PUSH_APP_TOKEN")
381+
elif [ -n "${CRISIS_ALERT_PUSH_APP_TOKEN:-}" ]; then
382+
env_pairs+=("CRISIS_ALERT_PUSH_APP_TOKEN=${CRISIS_ALERT_PUSH_APP_TOKEN}")
383+
remove_secret_vars+=("CRISIS_ALERT_PUSH_APP_TOKEN")
384+
else
385+
remove_env_vars+=("CRISIS_ALERT_PUSH_APP_TOKEN")
386+
remove_secret_vars+=("CRISIS_ALERT_PUSH_APP_TOKEN")
387+
fi
388+
389+
if [ -n "${CRISIS_ALERT_PUSH_ACCESS_TOKEN_SECRET_NAME:-}" ]; then
390+
secret_pairs+=("CRISIS_ALERT_PUSH_ACCESS_TOKEN=${CRISIS_ALERT_PUSH_ACCESS_TOKEN_SECRET_NAME}:latest")
391+
remove_env_vars+=("CRISIS_ALERT_PUSH_ACCESS_TOKEN")
392+
elif [ -n "${CRISIS_ALERT_PUSH_ACCESS_TOKEN:-}" ]; then
393+
env_pairs+=("CRISIS_ALERT_PUSH_ACCESS_TOKEN=${CRISIS_ALERT_PUSH_ACCESS_TOKEN}")
394+
remove_secret_vars+=("CRISIS_ALERT_PUSH_ACCESS_TOKEN")
395+
else
396+
remove_env_vars+=("CRISIS_ALERT_PUSH_ACCESS_TOKEN")
397+
remove_secret_vars+=("CRISIS_ALERT_PUSH_ACCESS_TOKEN")
398+
fi
399+
366400
secret_pairs+=("LONGPORT_APP_KEY=${LONGPORT_APP_KEY_SECRET_NAME}:latest")
367401
remove_env_vars+=("LONGPORT_APP_KEY")
368402
@@ -417,6 +451,12 @@ jobs:
417451
remove_env_vars+=("LONGBRIDGE_RESERVED_CASH_RATIO")
418452
fi
419453
454+
if [ -n "${CRISIS_ALERT_CHANNELS:-}" ]; then
455+
env_pairs+=("CRISIS_ALERT_CHANNELS=${CRISIS_ALERT_CHANNELS}")
456+
else
457+
remove_env_vars+=("CRISIS_ALERT_CHANNELS")
458+
fi
459+
420460
if [ -n "${CRISIS_ALERT_EMAIL_RECIPIENTS:-}" ]; then
421461
env_pairs+=("CRISIS_ALERT_EMAIL_RECIPIENTS=${CRISIS_ALERT_EMAIL_RECIPIENTS}")
422462
else
@@ -489,6 +529,48 @@ jobs:
489529
remove_env_vars+=("CRISIS_ALERT_SMS_BODY_MAX_CHARS")
490530
fi
491531
532+
if [ -n "${CRISIS_ALERT_PUSH_RECIPIENTS:-}" ]; then
533+
env_pairs+=("CRISIS_ALERT_PUSH_RECIPIENTS=${CRISIS_ALERT_PUSH_RECIPIENTS}")
534+
else
535+
remove_env_vars+=("CRISIS_ALERT_PUSH_RECIPIENTS")
536+
fi
537+
538+
if [ -n "${CRISIS_ALERT_PUSH_PROVIDER:-}" ]; then
539+
env_pairs+=("CRISIS_ALERT_PUSH_PROVIDER=${CRISIS_ALERT_PUSH_PROVIDER}")
540+
else
541+
remove_env_vars+=("CRISIS_ALERT_PUSH_PROVIDER")
542+
fi
543+
544+
if [ -n "${CRISIS_ALERT_PUSH_API_BASE_URL:-}" ]; then
545+
env_pairs+=("CRISIS_ALERT_PUSH_API_BASE_URL=${CRISIS_ALERT_PUSH_API_BASE_URL}")
546+
else
547+
remove_env_vars+=("CRISIS_ALERT_PUSH_API_BASE_URL")
548+
fi
549+
550+
if [ -n "${CRISIS_ALERT_PUSH_DEVICE:-}" ]; then
551+
env_pairs+=("CRISIS_ALERT_PUSH_DEVICE=${CRISIS_ALERT_PUSH_DEVICE}")
552+
else
553+
remove_env_vars+=("CRISIS_ALERT_PUSH_DEVICE")
554+
fi
555+
556+
if [ -n "${CRISIS_ALERT_PUSH_PRIORITY:-}" ]; then
557+
env_pairs+=("CRISIS_ALERT_PUSH_PRIORITY=${CRISIS_ALERT_PUSH_PRIORITY}")
558+
else
559+
remove_env_vars+=("CRISIS_ALERT_PUSH_PRIORITY")
560+
fi
561+
562+
if [ -n "${CRISIS_ALERT_PUSH_TAGS:-}" ]; then
563+
env_pairs+=("CRISIS_ALERT_PUSH_TAGS=${CRISIS_ALERT_PUSH_TAGS}")
564+
else
565+
remove_env_vars+=("CRISIS_ALERT_PUSH_TAGS")
566+
fi
567+
568+
if [ -n "${CRISIS_ALERT_PUSH_BODY_MAX_CHARS:-}" ]; then
569+
env_pairs+=("CRISIS_ALERT_PUSH_BODY_MAX_CHARS=${CRISIS_ALERT_PUSH_BODY_MAX_CHARS}")
570+
else
571+
remove_env_vars+=("CRISIS_ALERT_PUSH_BODY_MAX_CHARS")
572+
fi
573+
492574
if [ -n "${LONGBRIDGE_DRY_RUN_ONLY:-}" ]; then
493575
env_pairs+=("LONGBRIDGE_DRY_RUN_ONLY=${LONGBRIDGE_DRY_RUN_ONLY}")
494576
else

README.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ Telegram notifications include structured execution and heartbeat messages, with
7070
| `LONGBRIDGE_DRY_RUN_ONLY` | No | Set to `true` to keep the selected deployment in dry-run mode. |
7171
| `LONGBRIDGE_DEBUG_POSITION_SNAPSHOT` | No | Set to `true` to log raw LongBridge position quantity and available quantity for troubleshooting. |
7272
| `LONGBRIDGE_STRATEGY_PLUGIN_MOUNTS_JSON` | No | Optional LongBridge-side strategy plugin mount JSON. The plugin artifact controls mode; platform config must not set `mode`. |
73+
| `CRISIS_ALERT_CHANNELS` | No | Optional crisis alert channel list: `email`, `sms`, and/or `push`. |
7374
| `CRISIS_ALERT_EMAIL_RECIPIENTS` | No | Comma/semicolon/newline-separated email-form recipients. Use a normal mailbox for email-only delivery, or a Google Voice-associated mailbox/address to also trigger Google Voice prompts. |
7475
| `CRISIS_ALERT_EMAIL_SENDER_EMAIL` | No | Sender email address used for crisis alert email. Gmail is the default transport, but the sender naming is provider-neutral. |
7576
| `CRISIS_ALERT_EMAIL_SENDER_PASSWORD` | No | Sender SMTP password or app password. For Cloud Run, prefer `CRISIS_ALERT_EMAIL_SENDER_PASSWORD_SECRET_NAME` in env sync. |
@@ -86,8 +87,8 @@ Telegram notifications include structured execution and heartbeat messages, with
8687

8788
Strategy allocation can still target fractional dollar values and fractional position weights. The LongBridge execution layer now keeps a whole-share-only rule for every broker order: sell sizing floors to whole shares, buy sizing floors to whole shares, and fractional orders are skipped rather than downgraded. When a target value is zero, sell sizing uses the sellable position quantity instead of re-deriving shares from current price, so liquidation targets do not leave a residual share because of quote drift.
8889

89-
When `LONGBRIDGE_STRATEGY_PLUGIN_MOUNTS_JSON` includes the `crisis_response_shadow` plugin, the normal Telegram cycle message still includes the compact plugin line. If the plugin signal escalates beyond `no_action` (for example `canonical_route=true_crisis`, `suggested_action=defend`/`blocked`, or `would_trade_if_enabled=true`), the service also sends an independent crisis email notification when the `CRISIS_ALERT_EMAIL_*` settings are complete.
90-
Email alert results are written into the runtime report. Duplicate suppression uses stable plugin alert keys and stores markers under `STRATEGY_PLUGIN_ALERT_STATE_GCS_URI` when set, otherwise `EXECUTION_REPORT_GCS_URI`, with a local `/tmp` marker fallback.
90+
When `LONGBRIDGE_STRATEGY_PLUGIN_MOUNTS_JSON` includes the `crisis_response_shadow` plugin, the normal Telegram cycle message still includes the compact plugin line. If the plugin signal escalates beyond `no_action` (for example `canonical_route=true_crisis`, `suggested_action=defend`/`blocked`, or `would_trade_if_enabled=true`), the service also sends independent crisis alerts through configured `CRISIS_ALERT_CHANNELS` channels.
91+
Alert results are written into the runtime report. Duplicate suppression uses stable plugin alert keys and stores markers under `STRATEGY_PLUGIN_ALERT_STATE_GCS_URI` when set, otherwise `EXECUTION_REPORT_GCS_URI`, with a local `/tmp` marker fallback.
9192

9293
Secret Manager must contain the secret named by `LONGPORT_SECRET_NAME` (default: `longport_token_paper`), where the **latest version = active access token**. The app refreshes it when expiry is within 30 days.
9394

@@ -154,7 +155,7 @@ Important:
154155
- GitHub now authenticates to Google Cloud with OIDC + Workload Identity Federation, so `GCP_SA_KEY` is no longer required for this workflow.
155156
- If you deploy with `gcloud run deploy --source` or a Cloud Run source trigger, also grant `roles/storage.objectViewer` on `gs://run-sources-<project>-<region>` to the build service account, the deploy service account, and the default compute service account. Otherwise source deploy can fail before Cloud Build starts with `storage.objects.get` denied.
156157
- Here "shared" only means **shared inside this repository** between the `paper`, `HK`, and `SG` Cloud Run services. The Telegram token can still be shared, but LongPort app credentials should live in Secret Manager and be referenced by per-environment secret-name variables; they are not meant to be a global secret set reused by unrelated quant repos.
157-
- If you want one cross-project shared layer across multiple quant repos, keep it small: `GLOBAL_TELEGRAM_CHAT_ID`, `NOTIFY_LANG`, and shared crisis email settings under `CRISIS_ALERT_EMAIL_*` are reasonable when the same alert policy applies; account credentials and deployment keys are not.
158+
- If you want one cross-project shared layer across multiple quant repos, keep it small: `GLOBAL_TELEGRAM_CHAT_ID`, `NOTIFY_LANG`, `CRISIS_ALERT_CHANNELS`, and shared crisis alert settings under `CRISIS_ALERT_EMAIL_*`/`CRISIS_ALERT_PUSH_*` are reasonable when the same alert policy applies; account credentials, deployment keys, and alert secrets are not.
158159

159160
### Deployment unit and naming
160161

@@ -240,6 +241,7 @@ Telegram 通知包含结构化的调仓和心跳消息,支持中英文切换
240241
| `LONGBRIDGE_DRY_RUN_ONLY` || 设为 `true` 时,该部署保持 dry-run。 |
241242
| `LONGBRIDGE_DEBUG_POSITION_SNAPSHOT` || 设为 `true` 时输出 LongBridge 原始持仓数量和可卖数量,便于排查。 |
242243
| `LONGBRIDGE_STRATEGY_PLUGIN_MOUNTS_JSON` || 可选的 LongBridge 侧策略插件挂载 JSON。插件 artifact 自带模式;平台配置不要设置 `mode`|
244+
| `CRISIS_ALERT_CHANNELS` || 可选危机告警通道列表:`email``sms` 和/或 `push`|
243245
| `CRISIS_ALERT_EMAIL_RECIPIENTS` || 通知收件邮箱。普通邮箱只收邮件;关联 Google Voice 的邮箱/地址会额外触发 Google Voice 提醒。支持逗号、分号或换行分隔。 |
244246
| `CRISIS_ALERT_EMAIL_SENDER_EMAIL` || 通知发送方邮箱。默认传输走 Gmail SMTP,但命名不绑定 Gmail。 |
245247
| `CRISIS_ALERT_EMAIL_SENDER_PASSWORD` || 发送方 SMTP 密码或 app password。Cloud Run env sync 建议配置 `CRISIS_ALERT_EMAIL_SENDER_PASSWORD_SECRET_NAME`|
@@ -256,8 +258,8 @@ Telegram 通知包含结构化的调仓和心跳消息,支持中英文切换
256258

257259
策略分配层仍然可以按目标金额和目标比例计算出小数仓位;LongBridge 执行层只提交整数股订单,因为实测账户的 OpenAPI `submit_order` 会拒绝碎股委托数量。目标市值为 0 时,卖出数量直接按可卖整数股持仓计算,不再用当前报价反推股数,避免因报价漂移留下 1 股残仓。
258260

259-
如果 `LONGBRIDGE_STRATEGY_PLUGIN_MOUNTS_JSON` 挂载了 `crisis_response_shadow` 插件,常规策略周期 Telegram 仍会包含插件摘要行。当插件信号升级到非 `no_action`(例如 `canonical_route=true_crisis``suggested_action=defend`/`blocked`,或 `would_trade_if_enabled=true`)时,只要 `CRISIS_ALERT_EMAIL_*` 配置完整,服务还会额外发送一条独立邮件危机通知
260-
邮件告警结果会写入 runtime report。重复发送抑制使用稳定的插件告警 key;如配置了 `STRATEGY_PLUGIN_ALERT_STATE_GCS_URI` 则写入该前缀,否则复用 `EXECUTION_REPORT_GCS_URI`,并有本地 `/tmp` marker fallback。
261+
如果 `LONGBRIDGE_STRATEGY_PLUGIN_MOUNTS_JSON` 挂载了 `crisis_response_shadow` 插件,常规策略周期 Telegram 仍会包含插件摘要行。当插件信号升级到非 `no_action`(例如 `canonical_route=true_crisis``suggested_action=defend`/`blocked`,或 `would_trade_if_enabled=true`)时,服务还会按 `CRISIS_ALERT_CHANNELS` 配置额外发送独立危机通知
262+
告警结果会写入 runtime report。重复发送抑制使用稳定的插件告警 key;如配置了 `STRATEGY_PLUGIN_ALERT_STATE_GCS_URI` 则写入该前缀,否则复用 `EXECUTION_REPORT_GCS_URI`,并有本地 `/tmp` marker fallback。
261263

262264
Secret Manager 中需存在 `LONGPORT_SECRET_NAME` 指定的密钥(默认: `longport_token_paper`),**最新版本 = 当前有效的 access token**。Token 到期前 30 天会自动刷新。
263265

@@ -325,7 +327,7 @@ Secret Manager 中需存在 `LONGPORT_SECRET_NAME` 指定的密钥(默认: `lo
325327
- GitHub 现在通过 OIDC + Workload Identity Federation 登录 Google Cloud,这个 workflow 不再需要 `GCP_SA_KEY`
326328
- 如果你用 `gcloud run deploy --source` 或 Cloud Run source trigger 部署,还要给 `gs://run-sources-<project>-<region>` 这个 staging bucket 补 `roles/storage.objectViewer`,对象是 build service account、deploy service account、默认 compute service account。少了这层权限,部署会在 Cloud Build 启动前直接报 `storage.objects.get denied`
327329
- 这里的“共享”只是指 **同一个仓库里的 paper / HK / SG 服务共享**。Telegram token 可以继续共用,但 LongPort app 凭据建议放到 Secret Manager,并通过各自 Environment 里的 secret-name 变量引用,不建议把它们当成所有 quant 共用的全局 secrets。
328-
- 如果你真的要在多个 quant 仓库之间保留一层全局共享,建议只保留 `GLOBAL_TELEGRAM_CHAT_ID``NOTIFY_LANG`,以及同一套危机邮件策略下的 `CRISIS_ALERT_EMAIL_*` 这种低耦合配置。账户凭据和部署 key 不要做成全局共享。
330+
- 如果你真的要在多个 quant 仓库之间保留一层全局共享,建议只保留 `GLOBAL_TELEGRAM_CHAT_ID``NOTIFY_LANG``CRISIS_ALERT_CHANNELS`,以及同一套危机告警策略下的 `CRISIS_ALERT_EMAIL_*`/`CRISIS_ALERT_PUSH_*` 这种低耦合配置。账户凭据、部署 key 和告警 secret 不要做成全局共享。
329331

330332
### 部署单元和命名建议
331333

requirements.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
flask
22
gunicorn
3-
quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@7183145b06f8b9292e1c8f3adba0a4f5dc0a5834
4-
us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@d13b248d279887a57eef5b7692c2c7bd33906348
3+
quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@1050a678a17a997bf4776c2a4c4bef59de29e1c1
4+
us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@48f0267e3128eb7c6a8344ddefa08e0e80dc9d27
55
pandas
66
requests
77
pytz

runtime_config_support.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ class PlatformRuntimeSettings:
5454
strategy_config_path: str | None = None
5555
strategy_config_source: str | None = None
5656
strategy_plugin_mounts_json: str | None = None
57+
crisis_alert_channels: tuple[str, ...] = ()
5758
crisis_alert_email_recipients: tuple[str, ...] = ()
5859
crisis_alert_email_sender_email: str | None = None
5960
crisis_alert_email_sender_password: str | None = None
@@ -68,6 +69,15 @@ class PlatformRuntimeSettings:
6869
crisis_alert_sms_messaging_service_id: str | None = None
6970
crisis_alert_sms_api_base_url: str | None = None
7071
crisis_alert_sms_body_max_chars: str | None = None
72+
crisis_alert_push_recipients: tuple[str, ...] = ()
73+
crisis_alert_push_provider: str | None = None
74+
crisis_alert_push_app_token: str | None = None
75+
crisis_alert_push_access_token: str | None = None
76+
crisis_alert_push_api_base_url: str | None = None
77+
crisis_alert_push_device: str | None = None
78+
crisis_alert_push_priority: str | None = None
79+
crisis_alert_push_tags: str | None = None
80+
crisis_alert_push_body_max_chars: str | None = None
7181
runtime_target: RuntimeTarget | None = None
7282

7383

@@ -164,6 +174,7 @@ def load_platform_runtime_settings(
164174
os.getenv("LONGBRIDGE_STRATEGY_PLUGIN_MOUNTS_JSON")
165175
or os.getenv("STRATEGY_PLUGIN_MOUNTS_JSON")
166176
),
177+
crisis_alert_channels=_split_env_list(os.getenv("CRISIS_ALERT_CHANNELS")),
167178
crisis_alert_email_recipients=_split_env_list(os.getenv("CRISIS_ALERT_EMAIL_RECIPIENTS")),
168179
crisis_alert_email_sender_email=_first_non_empty(os.getenv("CRISIS_ALERT_EMAIL_SENDER_EMAIL")),
169180
crisis_alert_email_sender_password=_first_non_empty(
@@ -186,6 +197,17 @@ def load_platform_runtime_settings(
186197
crisis_alert_sms_body_max_chars=_first_non_empty(
187198
os.getenv("CRISIS_ALERT_SMS_BODY_MAX_CHARS")
188199
),
200+
crisis_alert_push_recipients=_split_env_list(os.getenv("CRISIS_ALERT_PUSH_RECIPIENTS")),
201+
crisis_alert_push_provider=_first_non_empty(os.getenv("CRISIS_ALERT_PUSH_PROVIDER")),
202+
crisis_alert_push_app_token=_first_non_empty(os.getenv("CRISIS_ALERT_PUSH_APP_TOKEN")),
203+
crisis_alert_push_access_token=_first_non_empty(os.getenv("CRISIS_ALERT_PUSH_ACCESS_TOKEN")),
204+
crisis_alert_push_api_base_url=_first_non_empty(os.getenv("CRISIS_ALERT_PUSH_API_BASE_URL")),
205+
crisis_alert_push_device=_first_non_empty(os.getenv("CRISIS_ALERT_PUSH_DEVICE")),
206+
crisis_alert_push_priority=_first_non_empty(os.getenv("CRISIS_ALERT_PUSH_PRIORITY")),
207+
crisis_alert_push_tags=_first_non_empty(os.getenv("CRISIS_ALERT_PUSH_TAGS")),
208+
crisis_alert_push_body_max_chars=_first_non_empty(
209+
os.getenv("CRISIS_ALERT_PUSH_BODY_MAX_CHARS")
210+
),
189211
runtime_target=runtime_target,
190212
)
191213

0 commit comments

Comments
 (0)