Попробовать API
</>
Zero-deps SDK BOTIX: подключение, ключи, open-source
sdkИнструкция
15 мин

Zero-deps SDK BOTIX: подключение, ключи, open-source

SDK с десятком зависимостей — это десяток будущих CVE в вашем `requirements.txt`. TL;DR: три SDK BOTIX (PHP, Python, Node) собраны без транзитивных пакетов, ключ хранится только через ENV и secret manager, а исходники лежат открытыми на GitHub. Ниже — установка построчно, семь антипаттернов работы с ключами и чек-лист код-ревью.

Коротко

  • Zero-deps. Все три SDK не тянут ни одной транзитивной зависимости: HTTP из stdlib, JSON из stdlib, UUID и HMAC из stdlib. composer audit / npm audit / safety check зелёные по дизайну, а не по везению.
  • Ключ = бессрочный пароль. Семь антипаттернов (ключ в репо, в .env, в логах, в URL, без ротации, без scope, один на всех) закрываются одной схемой: secret manager → ENV → SDK, маскирование в логах, отдельный ключ с минимальным scope на каждый сервис.
  • Open-source — не подарок, а инструмент. Открытый код SDK снимает блокировку security-команды без NDA и SOC 2, разблокирует bug fix через PR/форк и работает как сигнал зрелости API. При этом архитектуру API он не раскрывает: бизнес-логика остаётся на api.botix.pro.

Почему 14 зависимостей в SDK — технический долг интегратора

SDK для публичного API — это не приложение, а тонкая обёртка над HTTP: сформировать запрос, подписать, распарсить ответ. Каждая зависимость этой обёртки становится головной болью того, кто её установит.

Команда подключает сторонний API. Видит на странице документации pip install vendor-sdk / composer require vendor/sdk / npm install @vendor/sdk, ставит — и через минуту в requirements.txt или composer.lock появляется не одна новая строка, а четырнадцать. SDK притащил HTTP-клиент, JSON-валидатор, UUID-библиотеку, retry-механизм, ещё один логгер и пару утилитарных пакетов от одного мейнтейнера «в свободное время». Каждая из них создаёт ровно три класса проблем.

Конфликт версий. SDK тянет requests==2.28.0, а у вас в проекте уже requests==2.31.0 из-за собственного фреймворка. Жёсткий pin — установка падает с конфликтом. Мягкий (>=2.20,<3.0) — установится одна из совместимых версий, и обновление основного фреймворка через полгода может сломать совместимость с SDK. В Python особенно больно: глобальное пространство имён не даёт держать две версии requests одновременно. В Node чуть легче за счёт node_modules per-package, но дубли раздувают бандл.

Supply-chain атаки. Каждая транзитивная зависимость — вектор атаки. event-stream в npm — мейнтейнер передал доступ незнакомцу, тот добавил код кражи криптокошельков. ua-parser-js — взлом аккаунта, релиз с майнером. colors.js — «протест-релиз», ломающий всё зависящее. PyPI и Composer — те же истории меньшего масштаба. Когда SDK тянет 14 пакетов, дерево транзитивных может перевалить за 100, и ваш npm audit / safety check начинает регулярно ругаться на advisories в зависимостях зависимостей — а фиксить их вы не можете, потому что не контролируете SDK, через который они пришли.

Устаревание. Зависимость, что год назад была свежей, сегодня имеет известную CVE. Активно поддерживаемый SDK обновляет их — нормальный жизненный цикл. Заброшенный — каждая зависимость становится миной под интегратором.

В BOTIX все три SDK построены по принципу zero-dependency: только стандартная библиотека языка. В PHP — curl через штатное расширение. В Python — urllib.request из stdlib. В Node — встроенные https/http. JSON-сериализация, UUIDv4 и HMAC для верификации webhook — тоже из stdlib. Возражение «но requests удобнее urllib» справедливо для прикладного кода. SDK — не прикладной код: он живёт в продакшене интегратора, и его задача не быть красивым, а минимизировать риск. «Нет 14 проблем с зависимостями» перевешивает «синтаксис чуть приятнее».

PHP, Python, Node — установка без единой зависимости

Порядок одинаковый для всех трёх языков: поставить пакет, прочитать ключ из ENV, сделать первый запрос, проверить дерево зависимостей.

1. PHP — composer require botix-pro/sdk. github.com/BOTIX-pro/sdk-php/blob/main/composer.json:

json
{
    "require": {
        "php": "^8.1",
        "ext-curl": "*",
        "ext-json": "*"
    }
}

Кроме самого PHP и двух стандартных расширений — ничего. Установка:

bash
composer require botix-pro/sdk:^1.1

Использование (ключ — только из ENV):

php
<?php
require __DIR__ . '/vendor/autoload.php';

use Botix\SDK\Client;

$client = new Client(apiKey: getenv('BOTIX_API_KEY'));

$contact = $client->contacts()->create([
    'phone' => '+79991234567',
    'name'  => 'Test',
]);

echo $contact['id'];

Внутри HTTP — через curl_exec, JSON — через json_encode/json_decode, UUIDv4 — собственная реализация на 6 строк через random_bytes(16). Проверка дерева:

bash
composer show --tree
# botix-pro/sdk 1.1.0
# └── php >=8.1

На фоне Guzzle (psr/http-client + psr/http-factory + psr/http-message + ralouphie/getallheaders + symfony/deprecation-contracts) разница очевидна.

2. Python — pip install botix. github.com/BOTIX-pro/sdk-python/blob/main/setup.py:

python
setup(
    name="botix",
    version="1.1.0",
    install_requires=[],  # пусто
    python_requires=">=3.8",
)

install_requires=[] — пустой список. SDK использует только stdlib: urllib.request для HTTP, json для сериализации, hmac и hashlib для верификации webhook, uuid для идемпотентности. Никакого requests, httpx, pydantic.

bash
pip install botix

Использование:

python
import os
from botix import Client

client = Client(api_key=XXXXXXXX["BOTIX_API_KEY"])

contact = client.contacts.create(
    phone="+79991234567",
    name="Test",
)
print(contact.id)

Дерево зависимостей:

bash
pip show botix | grep Requires
# Requires:

Пусто. pip list после установки покажет только сам botix. safety check не выдаёт новых CVE-предупреждений.

3. Node — npm install @botix/sdk. github.com/BOTIX-pro/sdk-node/blob/main/package.json:

json
{
    "name": "@botix/sdk",
    "version": "1.1.0",
    "dependencies": {},
    "devDependencies": {
        "typescript": "^5.0",
        "vitest": "^1.0"
    }
}

dependencies пустые. devDependencies — только билд-инструменты, в node_modules пользователя не попадают. HTTP — встроенные https и http, JSON — JSON.parse/JSON.stringify, HMAC — встроенный crypto.

bash
npm install @botix/sdk

Использование:

javascript
const { Client } = require('@botix/sdk');

const client = new Client({ apiKey: XXXXXXXX });

const contact = await client.contacts.create({
    phone: '+79991234567',
    name: 'Test',
});
console.log(contact.id);
bash
npm ls
# my-app@1.0.0
# └── @botix/sdk@1.1.0

Без вложенных. На фоне axios (follow-redirects + form-data + proxy-from-env + транзитивные) разница в размере node_modules заметная: установка @botix/sdk добавляет 30–40 КБ, а не 2 МБ. Структура методов у всех трёх SDK одинаковая — client.contacts.create(...) выглядит идентично в PHP, Python и Node, потому что все три генерируются из одного openapi.yaml. Подробнее про генерацию из спецификации — в разборе zero-deps SDK: генерация из OpenAPI и open-source и SDK BOTIX 1.1: zero-deps, генерация из OpenAPI, триал.

Семь антипаттернов хранения API-ключа

API-ключ — это аналог пароля, написанного в открытом виде. У него по умолчанию нет срока действия, защиты вторым фактором, попыточного лимита. Любой, кто получит ключ, делает всё, что доступно тарифу проекта: читает контакты, рассылает сообщения, меняет сценарии, удаляет данные. Формат ключа в BOTIX — Authorization: Bearer XXXXXXXX… (40 символов), каждый ключ привязан к одному project_id. Компрометация одного ключа — это не «инцидент в фиче», а потенциально полный slave проекта на платформе.

Большинство утечек происходит не из-за изощрённого взлома, а из-за стандартных антипаттернов. Их семь, и каждый встречается даже в зрелых командах.

  1. Ключ в репозитории. Разработчик пишет $key = 'btx_live_XXXX…'; прямо в конфиге, коммитит. Через неделю репозиторий становится публичным (open-source, переезд, бэкап) — ключ у всех. Секрет-сканеры (GitHub Secret Scanning, GitLab Secret Detection) ловят паттерн btx_live_… и уведомляют владельца за часы — но за эти часы базу контактов уже успевают выгрузить.
  2. Ключ в .env без шифрования. Файл лежит на диске в plaintext. RCE-уязвимость, бэкап-копия или увольнённый админ — и ключи у всех разом. Классика: Docker-образ, попавший в публичный реестр с забытым .env внутри. .env — приемлемое место для *переменной*, но не для *хранения*.
  3. Один ключ на всю команду. Master-ключ в Slack. Через два года ушли пятеро, при увольнении ключ не ротировался — любой бывший сотрудник может вернуться и навредить.
  4. Ключ в логах. error_log('Request: ' . print_r($headers, true)); — и в логах полный Authorization: Bearer XXXXXXXX…. Логи уходят в ELK/Loki/Datadog, где их видят все с доступом к мониторингу. Полу-публичная утечка.
  5. Ключ в URL. https://api.example.com/contacts?api_key=… — попадает в access.log nginx, логи прокси и Referer при переходах на третьи ресурсы. Платформа BOTIX категорически не принимает ключ через query-string, только через Authorization: Bearer — это закреплено явной проверкой источника заголовка в app/Middleware/PublicApiAuth.php.
  6. Ключ без ротации. Тот же ключ два года: сменилась половина команды, прошли рефакторинги, был инцидент «с подозрением, но не точно». Бессрочный пароль — чем дольше живёт, тем выше шанс, что уже утёк. Гигиена: плановая ротация раз в 6 месяцев плюс внеплановая после любого подозрения, с двумя состояниями (новый работает, старый ещё не отозван) для безболезненного свитча.
  7. Ключ с избыточными правами. Сервис, который только шлёт сообщения, использует ключ с полным набором прав. Контрмера — scopes на уровне ключа. У BOTIX scopes — JSON-поле в таблицах btx_api_keys и btx_oauth_access_tokens. При создании ключа на app.botix.pro/developers указывается список scope, middleware проверяет соответствие при каждом запросе; без нужного — 403 INSUFFICIENT_SCOPE. Сервису для рассылки выдаётся ключ с messages:send — при компрометации никаких побочных эффектов вроде DELETE /contacts.

Нормальная схема: secret manager → ENV → SDK

Схема, закрывающая все семь антипаттернов сразу:

  • Источник правды — secret manager (HashiCorp Vault, AWS Secrets Manager, Yandex Lockbox; в простом случае — pass поверх gpg). Ключ хранится зашифрованным, доступ выдаётся ролям, у каждого доступа — audit-лог.
  • При деплое скрипт читает ключ из secret manager и подставляет в ENV процесса. Файл .env в репозитории отсутствует или содержит только placeholder'ы. Контейнер пересобирается без ключа — ключ инжектится в момент запуска: docker run -e BOTIX_API_KEY=... или через Kubernetes Secret.
  • SDK читает ключ из ENV (os.environ, getenv, process.env). В коде нет строковой константы, конфига или файла с ключом. Если ENV не установлен — SDK падает на старте с понятной ошибкой. Примеры инициализации на PHP/Python/Node лежат на developers.botix.pro/best-practices.
  • В логах ключ маскируется. SDK BOTIX делают это автоматически: при сериализации заголовков для логирования значение Authorization заменяется на Bearer ***. Если код пишется руками — правило проговаривается в код-ревью.
  • В URL ключ не передаётся. Каждый сервис — свой ключ с минимальным scope. Ротация — раз в полгода либо по событию.
  • Audit-лог. Каждый запрос пишется в btx_api_log, журнал API на app.botix.pro/developers показывает, что именно шло с каждого ключа. Если ключ внезапно начал делать DELETE /contacts, хотя в норме шлёт только POST /messages, — это видно сразу, и ключ отзывается до масштабного ущерба.

Чек-лист для код-ревью или security-аудита — семь проверок по минуте каждая:

  • .env в .gitignore.
  • В исходниках нет строк, начинающихся с btx_live_.
  • Конфиг читает ключ через getenv() или эквивалент.
  • SDK инициализируется один раз на старте процесса, не на каждом запросе.
  • В логах headers фильтруются — нет полного значения Authorization.
  • URL'ы не содержат ключа.
  • На каждый сервис — отдельный ключ, имя сервиса записано в поле name таблицы btx_api_keys.

Прохождение чек-листа — не паранойя, а уровень гигиены, ниже которого работать с публичным API в продакшене нельзя. Про выбор Authorization: Bearer против OAuth-токена и когда что применять — в разборе OAuth 2.0 vs API-key в SaaS-интеграциях и multi-tenant: один SDK на 100 ботов.

Зачем компании открывать исходный код SDK

Открытый код SDK обычно обсуждают через категорию «щедрость»: «принесём пользу сообществу» против «потратим время на фичи». В таком виде обсуждение буксует, потому что стороны спорят о морали, а не о функциях. На деле open-source SDK решает четыре конкретные задачи, которые закрытый SDK либо не решает, либо решает дорого.

Функция 1: security-аудит без участия поставщика. Корпоративная интеграция почти всегда проходит через security-команду. Закрытая библиотека для них — чёрный ящик, который что-то делает с данными. Дальше три дорогих варианта: заблокировать интеграцию (частый исход), потребовать SOC 2 Type II + ISO 27001 + DPA (десятки тысяч долларов и месяцы поставщику), либо запросить исходник под NDA (недели процедуры). Open-source закрывает все три: security открывает GitHub-репозиторий, видит, что библиотека делает только заявленное, и пропускает интеграцию. SOC 2 при этом всё равно нужен — но для инфраструктуры и процессов, а не для точки входа в собственный код.

Функция 2: bug fix не блокируется вендором. В закрытом SDK любая ошибка — тикет в поддержку и новая версия через месяц-три, всё это время у интегратора костыль. В открытом — два пути: PR с фиксом в upstream либо временный форк, который патчится через VCS-ссылку в composer.json/package.json, пока PR не приняли. Никакой блокировки.

Функция 3: сигнал зрелости API. Публикация SDK под открытой лицензией читается как «у API есть стабильный контракт, который не стыдно показать». Закрытый SDK часто прочитывается как «наколхозили, поэтому прячут» — не обязательно правда, но влияет на восприятие. Сигнал работает не на сознательном уровне: инженер посмотрел репозиторий, не нашёл ничего стыдного — и покупатель формулирует «серьёзные люди».

В BOTIX сигнал встроен в стратегию SDK с самого начала: три SDK, CLI и три example-репозитория выложены на GitHub в организацию BOTIX-pro под открытой лицензией, пакеты опубликованы в Composer, PyPI и npm:

composer require botix-pro/sdk:^1.1
pip install botix==1.1.0
npm install @botix/sdk@1.1.0

Полная карта репозиториев:

РепоПакет
sdk-phpComposer botix-pro/sdk
sdk-pythonPyPI botix
sdk-nodenpm @botix/sdk
cliPyPI botix-cli
example-laravelLaravel 11 + Pest
example-expressExpress 4 + TypeScript + Vitest
example-flaskFlask 3 + pytest

Функция 4: контрибьюции от сообщества. На старте open-source SDK — односторонняя отдача: поставщик пишет, сообщество потребляет. По мере роста появляются PR на retry, timeout, прокси, совместимость с нетипичной версией зависимости — часы, которые поставщик не потратил. У зрелых SDK (Stripe, Twilio, Slack) — десятки внешних контрибьюторов; у молодых — единицы или ноль, и это нормально. SDK BOTIX молодые, контрибьюций пока нет, оценка — через 90 дней после релиза.

Открытость не раскрывает архитектуру API — при одном условии: SDK не содержит бизнес-логики. Он делает ровно три вещи — формирует запрос, подписывает, парсит ответ. Индекс категорий, бизнес-правила, расчёты остаются на стороне api.botix.pro. При такой дисциплине открытый код показывает только формат работы с публичным API, который и так лежит в OpenAPI-спецификации. Утащить SDK в чужой продукт бессмысленно: без своего API он бесполезен.

Подводные камни и когда open-source не нужен

Честно про издержки, чтобы не выглядело маркетингом.

HTTP-клиент в stdlib чуть менее удобен. На Python — urllib.request.Request вместо однострочного requests.get. Внутри SDK это закрыто; если пишете на голом HTTP — примите немного больше кода. Цена за ноль зависимостей.

Тесты SDK сложнее. Моки HTTP-вызовов через урезанный stdlib-клиент пишутся вручную. Это проблема разработчиков SDK, не интеграторов, и она снята генерацией из единого openapi.yaml: шаблоны настроены один раз, структура кода идентична во всех трёх языках.

Поддержка публичного репозитория — реальная работа. Входящие issues без выделенного человека превращают SDK в кладбище с просрочкой по 200 дней — антиреклама. В BOTIX этот пункт в фазе становления.

Open-source нужен не всякому API. Если API нишевой и аудитория — два-три интегратора по NDA; если API в стадии активного breaking-change (сообщество увидит нестабильность в публичном репозитории — сигнал, обратный ожидаемому); если нет человека на review PR и ответы на issues — открытие ухудшит ситуацию. Все три условия — про ранние стадии; когда продукт зреет и аудитория растёт, закрытый SDK становится якорем роста.

Проверяйте размер dependencies перед установкой любого SDK. 0–2 пакета — SDK с уважением к интегратору. 5–7 — приемлемо, но убедитесь, что это мейнстрим, а не маргинальные пакеты от одного автора. 10+ — SDK, который кладёт на вас груз чужой экосистемы.