NATS: subject'ы и JWT по окружению из OpenBao (OPENBAO__NATS__*) (#31) #37

Merged
aep merged 6 commits from feat/31-nats-env-config into main 2026-10-13 12:55:07 +03:00
Owner

Closes #31

Subject'ы и учётные данные NATS tabular-parser — из OPENBAO__NATS__* (контракт и общая дельта — RSHB/arm-ka-docs#80).

Что в этом PR (tabular-parser)

  • NATSSettings: три subject'а с валидацией (все три, R-3), NATS_JWT/NATS_SEED → SecretStr, hide_input_in_errors=True во всех классах настроек.
  • Подписка на NATS_TABULAR_REQUEST_SUBJECT (queue group tabular-parser), ack и результат — в NATS_RESULT_SUBJECT (RecognitionWorker(result_subject)).
  • used_subjects() → лог старта и /healthcheck.subjects (tabular_request, result) при любом nats.
  • Roundtrip-тест на уникальных subject'ах прогона — не пересекается с контейнером стенда (OQ-83).
  • .env.example, README, CLAUDE.md; дочерний change nats-env-config (спека tabular-recognition-service).
  • Ветка перебазирована на main после #33 (R-14).

Проверки

  • make check-full — код 0: lint, test 2313 passed, test-integration 10 passed, docker-build.
  • openspec validate nats-env-config --strict — valid.

Связанные PR (одна фича, change nats-env-config в четырёх репозиториях)

Порядок merge любой: умолчания subject'ов не меняются (files.tabular_uploaded, files.img_uploaded,
files.tabular_parsed), поэтому смешанное состояние «часть сервисов уже с настройками» на стенде ничего не ломает.
Новые ключи в контуре задавать только после выката всех трёх сервисов — одинаковым набором для всех трёх.

Ключи окружения (одинаковые в трёх сервисах)

Ключ Умолчание arm-core tabular-parser scan-gateway
OPENBAO__NATS__NATS_TABULAR_REQUEST_SUBJECT files.tabular_uploaded публикует подписан —
OPENBAO__NATS__NATS_IMAGE_REQUEST_SUBJECT files.img_uploaded публикует — подписан
OPENBAO__NATS__NATS_RESULT_SUBJECT files.tabular_parsed подписан публикует публикует
OPENBAO__NATS__NATS_JWT, NATS_SEED пусто SecretStr SecretStr SecretStr

Каждый сервис проверяет все три имени при старте (непустое, без пробелов, *, >, пустых токенов; попарно различны) —
иначе не стартует, ошибка называет ключ. JWT/seed не попадают в логи, repr и тексты ошибок валидации
(hide_input_in_errors=True во всех классах настроек). Subject'ы сервиса — в логе старта и в /healthcheck.subjects
при любом состоянии NATS. Queue group'ы и schema_version не меняются.

Rulings I made

Решения без обсуждения — docs/openspec/changes/nats-env-config/design.md, раздел «Decisions made without discussion».

  • R-1 (design #1) — имена ключей NATS_TABULAR_REQUEST_SUBJECT, NATS_IMAGE_REQUEST_SUBJECT, NATS_RESULT_SUBJECT (по образцу FileWorker; у нас два subject'а запроса).
  • R-2 (design #2) — schema_version не меняется: тела сообщений те же, subject'ы — окружение.
  • R-3 (design #3) — каждый сервис проверяет все три subject'а, включая неиспользуемые им.
  • R-4 (design #4) — subjects в /healthcheck отдаётся и при nats = off.
  • R-5 (design #5) — пароли MinIO/SMB в SecretStr не переводятся (вне запроса); в ошибках валидации они скрыты hide_input_in_errors.
  • R-6 (design #6) — change nats-env-config в четырёх репозиториях, один план SDD.
  • R-7 (design #7) — e2e ядра остаётся на subject'ах по умолчанию (нужен контейнер tabular-parser стенда; конфликт — queue group arm-core); OQ-83 для make e2e открыт.
  • R-8 (design #8) — задачи настроек и проводки исполнялись параллельно по репозиториям, ревью — по каждой задаче.
  • R-9 (design #9) — трейлер коммитов приведён к единому до публикации.
  • R-10 (design #10) — minor-находки задач, усиливающие тесты, исправлены одной волной; тест утечки при невалидном subject оставлен как регрессионный.
  • R-11 (design #11) — по финальному ревью исправлены I-1, M-1, M-2, M-3, M-5; M-4 отложено, M-7 отклонено.
  • R-12 (design #12) — make check в docs запускается с CHANGE=nats-env-config (дефолт Makefile указывает на архивный change).
  • R-13 (design #13) — tabular-parser проверялся на временной ветке main + feat/31 (ветка отставала от main).
  • R-14 (design #14) — неопубликованные ветки docs и tabular-parser перебазированы на свежий main; все проверки перезапущены.
  • R-15 (design #15) — RM-1, RM-2 исправлены сразу вместо отложенных; T8.1 сверено с кодом, строка qa-guide уточнена.

Находки

Маркер Что Статус
T2.1, T2.2, T3.1, T3.2 тесты arm-core: все subject'ы и пары в валидации, healthcheck не на умолчаниях, вызов subscribe fixed db8b0bc (arm-core)
T4.1, T4.2, T5.1–T5.3, T5.6 тесты и типизация tabular-parser fixed 4f0636f (tabular-parser)
T5.4 docstring roundtrip-теста называл боевой subject fixed 1b50d65 (tabular-parser)
T6.1, T6.3 тесты scan-gateway: все пары, .strip() seed fixed cd5409b (scan-gateway)
T7.1 переносы docstring в nats.py fixed c10f927 (scan-gateway)
T8.1 симптом разъехавшихся subject'ов в qa-guide.md fixed 3a31674 (docs)
T8.2, T8.3 OQ-83 в dev/README.md, порядок правил fixed b60ed85 (docs)
T2.3, T3.3, T4.3, T5.5, T6.2, T7.2, T7.3, T7.4 косметика / уже обеспечено rejected (причины в ledger и design R-10)
I-1 повторная публикация не обновляла recognition_job.request_subject после смены настроек fixed c9d6090 (arm-core)
M-1 примеры /healthcheck без subjects fixed c9d6090 (arm-core), 32fa327 (docs)
M-2 формулировка об интеграционных тестах ядра fixed 32fa327 (docs)
M-3 docstring'и/логи называли умолчание фактическим subject'ом fixed c9d6090, 1b50d65, c10f927
M-4 базовые спеки с SHALL … files.* формально не помечают имена как умолчания deferred
M-5 CLAUDE.md сервисов и repo-templates без «по умолчанию» fixed c9d6090, 1b50d65, c10f927, 32fa327
M-6 рулинги не внесены в design.md fixed 62d7fd7 (docs)
M-7 разное оформление ключей в .env.example ядра и сервисов rejected: у ядра паритет .env.example/.env.test проверяет тест
RM-1, RM-2 литерал subject'а в логе file_mismatch, переносы docstring'ов arm-core fixed eaa563c (arm-core)
O-4 tabular-parser отставал от main (golden fixtures) fixed — rebase (R-14)
O-5 npm install 404 на rollup в web-check rejected: временный сбой реестра, повторный check-full зелёный

Отложено (deferred → follow-up при закрытии)

  • M-4 — базовые спеки (tabular-recognition-service, image-recognition-gateway, recognition-job-exchange, recognition-contract) называют files.* в SHALL без пометки «по умолчанию»; ADDED-требование это покрывает по смыслу, формально — нет. Решить отдельным change'ем.
  • M-2 (расширение) — запросы в интеграционных тестах ядра (test_recognition_exchange.py, test_api_files_upload.py) перевести на уникальные subject'ы — закрыть OQ-83 для make test-integration ядра.
  • O-2 — docs/Makefile: CHANGE ?= slice-0-skeleton указывает на архивный change, make check без параметра красный.
  • O-6 — урок для планов: тест утечки секретов надо проверять откатом hide_input_in_errors (pydantic обрезает input_value, длинный JWT без защиты не «утекает» целиком).

🤖 Generated with Claude Code

Closes #31 Subject'ы и учётные данные NATS tabular-parser — из `OPENBAO__NATS__*` (контракт и общая дельта — RSHB/arm-ka-docs#80). ## Что в этом PR (tabular-parser) - `NATSSettings`: три subject'а с валидацией (все три, R-3), `NATS_JWT`/`NATS_SEED` → `SecretStr`, `hide_input_in_errors=True` во всех классах настроек. - Подписка на `NATS_TABULAR_REQUEST_SUBJECT` (queue group `tabular-parser`), ack и результат — в `NATS_RESULT_SUBJECT` (`RecognitionWorker(result_subject)`). - `used_subjects()` → лог старта и `/healthcheck.subjects` (`tabular_request`, `result`) при любом `nats`. - Roundtrip-тест на уникальных subject'ах прогона — не пересекается с контейнером стенда (OQ-83). - `.env.example`, README, CLAUDE.md; дочерний change `nats-env-config` (спека `tabular-recognition-service`). - Ветка перебазирована на main после #33 (R-14). ## Проверки - `make check-full` — код 0: lint, test 2313 passed, test-integration 10 passed, docker-build. - `openspec validate nats-env-config --strict` — valid. ## Связанные PR (одна фича, change `nats-env-config` в четырёх репозиториях) - docs: https://git.aepif.ru/RSHB/arm-ka-docs/pulls/99 - arm-core: https://git.aepif.ru/RSHB/arm-core/pulls/107 - tabular-parser: https://git.aepif.ru/RSHB/arm-tabular-parser/pulls/37 - scan-gateway: https://git.aepif.ru/RSHB/arm-scan-gateway/pulls/33 Порядок merge любой: умолчания subject'ов не меняются (`files.tabular_uploaded`, `files.img_uploaded`, `files.tabular_parsed`), поэтому смешанное состояние «часть сервисов уже с настройками» на стенде ничего не ломает. Новые ключи в контуре задавать только после выката всех трёх сервисов — одинаковым набором для всех трёх. ## Ключи окружения (одинаковые в трёх сервисах) | Ключ | Умолчание | arm-core | tabular-parser | scan-gateway | |---|---|---|---|---| | `OPENBAO__NATS__NATS_TABULAR_REQUEST_SUBJECT` | `files.tabular_uploaded` | публикует | подписан | — | | `OPENBAO__NATS__NATS_IMAGE_REQUEST_SUBJECT` | `files.img_uploaded` | публикует | — | подписан | | `OPENBAO__NATS__NATS_RESULT_SUBJECT` | `files.tabular_parsed` | подписан | публикует | публикует | | `OPENBAO__NATS__NATS_JWT`, `NATS_SEED` | пусто | `SecretStr` | `SecretStr` | `SecretStr` | Каждый сервис проверяет все три имени при старте (непустое, без пробелов, `*`, `>`, пустых токенов; попарно различны) — иначе не стартует, ошибка называет ключ. JWT/seed не попадают в логи, `repr` и тексты ошибок валидации (`hide_input_in_errors=True` во всех классах настроек). Subject'ы сервиса — в логе старта и в `/healthcheck.subjects` при любом состоянии NATS. Queue group'ы и `schema_version` не меняются. ## Rulings I made Решения без обсуждения — `docs/openspec/changes/nats-env-config/design.md`, раздел «Decisions made without discussion». - **R-1 (design #1)** — имена ключей `NATS_TABULAR_REQUEST_SUBJECT`, `NATS_IMAGE_REQUEST_SUBJECT`, `NATS_RESULT_SUBJECT` (по образцу FileWorker; у нас два subject'а запроса). - **R-2 (design #2)** — `schema_version` не меняется: тела сообщений те же, subject'ы — окружение. - **R-3 (design #3)** — каждый сервис проверяет все три subject'а, включая неиспользуемые им. - **R-4 (design #4)** — `subjects` в `/healthcheck` отдаётся и при `nats = off`. - **R-5 (design #5)** — пароли MinIO/SMB в `SecretStr` не переводятся (вне запроса); в ошибках валидации они скрыты `hide_input_in_errors`. - **R-6 (design #6)** — change `nats-env-config` в четырёх репозиториях, один план SDD. - **R-7 (design #7)** — e2e ядра остаётся на subject'ах по умолчанию (нужен контейнер tabular-parser стенда; конфликт — queue group `arm-core`); OQ-83 для `make e2e` открыт. - **R-8 (design #8)** — задачи настроек и проводки исполнялись параллельно по репозиториям, ревью — по каждой задаче. - **R-9 (design #9)** — трейлер коммитов приведён к единому до публикации. - **R-10 (design #10)** — minor-находки задач, усиливающие тесты, исправлены одной волной; тест утечки при невалидном subject оставлен как регрессионный. - **R-11 (design #11)** — по финальному ревью исправлены I-1, M-1, M-2, M-3, M-5; M-4 отложено, M-7 отклонено. - **R-12 (design #12)** — `make check` в docs запускается с `CHANGE=nats-env-config` (дефолт Makefile указывает на архивный change). - **R-13 (design #13)** — tabular-parser проверялся на временной ветке main + feat/31 (ветка отставала от main). - **R-14 (design #14)** — неопубликованные ветки docs и tabular-parser перебазированы на свежий main; все проверки перезапущены. - **R-15 (design #15)** — RM-1, RM-2 исправлены сразу вместо отложенных; T8.1 сверено с кодом, строка qa-guide уточнена. ## Находки | Маркер | Что | Статус | |---|---|---| | T2.1, T2.2, T3.1, T3.2 | тесты arm-core: все subject'ы и пары в валидации, healthcheck не на умолчаниях, вызов `subscribe` | fixed db8b0bc (arm-core) | | T4.1, T4.2, T5.1–T5.3, T5.6 | тесты и типизация tabular-parser | fixed 4f0636f (tabular-parser) | | T5.4 | docstring roundtrip-теста называл боевой subject | fixed 1b50d65 (tabular-parser) | | T6.1, T6.3 | тесты scan-gateway: все пары, `.strip()` seed | fixed cd5409b (scan-gateway) | | T7.1 | переносы docstring в `nats.py` | fixed c10f927 (scan-gateway) | | T8.1 | симптом разъехавшихся subject'ов в `qa-guide.md` | fixed 3a31674 (docs) | | T8.2, T8.3 | OQ-83 в `dev/README.md`, порядок правил | fixed b60ed85 (docs) | | T2.3, T3.3, T4.3, T5.5, T6.2, T7.2, T7.3, T7.4 | косметика / уже обеспечено | rejected (причины в ledger и design R-10) | | I-1 | повторная публикация не обновляла `recognition_job.request_subject` после смены настроек | fixed c9d6090 (arm-core) | | M-1 | примеры `/healthcheck` без `subjects` | fixed c9d6090 (arm-core), 32fa327 (docs) | | M-2 | формулировка об интеграционных тестах ядра | fixed 32fa327 (docs) | | M-3 | docstring'и/логи называли умолчание фактическим subject'ом | fixed c9d6090, 1b50d65, c10f927 | | M-4 | базовые спеки с `SHALL … files.*` формально не помечают имена как умолчания | **deferred** | | M-5 | `CLAUDE.md` сервисов и `repo-templates` без «по умолчанию» | fixed c9d6090, 1b50d65, c10f927, 32fa327 | | M-6 | рулинги не внесены в design.md | fixed 62d7fd7 (docs) | | M-7 | разное оформление ключей в `.env.example` ядра и сервисов | rejected: у ядра паритет `.env.example`/`.env.test` проверяет тест | | RM-1, RM-2 | литерал subject'а в логе `file_mismatch`, переносы docstring'ов arm-core | fixed eaa563c (arm-core) | | O-4 | tabular-parser отставал от main (golden fixtures) | fixed — rebase (R-14) | | O-5 | `npm install` 404 на rollup в `web-check` | rejected: временный сбой реестра, повторный `check-full` зелёный | ## Отложено (deferred → follow-up при закрытии) - **M-4** — базовые спеки (`tabular-recognition-service`, `image-recognition-gateway`, `recognition-job-exchange`, `recognition-contract`) называют `files.*` в `SHALL` без пометки «по умолчанию»; ADDED-требование это покрывает по смыслу, формально — нет. Решить отдельным change'ем. - **M-2 (расширение)** — запросы в интеграционных тестах ядра (`test_recognition_exchange.py`, `test_api_files_upload.py`) перевести на уникальные subject'ы — закрыть OQ-83 для `make test-integration` ядра. - **O-2** — `docs/Makefile`: `CHANGE ?= slice-0-skeleton` указывает на архивный change, `make check` без параметра красный. - **O-6** — урок для планов: тест утечки секретов надо проверять откатом `hide_input_in_errors` (pydantic обрезает `input_value`, длинный JWT без защиты не «утекает» целиком). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
aep added 6 commits 2026-10-13 12:51:53 +03:00
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- NATSSettings: subject'ы запроса и ответа из окружения (имена контракта по умолчанию), проверка формата и попарного
  различия; NATS_SEED и NATS_JWT — SecretStr; request_subjects() для request_subject(pipeline, subjects).
- hide_input_in_errors во всех классах настроек: ошибка «нет поля» не печатает вход группы с JWT и seed.
- build_nats_auth читает секреты через get_secret_value().
- Схемы контракта скопированы из docs/contracts (request, result-message).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
T4.1, T2.1, T2.2, T5.1, T5.2, T5.3 (тесты); T5.6 (subscribe_requests: пустая строка не подменяется умолчанием).
Отмечены пункты tasks.md 1.1, 1.2, 2.x, 3.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
check-full: tests/fixtures падают только из-за отставания ветки от main (после merge main — 2313 passed).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
M-3: docstring воркера, T5.4: docstring и сообщение roundtrip-теста, M-5: CLAUDE.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
aep merged commit 143744b80d into main 2026-10-13 12:55:07 +03:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RSHB/arm-tabular-parser#37
No description provided.