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

Merged
aep merged 8 commits from feat/106-nats-env-config into main 2026-10-13 12:55:17 +03:00
Owner

Closes #106

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

Что в этом PR (arm-core)

  • NATSSettings: NATS_TABULAR_REQUEST_SUBJECT, NATS_IMAGE_REQUEST_SUBJECT, NATS_RESULT_SUBJECT с валидацией; NATS_JWT/NATS_SEED → SecretStr (в nkeys — get_secret_value()); hide_input_in_errors=True во всех классах настроек.
  • request_subject(pipeline, subjects); outbox (publish_pending/run_publisher_loop) и создание задания (primary_files) берут subject запроса из настроек; повторная публикация обновляет recognition_job.request_subject (I-1).
  • Подписка на NATS_RESULT_SUBJECT (queue group arm-core — константа).
  • used_subjects() → лог старта и /healthcheck.subjects (tabular_request, image_request, result) при любом nats.
  • .env.example, .env.test, README, CLAUDE.md; дочерний change nats-env-config (спека recognition-job-exchange).

Проверки

  • make check-full — код 0: lint (ruff, mypy), unit 1335 passed, integration 905 passed, make e2e 1 passed (на умолчаниях, R-7), web-check, 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 #106 Subject'ы и учётные данные NATS ядра — из `OPENBAO__NATS__*` (контракт и общая дельта — RSHB/arm-ka-docs#80). ## Что в этом PR (arm-core) - `NATSSettings`: `NATS_TABULAR_REQUEST_SUBJECT`, `NATS_IMAGE_REQUEST_SUBJECT`, `NATS_RESULT_SUBJECT` с валидацией; `NATS_JWT`/`NATS_SEED` → `SecretStr` (в nkeys — `get_secret_value()`); `hide_input_in_errors=True` во всех классах настроек. - `request_subject(pipeline, subjects)`; outbox (`publish_pending`/`run_publisher_loop`) и создание задания (`primary_files`) берут subject запроса из настроек; повторная публикация обновляет `recognition_job.request_subject` (I-1). - Подписка на `NATS_RESULT_SUBJECT` (queue group `arm-core` — константа). - `used_subjects()` → лог старта и `/healthcheck.subjects` (`tabular_request`, `image_request`, `result`) при любом `nats`. - `.env.example`, `.env.test`, README, CLAUDE.md; дочерний change `nats-env-config` (спека `recognition-job-exchange`). ## Проверки - `make check-full` — код 0: lint (ruff, mypy), unit 1335 passed, integration 905 passed, `make e2e` 1 passed (на умолчаниях, R-7), web-check, 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 8 commits 2026-10-13 12:51:46 +03:00
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- NATSSettings: NATS_TABULAR_REQUEST_SUBJECT / NATS_IMAGE_REQUEST_SUBJECT / NATS_RESULT_SUBJECT с умолчанием
  имён контракта v1.0; проверка формата (без пробелов, '*', '>', пустых токенов) и попарного различия.
- request_subjects() и request_subject(pipeline, subjects) — карта subject'ов окружения.
- NATS_SEED / NATS_JWT — SecretStr; build_nats_auth читает значения через get_secret_value().
- hide_input_in_errors=True во всех классах настроек: ошибка «нет поля» не печатает JWT/seed.
- Схемы контракта api/contracts/ — копии docs/contracts/ (побайтно).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- invalid_subject параметризован по трём ключам, equality покрывает три пары
- кейс утечки JWT/seed при невалидном subject
- /healthcheck с нестандартными subject'ами и проверкой отсутствия JWT
- subscribe с настроенным subject'ом, лог старта с subject'ами
- tasks.md: отмечены 1.1, 1.2, 2.x, 3.1

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Пункт 3.2 (make check-full) не отмечен: Python-часть зелёная, web-check падает на npm install (404 rollup в реестре).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
I-1: ветка повторной публикации в _process_one записывает request_subject
(как первая публикация); тест test_republish_updates_request_subject.
M-1: примеры /healthcheck в README (ядро: три subject'а; tabular-parser: два).
M-3: docstring'и и логи не выдают умолчание за фактический subject.
M-5: CLAUDE.md — subject'ы задаются OPENBAO__NATS__NATS_*_SUBJECT.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
aep merged commit 2e74cd66ab into main 2026-10-13 12:55:17 +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-core#107
No description provided.