Введение
26 сентября была запущена небольшая компания, все операции в которой управляются агентами Claude Code по расписанию GitHub Actions. Логи и журнал транзакций проекта находятся в открытом доступе. Первый же день работы принес пять программных ошибок. Ни одна из них не была экзотической, и для каждой потребовалось изменение всего в одну строку кода. Примечательно, что три из пяти багов не были обнаружены автоматическими тестами и прошли все проверки.
Ошибка 403 Forbidden при публикации на dev.to
Первая проблема возникла при попытке публиковать статьи на платформу dev.to через её API с использованием стандартной библиотеки Python urllib. Запрос завершался ошибкой HTTP Error 403: Forbidden. Причина оказалась в стандартном заголовке User-Agent, который отправляет urllib (например, Python-urllib/3.x). Платформа dev.to блокирует такие запросы, считая их нежелательными ботами.
Решение заключалось в явном указании собственного, информативного User-Agent. Это не только решает проблему с блокировкой, но и является хорошей практикой для идентификации вашего сервиса.
Исправленный код:
req = urllib.request.Request(
url, data=body, method="POST",
headers={
"Content-Type": "application/json",
"User-Agent": "company-publisher/1.0 (+https://example.com)",
"api-key": key,
},
)
Этот баг был обнаружен при первом реальном запуске. Он оставался незамеченным тестами, потому что скрипт логировал ошибку, но завершал работу с кодом 0 (успех). Это было сделано для того, чтобы следующий шаг в CI/CD-пайплайне мог зафиксировать успешно опубликованные посты. Для исправления этого поведения в логи GitHub Actions стали добавляться специальные аннотации об ошибках (::error title=...), которые гарантированно подсвечивают сбой на странице запуска.
Проблемы с кодировкой на Windows
Вторая и третья ошибки были связаны с кодировками и проявлялись только при запуске на Windows, в то время как на Linux-машинах в CI/CD все работало идеально.
-
UnicodeEncodeError для символа '→'. Скрипт казначейства записывал Markdown-файл с состоянием, содержащий символ стрелки '→'. На Linux это проходило без проблем, но на Windows вызывало крах с ошибкой
UnicodeEncodeError: 'charmap' codec can't encode character '→'. По умолчанию функцииPath.write_text()иopen()используют системную кодировку, которая на Windows часто являетсяcp1252и не поддерживает многие Unicode-символы.Решение: Явно указывать кодировку UTF-8 при всех операциях с файлами.
Исправленный код:
STATE_MD.write_text(render_state_md(s), encoding="utf-8") with LEDGER.open(newline="", encoding="utf-8") as f: # ... -
Тихий пропуск файлов при чтении. Более коварная версия этой же проблемы возникала на этапе сборки, где скрипт читал текстовые файлы для их «очистки» от брендов. Файлы открывались в кодировке
cp1252, и при встрече с неразрешимыми байтами они молча пропускались, что приводило к неполной сборке.
Для унификации поведения в тестах, запускающих подпроцессы на Windows, было решено принудительно включать режим UTF-8 для всего процесса через переменную окружения PYTHONUTF8.
env={**os.environ, "PYTHONUTF8": "1"}
Эти проблемы были выявлены во время "smoke test" — дымового тестирования продукта на реальном оборудовании, а не в изолированной среде CI.
Оставшиеся три бага
Хотя исходный текст обрывается на описании второго типа проблем, он упоминает, что всего было зафиксировано пять подобных инцидентов. Общая тенденция, прослеживаемая на этих примерах, показывает уязвимости, возникающие на стыке разных сред выполнения (локальная разработка, CI/CD на Linux, конечные пользователи на Windows) и на границе взаимодействия с внешними API. Все они подчеркивают важность явного управления конфигурацией, будь то HTTP-заголовки или кодировки файлов, вместо полагания на ненадежные значения по умолчанию.