Files

5.2 KiB
Raw Permalink Blame History

Отправка СМС

На ВМ выполните:

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

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"

Ожидается:

HTTP 404

2. Проверить callback с неправильного IP

curl -sS -o /dev/null -w 'HTTP %{http_code}\n' \
  -X POST \
  -H 'Content-Type: application/json' \
  --data '[]' \
  "$PUBLIC_WEB_URL/callbacks/idgtl/sms"

Ожидается:

HTTP 403

Заголовок X-Forwarded-For не должен позволять обойти ограничение.

3. Проверить Basic auth внутри Docker-сети

Credentials получает только дочерний процесс через secret launcher.

Неверные credentials:

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:

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:

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.

Дополнительно:

docker compose --env-file .env logs --since=30m nginx sms-service

Для callback должен быть ответ 204. Только реальный запрос Direct может полноценно подтвердить IP allowlist.