Files
han-app/codebase/services/bitrix-sync/README.md
T

4.5 KiB
Raw Blame History

bitrix-sync

Изолированный Python 3.12 сервис durable-синхронизации Contact между han_app и Битрикс24. Сервис не участвует в Open Lines и не имеет HTTP-зависимости от api-backend.

Entrypoints

  • han-bitrix-sync-api — health, internal status и два bounded robot receiver;
  • han-bitrix-sync-worker — queue/webhook/rebind workflows с lease fencing;
  • han-bitrix-sync-reconciliation — один advisory-lock incremental run;
  • alembic upgrade head — отдельная контролируемая миграция, не startup DDL.

Disabled mode требует только BITRIX_SYNC_ENABLED=false и BITRIX_SYNC_MODE=disabled, не читает БД и не принимает webhook. Full mode валидирует весь каталог secret files, portal identity, custom fields, HTTPS host lock и непустой CIDR allow-list до startup.

Границы безопасности

  • CRM credential URL используется как единый секрет; redirect выключен, TLS проверяется, REST method выбирается только из закрытого allow-list.
  • Receiver принимает только application/x-www-form-urlencoded с bounded content length, числом и длиной полей. Query token сравнивается constant-time.
  • nginx должен перезаписывать X-Real-IP из TCP peer, проверять CIDR до proxy и не логировать $request_uri, args или body. Контейнер receiver недоступен напрямую.
  • DB хранит только hash CRM-master значений в snapshot; safe command projection не содержит PII. URL credential, form body и token не логируются.
  • Запись CRM-master полей выполняется в одной транзакции после SET LOCAL han.sync_suppress='true'.

Локальные проверки

Лёгкие проверки, не требующие Docker, сервиса или реального PostgreSQL:

python -m pytest
python -m ruff check app tests

PostgreSQL integration и Bitrix contract suites намеренно являются внешними gates: локальный managed PostgreSQL не поднимается Compose-файлом.

External gates до BITRIX_SYNC_ENABLED=true

  1. Применить migrations migration-role и проверить grants runtime-role.
  2. На disposable managed PostgreSQL проверить concurrent SKIP LOCKED, lease expiry/fencing, active mapping uniqueness, rebind partial failure, transaction-local GUC без утечки и crash после CRM success.
  3. Подтвердить на целевом портале wire-контракты duplicate.findbycomm, Contact add/get/update, mixed batch, custom fields, enum dictionary и crm.item.list с opened=1, registration REST field =1.
  4. Заполнить и активировать валидную business_alerts settings version: entity/category/stage/field IDs и responsible party. Placeholder null запрещает alert receiver.
  5. Проверить least-privilege credential negative tests; credential администратора запрещён.
  6. Валидировать nginx exact routes, no-redirect HTTP policy, body/rate limits, version-controlled CIDR и отсутствие query/body в access/error/traces.
  7. Запустить synthetic webhook с реальным robot form contract, затем убедиться, что durable inbox commit предшествует 202.
  8. Выполнить 10k incremental reconciliation/load gate, webhook-loss recovery, 429/5xx/TLS/DNS/timeout/uncertain-create и restart-at-each-step tests.
  9. Проверить container image digest, dependency/SBOM/vulnerability scan и compose hardening; root Compose ВМ2 подключает этот fragment отдельно.
  10. Зафиксировать cutover watermark, отменить только pre-cutover active tasks, выполнить disabled preflight и затем controlled enablement.

compose.fragment.yaml — сервисный фрагмент, не root Compose и не команда развёртывания. Reconciliation entrypoint выполняет один run; расписание задаёт root-owned scheduler/deployment layer.