From 69beaad5966900a1c9a5fdeb96193f78da67e584 Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 24 Jun 2026 14:36:50 +0300 Subject: [PATCH] =?UTF-8?q?fix(review):=20manifest=20deny=5Funknown=5Ffiel?= =?UTF-8?q?ds=20+=20=D0=BA=D0=B0=D1=82=D0=B0=D0=BB=D0=BE=D0=B3=20=D1=81?= =?UTF-8?q?=D0=B8=D0=B3=D0=BD=D0=B0=D0=BB=D0=BE=D0=B2=20=D0=B2=20sdk::vehi?= =?UTF-8?q?cle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - deny_unknown_fields: опечатка в ключе capability (граница доверия F §3) не проглатывается. - VEHICLE_SIGNALS → shturman_sdk::vehicle (single source; валидатор берёт оттуда). Co-Authored-By: Claude Opus 4.8 Signed-off-by: Alexander --- crates/shturman-sdk/src/lib.rs | 1 + crates/shturman-sdk/src/manifest.rs | 22 +++++++++++++++ crates/shturman-sdk/src/vehicle.rs | 28 +++++++++++++++++++ .../src/validate.rs | 25 ++--------------- 4 files changed, 53 insertions(+), 23 deletions(-) create mode 100644 crates/shturman-sdk/src/vehicle.rs diff --git a/crates/shturman-sdk/src/lib.rs b/crates/shturman-sdk/src/lib.rs index 5417279..490ec37 100644 --- a/crates/shturman-sdk/src/lib.rs +++ b/crates/shturman-sdk/src/lib.rs @@ -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; diff --git a/crates/shturman-sdk/src/manifest.rs b/crates/shturman-sdk/src/manifest.rs index 5825bb5..2409ac2 100644 --- a/crates/shturman-sdk/src/manifest.rs +++ b/crates/shturman-sdk/src/manifest.rs @@ -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, @@ -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()); + } } diff --git a/crates/shturman-sdk/src/vehicle.rs b/crates/shturman-sdk/src/vehicle.rs new file mode 100644 index 0000000..5973dd2 --- /dev/null +++ b/crates/shturman-sdk/src/vehicle.rs @@ -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) +} diff --git a/crates/tools/shturman-manifest-validator/src/validate.rs b/crates/tools/shturman-manifest-validator/src/validate.rs index e1c6e84..ba39ba6 100644 --- a/crates/tools/shturman-manifest-validator/src/validate.rs +++ b/crates/tools/shturman-manifest-validator/src/validate.rs @@ -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 { )); } - // 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")); } }