Skip to content

Commit a882430

Browse files
kvfasilVinodsathyaseelanbrendanobra
authored
Move the openRPC schema validation crate under a feature flag and disable it by default (#905)
* feat: Move the openRPC schema validation crate under a feature flag and disable it by default (#878) * Fix: Changed log level to trace for rpc validate function Co-authored-by: Vinod Sathyaseelan <Vinod_sathyaseelan@comcast.com> Co-authored-by: brendanobra <brendan@obrafamily.org>
1 parent 69d68aa commit a882430

File tree

5 files changed

+143
-28
lines changed

5 files changed

+143
-28
lines changed

Cargo.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,11 @@ members = [
2121
"core/tdk",
2222
"device/thunder_ripple_sdk",
2323
"core/main",
24-
"device/mock_device",
25-
"openrpc_validator"]
24+
"device/mock_device"]
25+
26+
# openrpc_validator is excluded from the default workspace build
27+
# It will only be included when the openrpc_validation feature is enabled
28+
exclude = ["openrpc_validator"]
2629

2730
[workspace.package]
2831
version = "1.1.0"

core/main/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ path = "src/main.rs"
3232
local_dev = []
3333
sysd = ["sd-notify"]
3434
pre_prod = []
35+
openrpc_validation = ["dep:openrpc_validator"]
3536
http_contract_tests = [
3637
]
3738

@@ -69,7 +70,9 @@ jaq-std = { version = "1.5.1", default-features = false }
6970
strum = { version = "0.24", default-features = false }
7071
strum_macros = "0.24"
7172

72-
openrpc_validator = { path = "../../openrpc_validator" }
73+
# openrpc_validator is optional and not part of the default workspace
74+
# Only included when openrpc_validation feature is enabled
75+
openrpc_validator = { path = "../../openrpc_validator", optional = true, default-features = false }
7376
proc-macro2.workspace = true
7477

7578
[build-dependencies]

core/main/src/firebolt/firebolt_gateway.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use ripple_sdk::{
3232
},
3333
chrono::Utc,
3434
extn::extn_client_message::ExtnMessage,
35-
log::{debug, error, info, trace, warn},
35+
log::{error, info, trace, warn},
3636
serde_json::{self, Value},
3737
tokio::{self, runtime::Handle, sync::mpsc::Sender},
3838
};
@@ -488,7 +488,7 @@ fn validate_request(
488488
} else {
489489
// TODO: Currently LifecycleManagement and other APIs are not in the schema. Let these pass through to their
490490
// respective handlers for now.
491-
debug!(
491+
trace!(
492492
"validate_request: Method not found in schema: {}",
493493
request.method
494494
);

core/main/src/state/openrpc_state.rs

Lines changed: 129 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,85 @@
1515
// SPDX-License-Identifier: Apache-2.0
1616
//
1717

18+
#[cfg(feature = "openrpc_validation")]
1819
use openrpc_validator::jsonschema::JSONSchema;
20+
#[cfg(feature = "openrpc_validation")]
21+
use openrpc_validator::{FireboltOpenRpc as FireboltOpenRpcValidator, RpcMethodValidator};
22+
23+
#[cfg(not(feature = "openrpc_validation"))]
24+
pub mod openrpc_validator {
25+
pub mod jsonschema {
26+
#[derive(Debug, Clone)]
27+
pub struct JSONSchema;
28+
29+
impl JSONSchema {
30+
pub fn validate(&self, _value: &serde_json::Value) -> Result<(), Vec<String>> {
31+
Ok(())
32+
}
33+
}
34+
}
35+
36+
#[derive(Debug, Clone)]
37+
pub struct RpcMethodValidator;
38+
39+
impl RpcMethodValidator {
40+
pub fn new() -> Self {
41+
RpcMethodValidator
42+
}
43+
44+
pub fn add_schema(&mut self, _schema: super::FireboltOpenRpcValidator) {
45+
// No-op when validation is disabled
46+
}
47+
48+
pub fn get_method(&self, _name: &str) -> Option<super::RpcMethod> {
49+
None
50+
}
51+
52+
pub fn get_closest_result_properties_schema(
53+
&self,
54+
_name: &str,
55+
_sample_map: &serde_json::Map<String, serde_json::Value>,
56+
) -> Option<serde_json::Map<String, serde_json::Value>> {
57+
None
58+
}
59+
60+
pub fn get_result_ref_schema(
61+
&self,
62+
_reference_path: &str,
63+
) -> Option<serde_json::Map<String, serde_json::Value>> {
64+
None
65+
}
66+
67+
pub fn params_validator(
68+
&self,
69+
_version: String,
70+
_method: &str,
71+
) -> Result<jsonschema::JSONSchema, super::ValidationError> {
72+
Ok(jsonschema::JSONSchema)
73+
}
74+
}
75+
76+
#[derive(Debug, Clone)]
77+
pub struct FireboltOpenRpcValidator;
78+
79+
#[derive(Debug)]
80+
pub enum ValidationError {
81+
SpecVersionNotFound,
82+
}
83+
84+
#[derive(Debug, Clone)]
85+
pub struct RpcMethod {
86+
pub name: String,
87+
}
88+
}
89+
90+
#[cfg(not(feature = "openrpc_validation"))]
91+
use openrpc_validator::jsonschema::JSONSchema;
92+
#[cfg(not(feature = "openrpc_validation"))]
93+
use openrpc_validator::{RpcMethod, RpcMethodValidator, ValidationError};
94+
#[cfg(not(feature = "openrpc_validation"))]
95+
type FireboltOpenRpcValidator = openrpc_validator::FireboltOpenRpcValidator;
96+
1997
use ripple_sdk::log::{debug, error, info};
2098
use ripple_sdk::{api::firebolt::fb_openrpc::CapabilityPolicy, serde_json};
2199
use ripple_sdk::{
@@ -38,8 +116,6 @@ use std::{
38116
sync::{Arc, RwLock},
39117
};
40118

41-
use openrpc_validator::{FireboltOpenRpc as FireboltOpenRpcValidator, RpcMethodValidator};
42-
43119
#[derive(Debug, Clone)]
44120
pub enum ApiSurface {
45121
Firebolt,
@@ -77,6 +153,7 @@ pub struct OpenRpcState {
77153
provider_relation_map: Arc<RwLock<HashMap<String, ProviderRelationSet>>>,
78154
openrpc_validator: Arc<RwLock<RpcMethodValidator>>,
79155
provider_registrations: Arc<Vec<String>>,
156+
#[cfg(feature = "openrpc_validation")]
80157
json_schema_cache: Arc<RwLock<HashMap<String, JSONSchema>>>,
81158
}
82159

@@ -125,10 +202,19 @@ impl OpenRpcState {
125202
.expect("Failed parsing FireboltVersionManifest from open RPC file");
126203
let firebolt_open_rpc: FireboltOpenRpc = version_manifest.clone().into();
127204
let ripple_open_rpc: FireboltOpenRpc = FireboltOpenRpc::default();
128-
let openrpc_validator: FireboltOpenRpcValidator = serde_json::from_str(&open_rpc_path)
129-
.expect("Failed parsing FireboltOpenRpcValidator from open RPC file");
130-
let mut rpc_method_validator = RpcMethodValidator::new();
131-
rpc_method_validator.add_schema(openrpc_validator);
205+
206+
#[cfg(feature = "openrpc_validation")]
207+
let rpc_method_validator = {
208+
let openrpc_validator: FireboltOpenRpcValidator = serde_json::from_str(&open_rpc_path)
209+
.expect("Failed parsing FireboltOpenRpcValidator from open RPC file");
210+
let mut validator = RpcMethodValidator::new();
211+
validator.add_schema(openrpc_validator);
212+
validator
213+
};
214+
215+
#[cfg(not(feature = "openrpc_validation"))]
216+
let rpc_method_validator = RpcMethodValidator::new();
217+
132218
let v = OpenRpcState {
133219
firebolt_cap_map: Arc::new(RwLock::new(firebolt_open_rpc.get_methods_caps())),
134220
ripple_cap_map: Arc::new(RwLock::new(ripple_open_rpc.get_methods_caps())),
@@ -139,6 +225,7 @@ impl OpenRpcState {
139225
provider_relation_map: Arc::new(RwLock::new(HashMap::new())),
140226
openrpc_validator: Arc::new(RwLock::new(rpc_method_validator)),
141227
provider_registrations: Arc::new(provider_registrations),
228+
#[cfg(feature = "openrpc_validation")]
142229
json_schema_cache: Arc::new(RwLock::new(HashMap::new())),
143230
};
144231
v.build_provider_relation_sets(&firebolt_open_rpc.methods);
@@ -172,21 +259,29 @@ impl OpenRpcState {
172259

173260
// Add extension open rpc to the validator
174261
pub fn add_extension_open_rpc_to_validator(&self, path: String) -> Result<(), RippleError> {
175-
let extension_open_rpc_string = load_extension_open_rpc(path);
176-
if let Some(open_rpc) = extension_open_rpc_string {
177-
return match serde_json::from_str::<FireboltOpenRpcValidator>(&open_rpc) {
178-
Ok(additional_open_rpc_validator) => {
179-
let mut validator = self.openrpc_validator.write().unwrap();
180-
validator.add_schema(additional_open_rpc_validator);
181-
return Ok(());
182-
}
183-
Err(e) => {
184-
error!("Error parsing openrpc validator from e={:?}", e);
185-
Err(RippleError::ParseError)
186-
}
262+
#[cfg(feature = "openrpc_validation")]
263+
{
264+
let extension_open_rpc_string = load_extension_open_rpc(path);
265+
if let Some(open_rpc) = extension_open_rpc_string {
266+
return match serde_json::from_str::<FireboltOpenRpcValidator>(&open_rpc) {
267+
Ok(additional_open_rpc_validator) => {
268+
let mut validator = self.openrpc_validator.write().unwrap();
269+
validator.add_schema(additional_open_rpc_validator);
270+
return Ok(());
271+
}
272+
Err(e) => {
273+
error!("Error parsing openrpc validator from e={:?}", e);
274+
Err(RippleError::ParseError)
275+
}
276+
};
187277
};
188-
};
189-
Err(RippleError::ParseError)
278+
Err(RippleError::ParseError)
279+
}
280+
#[cfg(not(feature = "openrpc_validation"))]
281+
{
282+
let _ = path; // Suppress unused variable warning
283+
Ok(()) // No-op when validation is disabled
284+
}
190285
}
191286

192287
pub fn is_excluded(&self, method: String, app_id: String) -> bool {
@@ -434,11 +529,18 @@ impl OpenRpcState {
434529
.extend(provider_relation_sets)
435530
}
436531

532+
#[cfg(feature = "openrpc_validation")]
437533
pub fn add_json_schema_cache(&self, method: String, schema: JSONSchema) {
438534
let mut json_cache = self.json_schema_cache.write().unwrap();
439535
let _ = json_cache.insert(method, schema);
440536
}
441537

538+
#[cfg(not(feature = "openrpc_validation"))]
539+
pub fn add_json_schema_cache(&self, method: String, schema: JSONSchema) {
540+
let _ = (method, schema); // Suppress unused variable warnings
541+
}
542+
543+
#[cfg(feature = "openrpc_validation")]
442544
pub fn validate_schema(&self, method: &str, value: &Value) -> Result<(), Option<String>> {
443545
let json_cache = self.json_schema_cache.read().unwrap();
444546
if let Some(schema) = json_cache.get(method) {
@@ -455,6 +557,12 @@ impl OpenRpcState {
455557
Err(None)
456558
}
457559
}
560+
561+
#[cfg(not(feature = "openrpc_validation"))]
562+
pub fn validate_schema(&self, method: &str, value: &Value) -> Result<(), Option<String>> {
563+
let _ = (method, value); // Suppress unused variable warnings
564+
Err(None) // Always return "not found" when validation is disabled
565+
}
458566
}
459567

460568
fn load_firebolt_open_rpc_from_file(fb_open_rpc_file: &str) -> Result<String, RippleError> {
@@ -516,6 +624,7 @@ fn load_firebolt_open_rpc_path() -> Result<String, RippleError> {
516624
load_firebolt_open_rpc_from_file("/etc/ripple/openrpc/firebolt-open-rpc.json")
517625
}
518626

627+
#[allow(dead_code)]
519628
fn load_extension_open_rpc(path: String) -> Option<String> {
520629
match std::fs::read_to_string(&path) {
521630
Ok(content) => {

openrpc_validator/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ edition = "2021"
55

66
[dependencies]
77
jsonschema = { version = "0.17.1", default-features = false }
8-
serde_json.workspace = true
9-
serde.workspace = true
10-
clap = {version = "=4.0", features = ["std"], default-features = false} # std required during ripple start
8+
serde_json = { version = "1.0", default-features = false }
9+
serde = { version = "1.0", features = ["derive"], default-features = false }
10+
clap = { version = "=4.0", features = ["std"], default-features = false }

0 commit comments

Comments
 (0)