fix(review): manifest deny_unknown_fields + каталог сигналов в sdk::vehicle

- deny_unknown_fields: опечатка в ключе capability (граница доверия F §3) не проглатывается.
- VEHICLE_SIGNALS → shturman_sdk::vehicle (single source; валидатор берёт оттуда).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Alexander <akotenev2003@gmail.com>
This commit is contained in:
2026-06-24 14:36:50 +03:00
parent 2b06ff749f
commit 69beaad596
4 changed files with 53 additions and 23 deletions
+1
View File
@@ -5,6 +5,7 @@ pub mod connect;
pub mod manifest;
pub mod power;
pub mod settings;
pub mod vehicle;
pub use connect::connect;
pub use manifest::Manifest;
+22
View File
@@ -6,6 +6,7 @@ use serde::Deserialize;
/// Корень манифеста (`manifest.yaml`).
#[derive(Debug, Clone, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Manifest {
pub plugin: Plugin,
#[serde(default)]
@@ -15,6 +16,7 @@ pub struct Manifest {
}
#[derive(Debug, Clone, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Plugin {
/// reverse-DNS id; `ru.shturman.*` закрыт за first-party (проверяет валидатор, F §3).
pub id: String,
@@ -29,6 +31,7 @@ pub struct Plugin {
}
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Capabilities {
/// Только сигналы из каталога data-model (проверяет валидатор).
#[serde(default)]
@@ -46,6 +49,7 @@ pub struct Capabilities {
}
#[derive(Debug, Clone, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Network {
/// host-allowlist (намерение; строгая гарантия — forced-proxy, plugin-sdk §3).
#[serde(default)]
@@ -53,6 +57,7 @@ pub struct Network {
}
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ExtensionPoints {
#[serde(default)]
pub tiles: Vec<Tile>,
@@ -61,6 +66,7 @@ pub struct ExtensionPoints {
}
#[derive(Debug, Clone, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Tile {
pub id: String,
#[serde(default)]
@@ -68,6 +74,7 @@ pub struct Tile {
}
#[derive(Debug, Clone, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Intents {
/// Путь объекта `IntentHandler` (все фразы → сюда, plugin-sdk §2).
pub handler: String,
@@ -138,4 +145,19 @@ plugin:
fn rejects_malformed_yaml() {
assert!(Manifest::from_yaml(": : not yaml : :").is_err());
}
#[test]
fn rejects_unknown_field() {
// опечатка в ключе capability на границе доверия (F §3) не должна молча проглатываться
let bad = r#"
plugin:
id: dev.example.x
name: "x"
version: 0.1.0
shturman_api: "1"
capabilities:
vehicl_read: [speed]
"#;
assert!(Manifest::from_yaml(bad).is_err());
}
}
+28
View File
@@ -0,0 +1,28 @@
//! Каталог стандартных сигналов машины (data-model §4) — single source для валидатора манифеста
//! и будущих потребителей (домен E, v2). Алиасы; точные VSS-пути — в домене E.
/// Алиасы стандартных OBD-II сигналов (data-model §4). `vehicle_read` манифеста — только отсюда.
pub const SIGNALS: &[&str] = &[
"speed",
"rpm",
"engine_load",
"coolant_temp",
"intake_temp",
"maf",
"throttle",
"intake_pressure",
"fuel_level",
"module_voltage",
"ambient_temp",
"oil_temp",
"fuel_rate",
"run_time",
"mil_on",
"dtc_count",
"distance_mil",
];
/// Является ли `alias` стандартным сигналом каталога.
pub fn is_known(alias: &str) -> bool {
SIGNALS.contains(&alias)
}
@@ -2,27 +2,6 @@
use shturman_sdk::Manifest;
/// Каталог стандартных сигналов (data-model §4). `vehicle_read` допускает только их.
const VEHICLE_SIGNALS: &[&str] = &[
"speed",
"rpm",
"engine_load",
"coolant_temp",
"intake_temp",
"maf",
"throttle",
"intake_pressure",
"fuel_level",
"module_voltage",
"ambient_temp",
"oil_temp",
"fuel_rate",
"run_time",
"mil_on",
"dtc_count",
"distance_mil",
];
/// Поддерживаемые мажоры API (plugin-sdk §7).
const SUPPORTED_API: &[&str] = &["1"];
@@ -55,9 +34,9 @@ pub fn validate(m: &Manifest) -> Vec<String> {
));
}
// vehicle_read только из каталога data-model
// vehicle_read только из каталога data-model (single source — shturman_sdk::vehicle)
for sig in &m.capabilities.vehicle_read {
if !VEHICLE_SIGNALS.contains(&sig.as_str()) {
if !shturman_sdk::vehicle::is_known(sig) {
errs.push(format!("vehicle_read '{sig}' нет в каталоге data-model"));
}
}