Commit graph

28 commits

Author SHA1 Message Date
f2945b7157 fix(ci): деплой падает громко, если :latest отстаёт от головы по компоненту (#2950) (#3023)
All checks were successful
Deploy / changes (push) Successful in 9s
Deploy Trade-In / changes (push) Successful in 15s
Deploy / deploy-caddy (push) Has been skipped
Deploy Trade-In / build-browser (push) Successful in 57s
Deploy / build-backend (push) Successful in 1m2s
Deploy / build-frontend (push) Successful in 1m8s
Deploy / build-worker (push) Successful in 1m9s
Deploy / deploy (push) Successful in 1m58s
Deploy / deploy-status (push) Successful in 3s
Deploy Trade-In / build-frontend (push) Successful in 3m14s
Deploy / perimeter-smoke (push) Successful in 14s
Deploy Trade-In / test (push) Successful in 4m12s
Deploy Trade-In / build-backend (push) Successful in 33s
Deploy Trade-In / deploy (push) Successful in 2m16s
Deploy Trade-In / deploy-status (push) Successful in 1s
Deploy Trade-In / perimeter-smoke (push) Successful in 9s
2026-08-21 12:19:07 +00:00
bot-backend
2d2336cd51 fix(ops): деплой триггерится на любой ops/*.sh, а не только docker-prune.sh (#2203)
All checks were successful
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / changes (pull_request) Successful in 9s
CI / frontend-tests (pull_request) Has been skipped
CI Trade-In / changes (pull_request) Successful in 8s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 2m6s
CI / backend-tests (pull_request) Successful in 17m11s
paths-filter в deploy.yml знал только про ops/docker-prune.sh (#2887) — правка
ops/backup.sh или новый ops/restore-drill.sh из этого же PR не долетели бы до
/opt/gendesign: деплой не триггерится -> git reset --hard origin/main не
исполняется -> cron на VM месяцами крутит старую версию, молча.

Точечный список сам по себе и есть баг: #2887 добавил только тот файл, о
котором тогда шла речь, и следующий новый ops-скрипт (backup.sh) остался
за бортом. Глоб ops/*.sh закрывает класс целиком — не матчит подпути
(ops/db-bootstrap/**, ops/glitchtip-auth-forwarder/**), у них свои explicit
триггеры уже есть, дублирования нет.
2026-08-20 22:24:03 +03:00
68d041022d fix(ci): ожидание докер-лока оставляет след в логе (#2950) (#2958)
Some checks are pending
Deploy / changes (push) Waiting to run
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
Deploy / deploy-caddy (push) Blocked by required conditions
Deploy / perimeter-smoke (push) Blocked by required conditions
Deploy / deploy-status (push) Blocked by required conditions
Deploy Trade-In / changes (push) Successful in 11s
Deploy Trade-In / build-browser (push) Successful in 50s
Deploy Trade-In / build-frontend (push) Successful in 2m58s
Deploy Trade-In / test (push) Successful in 3m53s
Deploy Trade-In / build-backend (push) Successful in 32s
Deploy Trade-In / deploy (push) Successful in 1m53s
Deploy Trade-In / deploy-status (push) Successful in 1s
Deploy Trade-In / perimeter-smoke (push) Successful in 8s
2026-08-20 08:44:10 +00:00
feff8214f7 fix(ci): докер-секции прод-деплоев исключают друг друга через host-lock (#2950) (#2955)
All checks were successful
Deploy / changes (push) Successful in 9s
Deploy Trade-In / changes (push) Successful in 10s
Deploy Trade-In / build-browser (push) Successful in 48s
Deploy / deploy-caddy (push) Has been skipped
Deploy / build-backend (push) Successful in 47s
Deploy / build-frontend (push) Successful in 49s
Deploy / build-worker (push) Successful in 49s
Deploy / deploy (push) Successful in 1m26s
Deploy / deploy-status (push) Successful in 3s
Deploy / perimeter-smoke (push) Successful in 13s
Deploy Trade-In / build-frontend (push) Successful in 2m59s
Deploy Trade-In / test (push) Successful in 3m52s
Deploy Trade-In / build-backend (push) Successful in 37s
Deploy Trade-In / deploy (push) Successful in 2m22s
Deploy Trade-In / deploy-status (push) Successful in 1s
Deploy Trade-In / perimeter-smoke (push) Successful in 10s
2026-08-20 08:13:56 +00:00
2a01dea103 fix(ci): прод-деплои в одну группу concurrency — прун одного убивал pull другого (#2950) (#2952)
All checks were successful
Deploy / changes (push) Successful in 7s
Deploy Trade-In / changes (push) Successful in 10s
Deploy / deploy-caddy (push) Has been skipped
Deploy / build-worker (push) Successful in 51s
Deploy / build-backend (push) Successful in 52s
Deploy / build-frontend (push) Successful in 51s
Deploy Trade-In / build-browser (push) Successful in 32s
Deploy / deploy (push) Successful in 1m21s
Deploy / deploy-status (push) Successful in 1s
Deploy / perimeter-smoke (push) Successful in 11s
Deploy Trade-In / build-frontend (push) Successful in 3m30s
Deploy Trade-In / test (push) Successful in 4m15s
Deploy Trade-In / build-backend (push) Successful in 31s
Deploy Trade-In / deploy (push) Successful in 2m6s
Deploy Trade-In / deploy-status (push) Successful in 2s
Deploy Trade-In / perimeter-smoke (push) Successful in 11s
2026-08-20 07:47:48 +00:00
d25ff668f7 ci: правка конфига прокси больше не тянет полный деплой Site Finder (#2916) (#2925)
All checks were successful
Deploy / changes (push) Successful in 8s
Deploy / perimeter-smoke (push) Successful in 9s
Deploy / deploy-caddy (push) Has been skipped
Deploy / build-worker (push) Successful in 45s
Deploy / build-frontend (push) Successful in 44s
Deploy / build-backend (push) Successful in 45s
Deploy / deploy (push) Successful in 1m8s
Deploy / deploy-status (push) Successful in 1s
2026-08-19 08:39:01 +00:00
e86f0782da ci: смоук периметра МЕРЫ запускается сразу после деплоя (#2917) (#2922)
All checks were successful
Deploy / changes (push) Successful in 10s
perimeter-smoke-mera / smoke (push) Successful in 12s
Deploy Trade-In / changes (push) Successful in 14s
Deploy / build-frontend (push) Successful in 51s
Deploy / build-backend (push) Successful in 53s
Deploy / build-worker (push) Successful in 53s
Deploy Trade-In / build-browser (push) Successful in 40s
Deploy / deploy (push) Successful in 1m33s
Deploy / deploy-status (push) Successful in 2s
Deploy / perimeter-smoke (push) Successful in 10s
Deploy Trade-In / build-frontend (push) Successful in 2m50s
Deploy Trade-In / test (push) Successful in 4m8s
Deploy Trade-In / build-backend (push) Successful in 35s
Deploy Trade-In / deploy (push) Successful in 1m39s
Deploy Trade-In / deploy-status (push) Successful in 1s
Deploy Trade-In / perimeter-smoke (push) Successful in 10s
2026-08-19 08:13:49 +00:00
bot-backend
87258075a2 Merge main в chore/ci-config-cleanup-v2
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI / changes (pull_request) Successful in 9s
CI / backend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Successful in 52s
CI Trade-In / frontend-checks (pull_request) Successful in 1m19s
CI Trade-In / backend-tests (pull_request) Successful in 5m7s
Слить актуальный main (билд-раннер #2841/#2869, невалидные индексы #2752,
честный health-check и deploy-status #2841) в ветку очистки CI. Один конфликт
в .forgejo/workflows/deploy.yml: список triggers.paths — main добавил
ops/docker-prune.sh (#2887), ветка добавила auth/** (RBAC roles config).
Разрешено сохранением обоих путей, без потери ни одного триггера.
2026-08-15 22:30:47 +03:00
bot-backend
8bce8cf5ae fix(ci): fail-safe registry verification + real cache self-heal + honest health-check (#2841 R2)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 9s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
Ревью R2 нашёл, что вся безопасность предыдущего фикса держалась на
недоказанной поддержке act_runner'ом steps.<id>.outcome: если раннер его
не заполняет, retry-шаг молча не бежит, continue-on-error проглатывает
падение сборки, job зелёный — а деплой тянет старый :latest на прод.

- Добавлен engine-agnostic verify-шаг после каждого retry (6 мест,
  deploy.yml + deploy-tradein.yml): `docker buildx imagetools inspect
  <image>:<sha>` без continue-on-error. Не зависит от того, поддерживает
  ли раннер outcome — проверяет реальное состояние registry напрямую.
  Если ни build, ни retry реально не запушили образ — шаг падает и job
  честно FAILURE независимо от семантики outcome.
- Вернул `cache-to` в retry-шаги (6 мест): без него битый buildcache-тег
  никогда не перезаписывался — retry всегда собирал без cache-to, значит
  cache-to не выполнялся НИКОГДА, и каждый следующий прогон снова падал
  на том же cache-from. Заявленное самолечение не работало ни разу.
- Health-check в deploy.yml (main-стек) под `set -e` не мог упасть:
  `curl ... && break` — curl не последняя команда &&-списка, POSIX
  освобождает такие команды от errexit, цикл дохаживал до sleep (exit 0)
  даже если curl ни разу не отдал 200. Приведено к паттерну
  deploy-tradein.yml: явный флаг healthy + `exit 1` после цикла.
  Подтверждено локальным bash-репро (mock curl, всегда failure): старая
  версия — exit 0, новая — exit 1; позитивный сценарий не сломан.

docker rm -f без -v в SSH-скриптах деплоя не тронут.
2026-08-15 18:44:48 +03:00
bot-backend
9b3889bb36 ci(deploy): честный статус деплоя + нефатальный buildcache (#2841)
Зелёная галка прогона не отличима от пропущенного деплоя: если build падает
из-за битого blob в удалённом buildcache, шаг deploy молча пропускается
(if-условие даёт result=skipped), а прогон в целом не подсвечен как FAILED.

- deploy-status: новая job в конце deploy.yml и deploy-tradein.yml, всегда
  бежит (if: always() && !cancelled()) и падает явно, если deploy.result !=
  success — неважно, пропущен он (upstream build/test упал) или упал сам.
- cache-from нефатален: каждый build-push-action-шаг получил id + continue-
  on-error, и ретрай без cache-from/cache-to при steps.build.outcome ==
  'failure'. Битый remote-кеш больше не роняет саму сборку; следующий
  успешный прогон с кешем перезаписывает buildcache-тег целиком (mode=max)
  и самолечит порчу. Реальные ошибки сборки (не кеш) по-прежнему валят job
  на ретрае — deploy-status их тоже поймает.

Гейт против публикации services-портов на VPS (та же задача, проблема 1)
уже покрыт scripts/check-workflow-ports.py + шагом в ci.yml (#2757/#2759,
слит ранее) — сканирует все .forgejo/workflows/*.yml, включая эти два файла;
новых правок не потребовалось.

docker rm -f БЕЗ -v в SSH-скриптах деплоя не тронут — эти вызовы намеренно
без -v (боевые тома), правка их не касается.
2026-08-15 17:55:17 +03:00
bot-backend
c0782a8c4c chore(deploy): триггерить деплой на правку ops/docker-prune.sh
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI / changes (pull_request) Successful in 9s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
Скрипт уборки docker-мусора (#2887) исполняется на прод-VM по cron из
/opt/gendesign/ops/. Файлы туда попадают единственным путём — шагом
`git reset --hard origin/main` внутри deploy.yml.

Но paths-фильтр deploy.yml перечисляет подпути ops/ поимённо, а не ops/**.
Поэтому мерж #2887 деплой НЕ запустил: скрипт остался в main, на VM его не
было, а установленный cron указывал в пустоту. Правки скрипта и дальше
доезжали бы только случайно — со следующим чужим коммитом в backend/.

Ровно этот же баг уже ловили на ops/db-bootstrap/** — там рядом стоит
комментарий с той же формулировкой. Добавляю ops/docker-prune.sh по образцу
и фиксирую грабли в rules/deploy.md, чтобы следующий исполняемый файл в ops/
не наступил на них третий раз.
2026-08-15 17:14:00 +03:00
92593404fa ci: убирать buildx-билдер в конце сборочных job'ов (#2869) (#2870)
Some checks failed
Deploy / changes (push) Successful in 9s
Deploy Trade-In / changes (push) Successful in 13s
Deploy / build-backend (push) Successful in 49s
Deploy / build-frontend (push) Failing after 50s
Deploy / build-worker (push) Successful in 50s
Deploy / deploy (push) Has been skipped
Deploy Trade-In / build-browser (push) Successful in 34s
Deploy Trade-In / build-frontend (push) Successful in 2m29s
Deploy Trade-In / test (push) Successful in 3m46s
Deploy Trade-In / build-backend (push) Successful in 34s
Deploy Trade-In / deploy (push) Successful in 2m11s
2026-08-13 12:48:28 +00:00
482deb4864 fix(migrations): закрепить lock_timeout для блокирующего DDL и ловить невалидные индексы (#2791)
All checks were successful
Deploy / changes (push) Successful in 9s
Deploy Trade-In / changes (push) Successful in 13s
Deploy Trade-In / build-frontend (push) Successful in 43s
Deploy Trade-In / build-browser (push) Successful in 43s
Deploy / build-frontend (push) Successful in 47s
Deploy / build-worker (push) Successful in 49s
Deploy / build-backend (push) Successful in 50s
Deploy / deploy (push) Successful in 1m12s
Deploy Trade-In / test (push) Successful in 3m25s
Deploy Trade-In / build-backend (push) Successful in 30s
Deploy Trade-In / deploy (push) Successful in 1m50s
2026-08-07 11:21:28 +00:00
bot-backend
26fe9e4d77 chore(ci): деплой на изменение ролей, ruff-гейт для МЕРЫ, удаление мёртвого workflow
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 8s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Successful in 46s
CI Trade-In / frontend-checks (pull_request) Successful in 1m14s
CI Trade-In / backend-tests (pull_request) Successful in 3m57s
- deploy.yml: добавлен auth/** в path-триггеры. app.core.auth кэширует
  roles.yaml на весь lifetime процесса (@lru_cache), а файл монтируется
  ТОЛЬКО в backend (не в worker, у него лишь ./data и ./reports) — без
  триггера правка ролей вступала бы в силу в случайный момент.
- ci-tradein.yml: добавлен блокирующий шаг `ruff check` — гейт для tradein
  backend его не гонял вообще. Заодно почищены 3 срабатывания RUF059
  (unused unpacked vars) в test_estimator_pure_units.py:381 по established
  convention (`_` уже используется в соседнем тесте того же файла).
- Удалён мёртвый .github/workflows/ci.yml (Forgejo его не исполняет; GitHub
  mirror отстал на 500+ коммитов). Закомментированный postgres-services блок
  НЕ перенесён — обоснование, ради которого его хотели оставить как заготовку
  ("тестов против живой БД нет"), уже неверно: tests/sql/ реально гоняются
  против Postgres в ci.yml (#2745), и там намеренно НЕ используется `services:`
  — раннер поднимает job и service-контейнеры в сети хоста, где порт 5432
  занят прод-базой (см. ci.yml:91-100).
- README.md: убрана ложная привязка mypy к живому CI-гейту (только ruff +
  pytest + coverage gate ≥65%); убран stale-блок про .github/workflows/ —
  каталог после удаления ci.yml пуст.
2026-08-06 21:34:36 +03:00
bot-backend
bea61f6cd9 feat(auth): отдельная БД auth — фундамент единого входа «Меры» и «Птицы»
All checks were successful
CI Trade-In / changes (pull_request) Successful in 14s
CI / changes (pull_request) Successful in 14s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 3m0s
CI / backend-tests (pull_request) Successful in 15m35s
PR-1 эпика: вся авторизация переезжает на одну нейтральную форму входа, браузерный
popup (Caddy basic_auth) убирается. Этот PR — ТОЛЬКО фундамент, прод работает как
сейчас: в БД gendesign ничего не меняется, новая БД создаётся и наполняется
логинами без паролей, читать её пока некому.

Почему отдельная БД, а не таблица в существующей: хранилище доступов не должно
принадлежать продукту, из которого аккаунты выносятся. Сервер — существующий
gendesign-postgres (новый контейнер не заводим); проверено, что оба бэкенда
сидят в сети gendesign_shared и TCP-достают до него.

Состав:
- data/sql/auth/001-003 — схема (users, sessions), роль приложения, сид 13 логинов.
  password_hash = NULL у ВСЕХ: plaintext и bcrypt-хеши в git запрещены, пароли
  проставляются отдельно на проде (конвенция репы, прецедент tradein м.193).
- ops/db-bootstrap/create_auth_db.sql — CREATE DATABASE через \gexec. Не миграцией:
  CREATE DATABASE запрещён в транзакции, а миграции обязаны быть транзакционными.
- ops/db-bootstrap/set_auth_app_password.sql — пароль роли из env, зеркало
  set_tradein_fdw_password.sql (GUC + \o /dev/null + %L, строго через stdin —
  :'pw' не интерполируется внутри $$...$$, на этом падал деплой 2026-05-24).

Схема лежит в ПОДКАТАЛОГЕ data/sql/auth/ намеренно: основной цикл деплоя использует
`ls -1 data/sql/*.sql`, который в подкаталоги не рекурсирует → эти файлы физически
не могут примениться в БД gendesign. Защита не на дисциплине, а на глобе. Триггер
`data/sql/**` подкаталог при этом покрывает.

Права: владелец БД — суперюзер, а не auth_app (иначе гранты были бы декорацией).
users — только SELECT+UPDATE (INSERT не выдан: создания аккаунтов в этом PR нет, а
снять грант, на который уже опирается прод-код, сложнее чем выдать). REVOKE ALL ON
DATABASE FROM PUBLIC продублирован в bootstrap и в миграции намеренно: bootstrap
гоняется каждый деплой (переприменяемость), миграция — однократно (самодостаточность).

Проверено ИСПОЛНЕНИЕМ на postgis/postgis:16-3.4 (тот же образ, что на проде):
двойной прогон всех файлов идемпотентен; COALESCE-защита сида не затирает вручную
проставленные пароль/имя (проверено живьём); ASCII-CHECK отклоняет кириллицу;
auth_app коннектится, посторонняя роль → permission denied; битая миграция даёт
exit 1 и НЕ пишется в _schema_migrations, т.е. деплой прервётся до подъёма кода;
пароль с кавычками и бэкслешем не ломает %L и не печатается в stdout.

Тест backend/tests/sql/test_auth_sql_migrations.py: имена, транзакционность, наличие
wiring в deploy.yml и детектор паролей/хешей, покрывающий И data/sql/auth, И
ops/db-bootstrap — единственное место в репе с ALTER ROLE ... PASSWORD.
Детектор проверен на живучесть: подложенный bcrypt-хеш роняет тест.

Открытые развилки зафиксированы комментариями в коде, решаются в PR-2/3:
судьба tradein_users/tradein_sessions (два одинаковых по схеме хранилища) и
expired != disabled (trial-экран не выражается булевым is_active).

NB: переменную AUTH_DB_PASSWORD нужно завести вручную в runtime-env бэкенда на VPS.
Пока пусто — шаг ALTER ROLE пропускается с warning'ом, деплой не падает.
2026-07-31 21:47:33 +03:00
034d9f9bca feat(reports): Celery-джоба полного PDF-отчёта + кэш + 3 endpoint'а (#2259 PR-D) (#2287)
Some checks failed
Deploy / changes (push) Successful in 8s
Deploy / build-backend (push) Successful in 3m12s
Deploy / build-worker (push) Successful in 4m8s
Deploy / build-frontend (push) Successful in 4m46s
Deploy / deploy (push) Has been cancelled
2026-07-03 11:13:06 +00:00
6883d14177 fix(ops): repair broken main-DB backup + harden auth scripts/docs (#71 #427 #429 #428)
Some checks failed
CI / changes (push) Successful in 7s
CI / backend-tests (push) Has been skipped
CI / frontend-tests (push) Has been skipped
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
Deploy / changes (push) Has been cancelled
#71 (CRITICAL): backup.sh committed 100644 → git reset --hard on deploy
re-asserts non-exec mode → raw-path cron fails Permission denied (last good
dump 2026-05-27, no S3). Commit 100755 + chmod ops/*.sh in deploy.yml +
size sanity-check (never prune good dumps for a truncated one) + keep-N
retention + optional S3 (redacted /etc/default template). Modeled on the
working backup-tradein-db.sh.

#427: widen basic_auth username regex ^[a-z][a-z0-9_.-]{1,62}$ + literal-escape
  dotted names in grep probes.
#429: replace list_users.sh false-positive grep with anchored awk over basic_auth block.
#428: PILOT_ACCESS.md support email → pilot@gendsgn.ru.

Closes #71
Closes #427
Closes #429
Closes #428
2026-06-13 20:13:04 +05:00
d7960276b1 chore(deploy): wire OWN_DEVELOPER_IDS into prod env for §25.3 own-portfolio (#1169)
All checks were successful
CI / changes (push) Successful in 6s
CI / backend-tests (push) Has been skipped
CI / frontend-tests (push) Has been skipped
Deploy / changes (push) Successful in 6s
Deploy / build-worker (push) Successful in 32s
Deploy / build-frontend (push) Successful in 30s
CI / changes (pull_request) Successful in 5s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
Deploy / build-backend (push) Successful in 35s
Deploy / deploy (push) Successful in 1m3s
Mirror the LLM_ENABLED wiring for OWN_DEVELOPER_IDS (own-portfolio
cannibalization, #1169): forward vars.OWN_DEVELOPER_IDS into the SSH deploy
(env block + envs list) and write it to backend/.env.runtime ONLY when
non-empty (conditional, like OPENAI_API_KEY/LLM_ENABLED). Non-sensitive
(public companyGroup ids) → actions variable. Unset → cannibalization keeps
the proxy (dormant). No literal id in the workflow (refs only).

Captures in the pipeline the value already set live on prod via .env.runtime
(OWN_DEVELOPER_IDS=6208 = PRINZIP, verified against domrf_kn → 28 projects).
Owner must set Forgejo Variable OWN_DEVELOPER_IDS=6208 for full pipeline
management; meanwhile the .env.runtime line holds (survives git reset).

Refs #1169
2026-06-09 18:14:12 +05:00
98ecdecb5b chore(deploy): wire OPENAI_API_KEY + LLM_ENABLED into prod env for LLM chat
All checks were successful
CI / changes (push) Successful in 6s
CI / backend-tests (push) Has been skipped
CI / frontend-tests (push) Has been skipped
CI / changes (pull_request) Successful in 5s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
Deploy / changes (push) Successful in 5s
Deploy / build-worker (push) Successful in 28s
Deploy / build-backend (push) Successful in 30s
Deploy / build-frontend (push) Successful in 28s
Deploy / deploy (push) Successful in 1m1s
Forward OPENAI_API_KEY (Forgejo secret) and LLM_ENABLED (Forgejo actions
variable) into the SSH deploy and write them to backend/.env.runtime ONLY
when non-empty, so the LLM chat (#960/#957) stays dormant
(llm_enabled=False, openai_api_key=None) until BOTH are set in Forgejo.
Mirrors the OBJECTIVE_API_KEY wiring (env block + envs list + idempotent
.env.runtime grep-sed-or-printf), but guarded by [ -n ] so an unset
secret/var writes nothing. No literal key (refs only). Compose header
documents both as optional. .env.runtime is shared by backend+worker+beat.

Refs #960
2026-06-09 13:51:41 +05:00
ed49f6b953 fix(deploy): resolve FDW bootstrap race + extract bootstrap DO block to .sql file (#499)
Some checks failed
Deploy Trade-In / changes (push) Successful in 6s
Deploy / changes (push) Successful in 5s
Deploy Trade-In / build-backend (push) Successful in 24s
Deploy Trade-In / build-frontend (push) Successful in 23s
Deploy / build-backend (push) Successful in 26s
Deploy / build-worker (push) Successful in 25s
Deploy / build-frontend (push) Successful in 25s
Deploy Trade-In / deploy (push) Successful in 33s
Deploy / deploy (push) Failing after 22s
2026-05-24 09:46:00 +00:00
94cf199276 feat(tradein): postgres_fdw live read of gendesign.cad_buildings (replaces snapshot) (#493)
Some checks failed
Deploy Trade-In / changes (push) Successful in 5s
Deploy / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Successful in 26s
Deploy Trade-In / build-backend (push) Successful in 47s
Deploy / build-frontend (push) Successful in 29s
Deploy / build-backend (push) Successful in 1m24s
Deploy Trade-In / deploy (push) Successful in 40s
Deploy / build-worker (push) Successful in 2m57s
Deploy / deploy (push) Failing after 37s
Replaces tradein.cad_buildings snapshot with live postgres_fdw foreign table reading gendesign.v_tradein_cad_buildings. Fixes /trade-in/api/v1/geocode/reverse 500 (Nominatim ban) and address_not_geocoded for cadastre addresses (e.g. Хохрякова 81).

Security (deep-review fixes):
- 100_tradein_fdw_role.sql: passwordless CREATE ROLE; password set by deploy.yml ALTER ROLE bootstrap reading GENDESIGN_FDW_PASSWORD from backend/.env.runtime (via psql :'pw' var → format %L — injection-safe).
- core/fdw.py: regex whitelist [A-Za-z0-9_-]{32,256} on password, ValueError without echoing value, try/rollback on commit.
- 060_postgres_fdw_extension.sql: connect_timeout='3' on FOREIGN SERVER + ALTER ADD/SET fallback.
- geocoder.py: _cadastral_forward_sync / _cadastral_reverse_sync wrapped in asyncio.to_thread.
- 100_*.sql: REVOKE ALL ON ALL TABLES/SEQUENCES/FUNCTIONS IN SCHEMA public; only GRANT SELECT on v_tradein_cad_buildings.
- pg_user_mappings query handles PUBLIC mapping (usename IS NULL).

Tests: 3 SQL-injection guards on ensure_fdw_user_mapping + rewritten cadastral suite.
2026-05-24 08:57:30 +00:00
3295808b41 fix(security): caddy/** в deploy paths + username из 401 попытки (#434)
All checks were successful
Deploy / changes (push) Successful in 5s
Deploy / build-frontend (push) Successful in 24s
Deploy / build-worker (push) Successful in 25s
Deploy / build-backend (push) Successful in 26s
Deploy / deploy (push) Successful in 54s
2026-05-23 09:25:41 +00:00
f4d43d1cfc fix(security): forwarder PermissionError — убрать USER nobody + deploy automation (#432)
All checks were successful
Deploy / changes (push) Successful in 5s
Deploy / build-backend (push) Successful in 27s
Deploy / build-worker (push) Successful in 27s
Deploy / build-frontend (push) Successful in 25s
Deploy / deploy (push) Successful in 59s
Hotfix для GlitchTip Issue #71 (PermissionError при чтении /var/log/caddy/gendsgn.ru.log).

Changes:
- ops/glitchtip-auth-forwarder/Dockerfile — убран USER nobody, форвардер под root
- ops/glitchtip-auth-forwarder/forwarder.py — throttle capture_exception (300s)
- .forgejo/workflows/deploy.yml — paths-filter + build + force-recreate sidecar
- docs/runbooks/basic_auth_management.md — Deploy section

Security: caddy_logs mount read-only, нет network listener, нет shell,
auth_forwarder_state dedicated volume. Attack surface минимален.

После merge deploy.yml автоматически rebuild+recreate sidecar на VPS.
2026-05-23 09:04:00 +00:00
d1b721a3be fix(deploy): trigger workflow on all data/sql/** changes, not only .sql (#320)
All checks were successful
Deploy / changes (push) Successful in 4s
Deploy / build-backend (push) Successful in 25s
Deploy / build-worker (push) Successful in 26s
Deploy / build-frontend (push) Successful in 24s
Deploy / deploy (push) Successful in 37s
2026-05-17 18:51:28 +00:00
a93bef4147 feat(deploy): inject OBJECTIVE_API_KEY into backend/.env.runtime (#311)
All checks were successful
Deploy / changes (push) Successful in 5s
Deploy / build-backend (push) Successful in 33s
Deploy / build-worker (push) Successful in 31s
Deploy / build-frontend (push) Successful in 25s
Deploy / deploy (push) Successful in 54s
2026-05-17 16:05:13 +00:00
lekss361
11e78d738e fix(deploy): force-recreate caddy чтобы новые compose mounts применились
Раньше deploy.yml делал `docker compose exec caddy caddy reload` — это
только reload Caddyfile, но НЕ пересоздаёт container. Когда в
docker-compose.prod.yml добавлялся новый volume mount (например
./preview:/srv/preview:ro в PR #268), он не появлялся в running container
до manual `docker compose up -d --force-recreate caddy` через SSH.

Теперь deploy всегда вызывает force-recreate caddy после image pull —
идемпотентно, +~5 сек к deploy time, гарантирует что новые mounts +
Caddyfile блоки активны.
2026-05-17 11:30:45 +03:00
lekss361
e64fbd670b fix(infra): wire GlitchTip DSNs (build-arg + env_file) + reject sentry.io promote
Problem
- GlitchTip Issues = 0 за всё время, хотя backend + frontend SDK интегрированы (PR #207, #208).
- Старый Sentry.io продолжает получать события — user видит уведомления оттуда.

Root cause
- frontend/Dockerfile не имеет ARG NEXT_PUBLIC_GLITCHTIP_DSN → `npm run build` бьёт
  с пустым env var → Next.js инлайнит undefined → SDK init guard `if (dsn)` skips.
  Chrome-devtools check на prod bundle подтвердил: ни в одном из 9 chunks DSN-строка
  не запечена; `i.env.NEXT_PUBLIC_GLITCHTIP_DSN` evaluates to undefined.
- .forgejo/workflows/deploy.yml build-frontend не передавал build-args.
- На VPS backend/.env.runtime содержит legacy SENTRY_DSN=...@sentry.io/...
  config.py:_promote_legacy_sentry_dsn слепо промоутит его в glitchtip_dsn → SDK
  шлёт в чужой Sentry. GLITCHTIP_DSN там не задан.
- deploy.yml SSH-скрипт никогда не редактировал SENTRY_DSN/GLITCHTIP_DSN в .env.runtime.

Solution
1. frontend/Dockerfile: ARG NEXT_PUBLIC_GLITCHTIP_DSN + NEXT_PUBLIC_ENVIRONMENT
   с пустыми defaults, ENV-mirror перед `npm run build`. Локальный build без
   build-args работает по-прежнему (no-op DSN).

2. .forgejo/workflows/deploy.yml:
   - build-frontend: `build-args` передаёт `secrets.GLITCHTIP_FRONTEND_DSN`
     + NEXT_PUBLIC_ENVIRONMENT=production. Инвалидирует cache → frontend
     image пересоберётся (expected).
   - deploy step: GLITCHTIP_BACKEND_DSN через secret, в SSH-скрипте:
     a) `sed -i '/^SENTRY_DSN=/d' backend/.env.runtime` — снести legacy
     b) upsert GLITCHTIP_DSN (sed/printf) тем же паттерном что SENTRY_RELEASE
     c) `compose up -d --force-recreate --no-deps backend worker beat` —
        обычный `up -d` не перечитывает env_file без image change.

3. backend/app/core/config.py: _promote_legacy_sentry_dsn ужесточён —
   принимает SENTRY_DSN только если host == errors.gendsgn.ru. Для других
   URLs (sentry.io) выдаёт UserWarning и НЕ промоутит. Anti-regression на
   случай если SENTRY_DSN снова окажется в .env.runtime после ручного
   вмешательства.

Required Forgejo secrets (Settings → Actions → Secrets)
- GLITCHTIP_BACKEND_DSN = https://3d6e291003e142458957490c83559867@errors.gendsgn.ru/1
- GLITCHTIP_FRONTEND_DSN = https://5d7bc85e300c4e80a8554ccc818ff56d@errors.gendsgn.ru/2
DSNs публичны (видны в browser bundle) — secrets ради build-time injection,
не для конфиденциальности. Если secrets не заданы → deploy succeeds, SDK
no-op, без регрессии.

Test plan
- Verify Forgejo deploy.yml зелёный после merge
- chrome-devtools: открыть gendsgn.ru → search bundle на DSN string → должна
  быть запечена строка errors.gendsgn.ru/2
- Trigger frontend error → POST к errors.gendsgn.ru/api/2/envelope/
- Backend: curl на endpoint вызывающий 500 → событие в GlitchTip backend project
- GlitchTip dashboard https://errors.gendsgn.ru/gendesign/issues — Issues > 0

References
- vault: meta/00_credentials.md (DSNs + incident notes 2026-05-16)
- vault: decisions/Dec_GlitchTip_Frontend_Sentry_SDK.md (env contract)
- vault: fixes/fixes-MOC.md (#204 backend SDK init)
2026-05-16 21:48:28 +03:00
e97f96afa7 fix(ci): switch deploy to .forgejo/workflows + shell GHCR login (#192)
All checks were successful
Deploy / changes (push) Successful in 6s
Deploy / build-backend (push) Successful in 3m44s
Deploy / build-frontend (push) Successful in 26s
Deploy / build-worker (push) Successful in 4m43s
Deploy / deploy (push) Successful in 35s
2026-05-16 05:25:00 +00:00
Renamed from .github/workflows/deploy.yml (Browse further)