docs(ipc): v2 — ретро-ревью (10 находок)
- enforcement: прокси даёт грубую изоляцию (сервис/метод), тонкую (per-signal, per-key) делает сам сервис по идентичности sender — прокси не видит payload - PermBroker: идентичность только из соединения, CheckCapability(cap) sender-scoped (не принимает app аргументом → нет спуфинга); GrantChanged адресный - НОВЫЙ сервис ru.shturman.Location (домен K) — GPS/положение; GPS-скорость не через E - ошибки Stale/Timeout (транзиентно) vs NotAvailable (постоянно); GetSignal с таймаутом - desired_max_hz = агрегатный hint (не per-subscriber троттл); подписки owner-bound, авто-снятие по NameOwnerChanged; quality-поле; BatteryVoltage→ModuleVoltage - RegisterIntents(handler_path) — фразы из манифеста; версии-мажоры сосуществуют Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+29
-16
@@ -4,7 +4,7 @@
|
|||||||
> Формализует карту связей из [architecture.md](../architecture.md) §5 в конкретные
|
> Формализует карту связей из [architecture.md](../architecture.md) §5 в конкретные
|
||||||
> контракты. К нему цепляются data-model, plugin-sdk и все домены.
|
> контракты. К нему цепляются data-model, plugin-sdk и все домены.
|
||||||
|
|
||||||
Статус: **v1 (на ревью).**
|
Статус: **v2 (на ревью).** v2 — после ретро-ревью (10 находок).
|
||||||
Связано с: [architecture.md](../architecture.md) (§4–5) · [data-model.md](data-model.md) · [plugin-sdk.md](plugin-sdk.md) · [security-privacy.md](security-privacy.md)
|
Связано с: [architecture.md](../architecture.md) (§4–5) · [data-model.md](data-model.md) · [plugin-sdk.md](plugin-sdk.md) · [security-privacy.md](security-privacy.md)
|
||||||
|
|
||||||
Область: **control plane** (D-Bus). Аудио/видео/графика — НЕ здесь (PipeWire/Wayland, см. architecture §4).
|
Область: **control plane** (D-Bus). Аудио/видео/графика — НЕ здесь (PipeWire/Wayland, см. architecture §4).
|
||||||
@@ -31,13 +31,15 @@
|
|||||||
| Well-known имя | `ru.shturman.<Service>` (напр. `ru.shturman.VehicleData`) |
|
| Well-known имя | `ru.shturman.<Service>` (напр. `ru.shturman.VehicleData`) |
|
||||||
| Путь объекта | `/ru/shturman/<Service>` |
|
| Путь объекта | `/ru/shturman/<Service>` |
|
||||||
| Интерфейс | `ru.shturman.<Service>N` — `N` = мажорная версия (напр. `…VehicleData1`) |
|
| Интерфейс | `ru.shturman.<Service>N` — `N` = мажорная версия (напр. `…VehicleData1`) |
|
||||||
| Версионирование | аддитивные изменения внутри версии; ломающие → новый интерфейс `…2` |
|
| Версионирование | аддитивно внутри версии; ломающее → **добавляется** `…2` рядом со старым `…1`; оба сосуществуют в окне поддержки (старые плагины работают без правок; EOL мажора синхронизируется с `shturman_api` в манифесте) |
|
||||||
| Ошибки | `ru.shturman.Error.<Name>`: `PermissionDenied`, `NotAvailable`, `ReadOnly`, `InvalidArgument`, `Unsupported` |
|
| Ошибки | `ru.shturman.Error.<Name>`: `PermissionDenied`, `NotAvailable` (PID не поддержан машиной — постоянно), `Stale`/`Timeout` (транзиентно: таймаут/устарело), `ReadOnly`, `InvalidArgument`, `Unsupported` |
|
||||||
| Действие | **метод** |
|
| Действие | **метод** |
|
||||||
| Изменение состояния | **сигнал** |
|
| Изменение состояния | **сигнал** |
|
||||||
| Текущее состояние | **property** (+ стандартный `PropertiesChanged`) |
|
| Текущее состояние | **property** (+ стандартный `PropertiesChanged`) |
|
||||||
| Асинхронность | всё async (zbus + tokio); долгие операции не блокируют |
|
| Асинхронность | всё async (zbus + tokio); долгие операции не блокируют |
|
||||||
| Стандартные интерфейсы | `org.freedesktop.DBus.{Properties,Introspectable,Peer}` |
|
| Стандартные интерфейсы | `org.freedesktop.DBus.{Properties,Introspectable,Peer}` |
|
||||||
|
| Идентичность вызывающего | по **аутентифицированному соединению** (`sender` → PID/cgroup → манифест, привязка App-Host'ом), НЕ по аргументу метода; подменить нельзя |
|
||||||
|
| Жизненный цикл клиент-состояния | серверное состояние клиента (подписки, регистрации тайлов/интентов) **снимается автоматически** при исчезновении владельца имени (`NameOwnerChanged`) — крэш/рестарт не оставляет мусора |
|
||||||
|
|
||||||
> Полные сигнатуры (XML-интроспекция) фиксируются при реализации; здесь — реестр и ключевые члены.
|
> Полные сигнатуры (XML-интроспекция) фиксируются при реализации; здесь — реестр и ключевые члены.
|
||||||
|
|
||||||
@@ -46,10 +48,12 @@
|
|||||||
## 3. Реестр сервисов — ядро (привилегированные)
|
## 3. Реестр сервисов — ядро (привилегированные)
|
||||||
|
|
||||||
### `ru.shturman.VehicleData` — данные машины (**READ-ONLY**)
|
### `ru.shturman.VehicleData` — данные машины (**READ-ONLY**)
|
||||||
- **Методы (только чтение):** `ListSignals() → [name]`, `GetSignal(name) → (value, unit, ts)`, `Subscribe(names, max_hz)`/`Unsubscribe(names)`, `GetDtcs() → [(code, status, desc)]`.
|
- **Методы (только чтение):** `ListSignals() → [(name, availability)]`, `GetSignal(name) → (value, unit, ts, quality)`, `Subscribe(names, desired_max_hz)`/`Unsubscribe(names)`, `GetDtcs() → [(code, status, desc)]`.
|
||||||
- **Сигналы:** `SignalChanged(name, value, ts)` — **только подписчикам и только по подписанным** именам (не широковещательно «всё всем»), `DtcsChanged([...])`.
|
- **Авторизация по имени сигнала — в самом сервисе:** прокси (§5) не видит payload, поэтому `vehicle_read:[…]` enforce-ит **VehicleData по идентичности вызывающего** (`sender` → манифест), отвергая незаявленные имена `PermissionDenied`. Сигналы **адресные**: `SignalChanged(name, value, ts, quality)` шлётся только подписчику и только по `Subscribe ∩ манифест`; `DtcsChanged([...])`.
|
||||||
- **Политика частоты:** на шину сигналы идут **с потолком (~10–20 Гц)** — этого хватает для читаемых датчиков и держит control-plane лёгким. Сырой высокочастотный CAN остаётся внутри VehicleData. Цифровому приборному щитку, если нужна более плавная стрелка, — клиентская интерполяция или выделенный быстрый канал (не D-Bus); см. «Открытые вопросы».
|
- **Частота:** `desired_max_hz` — верхняя граница, которую готов принять подписчик, и вход в **агрегатный** опрос: фактический опрос PID = `max()` запрошенных, ограничен потолком шины (~10–20 Гц) и источником. Доставка индивидуально не троттлится — слабый клиент (приборка) прореживает сам. Имя `desired_` подчёркивает: не гарантия «моей частоты».
|
||||||
- **Properties (горячие, текущее значение):** `Speed`, `Rpm`, `CoolantTemp`, `BatteryVoltage`, `Online`.
|
- **Подписки привязаны к владельцу соединения** — снимаются автоматически при крэше/рестарте; агрегатный опрос пересчитывается, опрос PID останавливается без живых подписчиков (бережёт скудный ELM327).
|
||||||
|
- **Таймаут/staleness:** `GetSignal` имеет таймаут → `Stale`/`Timeout` (или stale-flag в `quality`), не виснет на медленном ELM327-PID. `NotAvailable` = PID не поддержан машиной (постоянно); `Stale` = транзиентно (двигатель заглушен/таймаут).
|
||||||
|
- **Properties (горячие):** `Speed`, `Rpm`, `CoolantTemp`, `ModuleVoltage` (питание ЭБУ ≈ бортсеть, не клеммы АКБ), `Online`.
|
||||||
- ⛔ **Методов записи нет** — ни `SetSignal`, ни actuator-команд, ни clear-DTC. Архитектурная гарантия read-only (принцип #2). Типы — [data-model.md](data-model.md).
|
- ⛔ **Методов записи нет** — ни `SetSignal`, ни actuator-команд, ни clear-DTC. Архитектурная гарантия read-only (принцип #2). Типы — [data-model.md](data-model.md).
|
||||||
|
|
||||||
### `ru.shturman.Power` — питание и жизненный цикл
|
### `ru.shturman.Power` — питание и жизненный цикл
|
||||||
@@ -60,12 +64,13 @@
|
|||||||
### `ru.shturman.Settings` — конфигурация и состояние
|
### `ru.shturman.Settings` — конфигурация и состояние
|
||||||
- **Методы:** `Get(key) → value`, `Set(key, value)`, `List(prefix) → [key]`, `Reset(key)`.
|
- **Методы:** `Get(key) → value`, `Set(key, value)`, `List(prefix) → [key]`, `Reset(key)`.
|
||||||
- **Сигналы:** `Changed(key, value)`.
|
- **Сигналы:** `Changed(key, value)`.
|
||||||
- Namespace на каждый ап изолирован (брокер не даёт читать чужой).
|
- **Namespace изолирует сам сервис Settings** по идентичности вызывающего (`sender` → app-id): Get/Set/List/Reset вне своего namespace → `PermissionDenied` (прокси этого не делает — не инспектирует строку `key`). Свой namespace — read/write по умолчанию (ambient, без отдельной capability).
|
||||||
|
|
||||||
### `ru.shturman.PermBroker` — выдача разрешений (привратник)
|
### `ru.shturman.PermBroker` — политика разрешений (привратник)
|
||||||
- **Методы:** `CheckCapability(app, cap) → bool`, `RequestRuntimeGrant(cap) → granted` (рантайм-промпт пользователю, напр. «ап X хочет сеть»).
|
- **Идентичность — только из соединения** (`sender` → манифест), **никогда из аргумента** (иначе спуфинг/проверка за чужой ап).
|
||||||
- **Сигналы:** `GrantChanged(app, cap, granted)`.
|
- **Методы:** `CheckCapability(cap) → bool` (sender-scoped — ап спрашивает про СЕБЯ; кросс-ап форма доступна только привилегированным core по D-Bus-политике), `RequestRuntimeGrant(cap) → granted` (рантайм-промпт; целевой ап = `sender`).
|
||||||
- Основная фильтрация — на уровне прокси (§5); этот API для рантайм-согласий.
|
- **Сигналы:** `GrantChanged(cap, granted)` — адресно владельцу гранта (чужие не получают).
|
||||||
|
- Статическая фильтрация — прокси + sandbox (§5, владеет App-Host); broker — политика и рантайм-согласия.
|
||||||
|
|
||||||
### `ru.shturman.AppHost` — запуск/супервизия апов и плагинов
|
### `ru.shturman.AppHost` — запуск/супервизия апов и плагинов
|
||||||
- **Методы:** `ListApps() → [(id, status)]`, `StartApp(id)`, `StopApp(id)`, `GetStatus(id) → status`.
|
- **Методы:** `ListApps() → [(id, status)]`, `StartApp(id)`, `StopApp(id)`, `GetStatus(id) → status`.
|
||||||
@@ -75,14 +80,19 @@
|
|||||||
### `ru.shturman.Connectivity` — сеть (обёртка NM/MM)
|
### `ru.shturman.Connectivity` — сеть (обёртка NM/MM)
|
||||||
- **Методы:** `GetStatus() → status`, `ListNetworks() → [...]`, `Connect(id)`, `Disconnect()`.
|
- **Методы:** `GetStatus() → status`, `ListNetworks() → [...]`, `Connect(id)`, `Disconnect()`.
|
||||||
- **Сигналы:** `ConnectivityChanged(online)`, `NetworkChanged(...)`.
|
- **Сигналы:** `ConnectivityChanged(online)`, `NetworkChanged(...)`.
|
||||||
- **Properties:** `Online`, `Type` (wifi/modem), `SignalStrength`.
|
- **Properties:** `Online` (bool — «сервис ещё не поднят» ≠ «offline»), `Type` (wifi/modem), `SignalStrength`.
|
||||||
|
|
||||||
|
### `ru.shturman.Location` — GPS/положение (владелец — домен K)
|
||||||
|
- **Properties:** `Latitude`, `Longitude`, `Heading`, `Speed` (GPS-скорость), `FixQuality`, `ts`.
|
||||||
|
- **Сигналы:** `LocationChanged(...)`, `FixChanged(quality)`.
|
||||||
|
- Источник — NMEA/gpsd (hardware §4); гейтится capability `location`. **GPS-скорость берётся ОТСЮДА** (не из VehicleData/E — E это CAN/OBD, появляется в v2). До домена K — мок-стаб (dev fake-GPS).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4. Реестр сервисов — апы (на SDK)
|
## 4. Реестр сервисов — апы (на SDK)
|
||||||
|
|
||||||
### `ru.shturman.Assistant`
|
### `ru.shturman.Assistant`
|
||||||
- **Методы:** `SendText(query) → reply`, `StartListening()`, `StopListening()`, `RegisterIntents(handler_path, [pattern])` (для плагинов с capability `assistant_intents`).
|
- **Методы:** `SendText(query) → reply`, `StartListening()`, `StopListening()`, `RegisterIntents(handler_path)` — привязывает handler к фразам **из манифеста** `assistant_intents` (фразы НЕ передаются в рантайме, иначе обходится install-ревью).
|
||||||
- **Сигналы:** `StateChanged(idle|listening|thinking|speaking)`, `TranscriptUpdated(text)`, `ReplyUpdated(text)`.
|
- **Сигналы:** `StateChanged(idle|listening|thinking|speaking)`, `TranscriptUpdated(text)`, `ReplyUpdated(text)`.
|
||||||
- Контекст машины подмешивается ассистентом из `VehicleData` (см. architecture §5).
|
- Контекст машины подмешивается ассистентом из `VehicleData` (см. architecture §5).
|
||||||
|
|
||||||
@@ -100,7 +110,7 @@
|
|||||||
|
|
||||||
1. Манифест плагина декларирует capabilities (`vehicle_read:[speed]`, `network`, `assistant_intents`…).
|
1. Манифест плагина декларирует capabilities (`vehicle_read:[speed]`, `network`, `assistant_intents`…).
|
||||||
2. App-Host поднимает плагин в bubblewrap и даёт ему **фильтрующий D-Bus-прокси**, сконфигурированный под эти capabilities.
|
2. App-Host поднимает плагин в bubblewrap и даёт ему **фильтрующий D-Bus-прокси**, сконфигурированный под эти capabilities.
|
||||||
3. Прокси пропускает только разрешённые сервисы/интерфейсы/методы/сигналы. Пример: `vehicle_read:[speed]` → виден `VehicleData.GetSignal("speed")` и `SignalChanged` по speed; **не виден** `Power`, чужие апы, любые write-методы.
|
3. Прокси даёт **грубую** изоляцию — сервис/интерфейс/метод/сигнал (payload/аргументы НЕ инспектирует). Пример: `vehicle_read:[speed]` → `VehicleData` (read) **достижим**, а `Power`, чужие апы и write-методы — **нет**. **Тонкую** авторизацию по конкретному имени сигнала / ключу настроек делает сам сервис по идентичности `sender` (см. VehicleData, Settings).
|
||||||
4. Рантайм-согласия (сеть «сейчас») — через `PermBroker.RequestRuntimeGrant`.
|
4. Рантайм-согласия (сеть «сейчас») — через `PermBroker.RequestRuntimeGrant`.
|
||||||
|
|
||||||
Итог: плагин физически не может дотянуться до того, чего нет в манифесте. Детали модели — [security-privacy.md](security-privacy.md).
|
Итог: плагин физически не может дотянуться до того, чего нет в манифесте. Детали модели — [security-privacy.md](security-privacy.md).
|
||||||
@@ -140,4 +150,7 @@
|
|||||||
|---------|-------|------|
|
|---------|-------|------|
|
||||||
| Топология шины | системная шина устройства + фильтрующий прокси на ап (🟡 на подтверждение) | 2026-06-16 |
|
| Топология шины | системная шина устройства + фильтрующий прокси на ап (🟡 на подтверждение) | 2026-06-16 |
|
||||||
| Изоляция доступа апов | портал-паттерн: per-app dbus-proxy из манифеста | 2026-06-16 |
|
| Изоляция доступа апов | портал-паттерн: per-app dbus-proxy из манифеста | 2026-06-16 |
|
||||||
| Соглашения имён/версий | `ru.shturman.*`, версия в имени интерфейса | 2026-06-16 |
|
| Соглашения имён/версий | `ru.shturman.*`, версия в имени интерфейса; мажоры сосуществуют в окне поддержки (аддитивно) | 2026-06-16 |
|
||||||
|
| Enforcement | грубо — прокси (сервис/метод); тонко (per-signal/per-key) — сам сервис по `sender` | 2026-06-16 |
|
||||||
|
| Идентичность | только из аутентиф. соединения, не из аргумента; клиент-состояние снимается по `NameOwnerChanged` | 2026-06-16 |
|
||||||
|
| Location/GPS | отдельный сервис `ru.shturman.Location` (домен K); GPS-скорость не через E | 2026-06-16 |
|
||||||
|
|||||||
Reference in New Issue
Block a user