Files
han-app/ops-monitoring/send_sms.md
T

202 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Отправка СМС
## На ВМ выполните:
cd /opt/han-chat/backend
umask 077
REQUEST_FILE=$(mktemp)
read -r -p "Тестовый номер в E.164 (+79...): " TEST_PHONE
python3 - "$REQUEST_FILE" "$TEST_PHONE" <<'PY'
import json
import secrets
import sys
import uuid
challenge_id = str(uuid.uuid4())
payload = {
"idempotency_key": f"ops:smoke:{challenge_id}",
"template_code": "auth_otp",
"locale": "ru",
"phone_e164": sys.argv[2],
"substitutions": {
"code": f"{secrets.randbelow(1000000):06d}",
"ttl_min": "1",
},
"customer_ref": challenge_id,
"message_ttl_sec": 60,
}
with open(sys.argv[1], "w", encoding="utf-8") as file:
json.dump(payload, file, ensure_ascii=False)
PY
## Создайте функцию отправки:
send_sms_smoke() {
deployment/secrets/han-secrets run --config .env -- \
docker compose --env-file .env --profile ops run --rm --no-deps \
--user 0:0 \
--entrypoint sh \
-v /run/han-chat/secrets/SMS_SERVICE_TOKEN:/run/secrets/sms_service_token:ro \
-v "$REQUEST_FILE:/tmp/sms-request.json:ro" \
toolbox -ec '
umask 077
printf "Authorization: Bearer %s\n" \
"$(cat /run/secrets/sms_service_token)" > /tmp/auth-header
curl -sS \
-w "\nHTTP %{http_code}\n" \
-X POST \
-H @/tmp/auth-header \
-H "Content-Type: application/json" \
-H "X-Request-ID: ops-sms-smoke" \
--data-binary @/tmp/sms-request.json \
http://sms-service:8080/internal/sms/v1/send
'
}
## Отправка:
send_sms_smoke
Ожидается:
HTTP 202 и JSON с sms_message_id.
## Проверьте журнал:
SELECT
id,
phone_masked,
send_status,
delivery_status,
provider_message_id,
provider_error_code,
attempt_count,
created_at
FROM sms.sms_outbound_message
ORDER BY created_at DESC
LIMIT 5;
## После проверки удалите секретные данные:
shred -u "$REQUEST_FILE" 2>/dev/null || rm -f "$REQUEST_FILE"
unset TEST_PHONE REQUEST_FILE
# Тесты
Выполняйте на ВМ из `/opt/han-chat/backend`.
### 1. Проверить запрет публичного internal API
```bash
PUBLIC_WEB_URL=$(python3 - <<'PY'
from pathlib import Path
for line in Path(".env").read_text().splitlines():
if line.startswith("PUBLIC_WEB_URL="):
print(line.split("=", 1)[1].strip().strip("\"'"))
break
PY
)
curl -sS -o /dev/null -w 'HTTP %{http_code}\n' \
"$PUBLIC_WEB_URL/internal/sms/v1/messages/00000000-0000-0000-0000-000000000000"
```
Ожидается:
```text
HTTP 404
```
### 2. Проверить callback с неправильного IP
```bash
curl -sS -o /dev/null -w 'HTTP %{http_code}\n' \
-X POST \
-H 'Content-Type: application/json' \
--data '[]' \
"$PUBLIC_WEB_URL/callbacks/idgtl/sms"
```
Ожидается:
```text
HTTP 403
```
Заголовок `X-Forwarded-For` не должен позволять обойти ограничение.
### 3. Проверить Basic auth внутри Docker-сети
Credentials получает только дочерний процесс через secret launcher.
Неверные credentials:
```bash
deployment/secrets/han-secrets run --config .env -- \
docker compose --env-file .env --profile ops run --rm --no-deps \
--entrypoint sh toolbox -ec '
curl -sS -o /dev/null -w "HTTP %{http_code}\n" \
-u invalid:invalid \
-H "Content-Type: application/json" \
--data "[]" \
http://sms-service:8080/callbacks/idgtl/sms
'
```
Ожидается `HTTP 401`.
Правильные credentials:
```bash
deployment/secrets/han-secrets run --config .env -- \
docker compose --env-file .env --profile ops run --rm --no-deps \
--entrypoint sh \
-v /run/han-chat/secrets/IDGTL_SMS_CALLBACK_USERNAME:/run/secrets/callback_user:ro \
-v /run/han-chat/secrets/IDGTL_SMS_CALLBACK_PASSWORD:/run/secrets/callback_password:ro \
toolbox -ec '
umask 077
{
printf "user = \"%s:%s\"\n" \
"$(cat /run/secrets/callback_user)" \
"$(cat /run/secrets/callback_password)"
} > /tmp/curl-auth.conf
curl -sS -o /dev/null -w "HTTP %{http_code}\n" \
--config /tmp/curl-auth.conf \
-H "Content-Type: application/json" \
--data "[]" \
http://sms-service:8080/callbacks/idgtl/sms
'
```
Ожидается `HTTP 422`: авторизация прошла, но пустой callback-массив невалиден.
### 4. Проверить реальный callback Direct
После тестовой SMS:
```sql
SELECT
id,
send_status,
delivery_status,
provider_message_id,
callback_last_at,
sent_at,
delivered_at
FROM sms.sms_outbound_message
ORDER BY created_at DESC
LIMIT 5;
```
Успешный реальный callback подтверждается:
- `callback_last_at IS NOT NULL`;
- `delivery_status = sent` или `delivered`;
- заполняются `sent_at`/`delivered_at`.
Дополнительно:
```bash
docker compose --env-file .env logs --since=30m nginx sms-service
```
Для callback должен быть ответ `204`. Только реальный запрос Direct может полноценно подтвердить IP allowlist.