From acd770e5e626b219bcb72d8e4126ddde6b3bffaa Mon Sep 17 00:00:00 2001 From: Ruslan Pislari Date: Tue, 15 Oct 2024 21:35:19 +0300 Subject: [PATCH 1/4] feat: impl draft secret libs --- Cargo.lock | 14 ++++++ Cargo.toml | 1 + crates/http-service/Cargo.toml | 1 + crates/http-service/src/executor/mod.rs | 20 +++++--- crates/http-service/src/executor/wasi_http.rs | 17 +++++-- crates/http-service/src/lib.rs | 19 +++++--- crates/http-service/src/state.rs | 6 ++- crates/reactor/src/lib.rs | 2 +- crates/runtime/src/app.rs | 10 ++++ crates/runtime/src/lib.rs | 2 +- crates/secret/Cargo.toml | 18 +++++++ crates/secret/src/lib.rs | 35 ++++++++++++++ sdk | 2 +- src/main.rs | 48 +++++++++++++++---- src/secret.rs | 44 +++++++++++++++++ 15 files changed, 206 insertions(+), 33 deletions(-) create mode 100644 crates/secret/Cargo.toml create mode 100644 crates/secret/src/lib.rs create mode 100644 src/secret.rs diff --git a/Cargo.lock b/Cargo.lock index 2358de5..ac68f9d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -513,6 +513,7 @@ dependencies = [ "hyper-util", "pretty_env_logger", "runtime", + "secret", "shellflip", "smol_str", "tokio", @@ -1421,6 +1422,7 @@ dependencies = [ "prometheus", "reactor", "runtime", + "secret", "serde", "shellflip", "smol_str", @@ -2618,6 +2620,18 @@ dependencies = [ "syn", ] +[[package]] +name = "secret" +version = "0.6.0" +dependencies = [ + "anyhow", + "async-trait", + "reactor", + "runtime", + "tracing", + "wasmtime", +] + [[package]] name = "security-framework" version = "2.11.1" diff --git a/Cargo.toml b/Cargo.toml index 2fd942e..b77c0fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,6 +58,7 @@ runtime = { path = "crates/runtime", default-features = false } http-service = { path = "crates/http-service" } http-backend = { path = "crates/http-backend" } dictionary = { path = "crates/dictionary" } +secret = { path = "crates/secret" } hyper-tls = "0.6" hyper-util = { version = "0.1", features = ["client", "client-legacy", "http1", "tokio"] } http-body-util = "0.1" diff --git a/crates/http-service/Cargo.toml b/crates/http-service/Cargo.toml index 9d27132..91103ef 100644 --- a/crates/http-service/Cargo.toml +++ b/crates/http-service/Cargo.toml @@ -26,6 +26,7 @@ reactor = { path = "../reactor" } runtime = { path = "../runtime" } http-backend = { path = "../http-backend" } dictionary = { path = "../dictionary" } +secret = { path = "../secret" } nanoid = "0.4" bytesize = "1.3.0" futures = "0.3.30" diff --git a/crates/http-service/src/executor/mod.rs b/crates/http-service/src/executor/mod.rs index 32e3d76..b5f556d 100644 --- a/crates/http-service/src/executor/mod.rs +++ b/crates/http-service/src/executor/mod.rs @@ -16,10 +16,10 @@ use hyper::body::{Body, Bytes}; use reactor::gcore::fastedge; use runtime::store::StoreBuilder; use runtime::{App, InstancePre, WasmEngine}; +use secret::{Secret, SecretStrategy}; use smol_str::SmolStr; -use wasmtime_wasi::StdoutStream; - pub use wasi_http::WasiHttpExecutorImpl; +use wasmtime_wasi::StdoutStream; pub(crate) static X_REAL_IP: &str = "x-real-ip"; pub(crate) static TRACEPARENT: &str = "traceparent"; @@ -48,17 +48,19 @@ pub trait ExecutorFactory { /// Execute context used by ['HttpService'] #[derive(Clone)] -pub struct HttpExecutorImpl { - instance_pre: InstancePre>, +pub struct HttpExecutorImpl { + instance_pre: InstancePre>, store_builder: StoreBuilder, backend: Backend, dictionary: Dictionary, + secret: Secret, } #[async_trait] -impl HttpExecutor for HttpExecutorImpl +impl HttpExecutor for HttpExecutorImpl where C: Clone + Send + Sync + 'static, + T: SecretStrategy + Clone + Send + Sync, { async fn execute( &self, @@ -75,21 +77,24 @@ where } } -impl HttpExecutorImpl +impl HttpExecutorImpl where C: Clone + Send + Sync + 'static, + T: SecretStrategy + Clone + Send, { pub fn new( - instance_pre: InstancePre>, + instance_pre: InstancePre>, store_builder: StoreBuilder, backend: Backend, dictionary: Dictionary, + secret: Secret, ) -> Self { Self { instance_pre, store_builder, backend, dictionary, + secret, } } @@ -152,6 +157,7 @@ where propagate_headers: parts.headers, propagate_header_names, dictionary: self.dictionary.clone(), + secret: self.secret.clone(), }; let mut store = store_builder.build(state)?; diff --git a/crates/http-service/src/executor/wasi_http.rs b/crates/http-service/src/executor/wasi_http.rs index 05c6ae1..b13bc15 100644 --- a/crates/http-service/src/executor/wasi_http.rs +++ b/crates/http-service/src/executor/wasi_http.rs @@ -15,23 +15,26 @@ use http_body_util::{BodyExt, Full}; use hyper::body::{Body, Bytes}; use runtime::store::StoreBuilder; use runtime::InstancePre; +use secret::{Secret, SecretStrategy}; use smol_str::ToSmolStr; use tracing::error; use wasmtime_wasi_http::WasiHttpView; /// Execute context used by ['HttpService'] #[derive(Clone)] -pub struct WasiHttpExecutorImpl { - instance_pre: InstancePre>, +pub struct WasiHttpExecutorImpl { + instance_pre: InstancePre>, store_builder: StoreBuilder, backend: Backend, dictionary: Dictionary, + secret: Secret, } #[async_trait] -impl HttpExecutor for WasiHttpExecutorImpl +impl HttpExecutor for WasiHttpExecutorImpl where C: Clone + Send + Sync + 'static, + T: SecretStrategy + Clone + Send + Sync + 'static, { async fn execute( &self, @@ -48,21 +51,24 @@ where } } -impl WasiHttpExecutorImpl +impl WasiHttpExecutorImpl where C: Clone + Send + Sync + 'static, + T: SecretStrategy + Clone + Send + 'static, { pub fn new( - instance_pre: InstancePre>, + instance_pre: InstancePre>, store_builder: StoreBuilder, backend: Backend, dictionary: Dictionary, + secret: Secret, ) -> Self { Self { instance_pre, store_builder, backend, dictionary, + secret, } } @@ -135,6 +141,7 @@ where propagate_headers, propagate_header_names, dictionary: self.dictionary.clone(), + secret: self.secret.clone(), }; let mut store = store_builder.build(state).context("store build")?; diff --git a/crates/http-service/src/lib.rs b/crates/http-service/src/lib.rs index 59b16d5..46ec437 100644 --- a/crates/http-service/src/lib.rs +++ b/crates/http-service/src/lib.rs @@ -24,6 +24,7 @@ use runtime::util::metrics; use runtime::util::stats::StatRow; use runtime::util::stats::StatsWriter; use runtime::{App, AppResult, ContextT, Router, WasmEngine, WasmEngineBuilder}; +use secret::SecretStrategy; use shellflip::ShutdownHandle; use smol_str::SmolStr; use state::HttpState; @@ -56,8 +57,8 @@ pub struct HttpConfig { pub backoff: u64, } -pub struct HttpService { - engine: WasmEngine>, +pub struct HttpService { + engine: WasmEngine>, context: T, } @@ -65,20 +66,21 @@ pub trait ContextHeaders { fn append_headers(&self) -> impl Iterator; } -impl Service for HttpService +impl Service for HttpService where T: ContextT + StatsWriter + Router + ContextHeaders - + ExecutorFactory> + + ExecutorFactory> + Sync + Send + 'static, T::BackendConnector: Connect + Clone + Send + Sync + 'static, T::Executor: HttpExecutor + Send + Sync, + S: SecretStrategy + Send + Sync + 'static, { - type State = HttpState; + type State = HttpState; type Config = HttpConfig; type Context = T; @@ -147,22 +149,25 @@ where &mut data.as_mut().dictionary })?; + reactor::gcore::fastedge::secret::add_to_linker(linker, |data| &mut data.as_mut().secret)?; + Ok(()) } } -impl HttpService +impl HttpService where T: ContextT + StatsWriter + Router + ContextHeaders - + ExecutorFactory> + + ExecutorFactory> + Sync + Send + 'static, T::BackendConnector: Clone + Send + Sync + 'static, T::Executor: HttpExecutor + Send + Sync, + U: SecretStrategy, { async fn serve(self: Arc, stream: S, _cancel: Arc) where diff --git a/crates/http-service/src/state.rs b/crates/http-service/src/state.rs index 49a64d1..60a52ab 100644 --- a/crates/http-service/src/state.rs +++ b/crates/http-service/src/state.rs @@ -5,20 +5,22 @@ use http::uri::Scheme; use http::{header, HeaderMap, HeaderName, Uri}; use http_backend::Backend; use runtime::BackendRequest; +use secret::{Secret, SecretStrategy}; use smol_str::{SmolStr, ToSmolStr}; use tracing::instrument; use wasmtime_wasi_nn::WasiNnCtx; -pub struct HttpState { +pub struct HttpState { pub(super) wasi_nn: WasiNnCtx, pub(super) http_backend: Backend, pub(super) uri: Uri, pub(super) propagate_headers: HeaderMap, pub(super) propagate_header_names: Vec, pub(super) dictionary: Dictionary, + pub(super) secret: Secret, } -impl BackendRequest for HttpState { +impl BackendRequest for HttpState { #[instrument(skip(self), ret, err)] fn backend_request(&mut self, mut head: Parts) -> anyhow::Result<(String, Parts)> { let original_url = head.uri; diff --git a/crates/reactor/src/lib.rs b/crates/reactor/src/lib.rs index 4eadd93..276330b 100644 --- a/crates/reactor/src/lib.rs +++ b/crates/reactor/src/lib.rs @@ -2,7 +2,7 @@ wasmtime::component::bindgen!({ path: "../../sdk/wit", - world: "http-reactor", + world: "reactor", async: true, tracing: false, }); diff --git a/crates/runtime/src/app.rs b/crates/runtime/src/app.rs index 14ee338..9f52eba 100644 --- a/crates/runtime/src/app.rs +++ b/crates/runtime/src/app.rs @@ -25,6 +25,16 @@ pub struct App { pub status: Status, #[serde(default)] pub debug_until: Option>, + #[serde(default)] + pub secrets: HashMap, +} + +pub type SecretValues = Vec; + +#[derive(Debug, Clone, PartialEq, Deserialize)] +pub struct SecretValue { + pub effective_from: u64, + pub value: String, } #[derive(Debug, Default, Clone, Copy, PartialEq, Deserialize)] diff --git a/crates/runtime/src/lib.rs b/crates/runtime/src/lib.rs index ad65131..4cfc2a1 100644 --- a/crates/runtime/src/lib.rs +++ b/crates/runtime/src/lib.rs @@ -26,7 +26,7 @@ pub mod util; use crate::logger::Logger; use anyhow::{anyhow, bail}; -pub use app::App; +pub use app::{App, SecretValue, SecretValues}; use http::request::Parts; use http::Request; use smol_str::SmolStr; diff --git a/crates/secret/Cargo.toml b/crates/secret/Cargo.toml new file mode 100644 index 0000000..9295b54 --- /dev/null +++ b/crates/secret/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "secret" +version.workspace = true +edition.workspace = true +publish.workspace = true +authors.workspace = true +description = "secret host function" + +[dependencies] +reactor = { path = "../reactor" } +runtime = { path = "../runtime" } +anyhow = {workspace = true} +tracing = {workspace = true} +async-trait = {workspace = true} +wasmtime = {workspace = true} + +[lints] +workspace = true diff --git a/crates/secret/src/lib.rs b/crates/secret/src/lib.rs new file mode 100644 index 0000000..51638b7 --- /dev/null +++ b/crates/secret/src/lib.rs @@ -0,0 +1,35 @@ +use async_trait::async_trait; +use reactor::gcore::fastedge::secret; + +pub trait SecretStrategy { + fn get(&self, key: String) -> anyhow::Result>>; +} + +#[derive(Clone)] +pub struct Secret { + strategy: T, +} + +#[async_trait] +impl secret::Host for Secret { + async fn get( + &mut self, + key: String, + ) -> wasmtime::Result, secret::Error>> { + Ok(match self.strategy.get(key) { + Ok(None) => Ok(None), + Ok(Some(plaintext)) => Ok(Some(String::from_utf8(plaintext)?)), + Err(error) => { + tracing::warn!(cause=?error, "error reading secret"); + Err(secret::Error::DecryptError) + } + }) + } +} + +impl Secret { + pub fn new(strategy: T) -> Self { + Self { strategy } + } +} + diff --git a/sdk b/sdk index 5e07465..3017fd5 160000 --- a/sdk +++ b/sdk @@ -1 +1 @@ -Subproject commit 5e0746539c11eb3d72bef23b327d7b4148515aa0 +Subproject commit 3017fd571cae7f47d4f2875054aa1e73e8fb442d diff --git a/src/main.rs b/src/main.rs index c97b00a..478977a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,7 @@ +mod secret; + +use crate::secret::SecretImpl; +use ::secret::Secret; use async_trait::async_trait; use bytesize::{ByteSize, MB}; use clap::{Args, Parser, Subcommand}; @@ -20,7 +24,7 @@ use runtime::service::{Service, ServiceBuilder}; use runtime::util::stats::{StatRow, StatsWriter}; use runtime::{ componentize_if_necessary, App, ContextT, ExecutorCache, PreCompiledLoader, Router, - WasiVersion, WasmConfig, WasmEngine, + SecretValue, WasiVersion, WasmConfig, WasmEngine, }; use shellflip::ShutdownCoordinator; use smol_str::{SmolStr, ToSmolStr}; @@ -53,8 +57,8 @@ struct HttpRunArgs { #[arg(short, long)] wasm: PathBuf, /// Environment variable list - #[arg(long, value_parser = parse_key_value::)] - envs: Option>, + #[arg(short, long, value_parser = parse_key_value::)] + env: Option>, /// Add header from original request #[arg(long = "propagate-header", num_args = 0..)] propagate_headers: Vec, @@ -73,6 +77,9 @@ struct HttpRunArgs { /// Enable WASI HTTP interface #[arg(long)] wasi_http: Option, + /// Secret variable list + #[arg(short, long, value_parser = parse_key_value::)] + secret: Option>, } /// Test tool execution context @@ -108,7 +115,7 @@ async fn main() -> anyhow::Result<()> { binary_id: 0, max_duration: run.max_duration.map(|m| m / 10).unwrap_or(60000), mem_limit: run.mem_limit.unwrap_or((128 * MB) as usize), - env: run.envs.unwrap_or_default().into_iter().collect(), + env: run.env.unwrap_or_default().into_iter().collect(), rsp_headers: Default::default(), log: Default::default(), app_id: 0, @@ -116,6 +123,20 @@ async fn main() -> anyhow::Result<()> { plan: SmolStr::new("cli"), status: Status::Enabled, debug_until: None, + secrets: run + .secret + .unwrap_or_default() + .into_iter() + .map(|(k, v)| { + ( + k, + vec![SecretValue { + effective_from: 0, + value: v.to_string(), + }], + ) + }) + .collect(), }; let mut headers: HashMap = @@ -132,7 +153,7 @@ async fn main() -> anyhow::Result<()> { wasi_http: run.wasi_http.unwrap_or_default(), }; - let http: HttpService = ServiceBuilder::new(context).build()?; + let http: HttpService = ServiceBuilder::new(context).build()?; let http = http.run(HttpConfig { all_interfaces: false, port: run.port, @@ -206,8 +227,8 @@ impl ContextT for CliContext { } enum CliExecutor { - Http(HttpExecutorImpl>), - Wasi(WasiHttpExecutorImpl>), + Http(HttpExecutorImpl, SecretImpl>), + Wasi(WasiHttpExecutorImpl, SecretImpl>), } #[async_trait] @@ -227,19 +248,26 @@ impl HttpExecutor for CliExecutor { } } -impl ExecutorFactory>> for CliContext { +impl ExecutorFactory, SecretImpl>> for CliContext { type Executor = CliExecutor; fn get_executor( &self, name: SmolStr, app: &App, - engine: &WasmEngine>>, + engine: &WasmEngine, SecretImpl>>, ) -> anyhow::Result { let mut dictionary = Dictionary::new(); for (k, v) in app.env.iter() { dictionary.insert(k.to_string(), v.to_string()); } + let mut secret_impl = SecretImpl::new(); + for (k, v) in app.secrets.iter() { + if let Some(value) = v.first() { + secret_impl.insert(k.to_string(), value.value.to_string()); + } + } + let secret = Secret::new(secret_impl); let env = app.env.iter().collect::>(); @@ -261,6 +289,7 @@ impl ExecutorFactory>> for CliContext { store_builder, self.backend(), dictionary, + secret, ))) } else { Ok(CliExecutor::Http(HttpExecutorImpl::new( @@ -268,6 +297,7 @@ impl ExecutorFactory>> for CliContext { store_builder, self.backend(), dictionary, + secret, ))) } } diff --git a/src/secret.rs b/src/secret.rs new file mode 100644 index 0000000..795e30b --- /dev/null +++ b/src/secret.rs @@ -0,0 +1,44 @@ +use secret::SecretStrategy; +use std::collections::HashMap; +use std::ops::{Deref, DerefMut}; + +#[derive(Clone)] +pub struct SecretImpl { + inner: HashMap, +} + +impl SecretStrategy for SecretImpl { + fn get(&self, key: String) -> anyhow::Result>> { + Ok(self.inner.get(&key).map(|v| v.as_bytes().to_vec())) + } +} + +impl Default for SecretImpl { + fn default() -> Self { + Self { + inner: Default::default(), + } + } +} + +impl SecretImpl { + pub fn new() -> Self { + Self { + inner: Default::default(), + } + } +} + +impl Deref for SecretImpl { + type Target = HashMap; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for SecretImpl { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} From 33c2c95014c89b4a04079b53d636f031d6481200 Mon Sep 17 00:00:00 2001 From: Ruslan Pislari Date: Mon, 21 Oct 2024 15:42:59 +0300 Subject: [PATCH 2/4] forward sdk submodule --- sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk b/sdk index 3017fd5..e978106 160000 --- a/sdk +++ b/sdk @@ -1 +1 @@ -Subproject commit 3017fd571cae7f47d4f2875054aa1e73e8fb442d +Subproject commit e9781068b78c8c9a99bb2d85a377ef4e2e58b710 From 18800b70db8037ea3d5fb068644916a60a305a2d Mon Sep 17 00:00:00 2001 From: Ruslan Pislari Date: Mon, 21 Oct 2024 15:44:25 +0300 Subject: [PATCH 3/4] feat: secret common lib implementation --- Cargo.lock | 2 +- crates/http-service/src/lib.rs | 38 +++++++++++++++++++++++----------- crates/runtime/src/app.rs | 20 +++++++++++++++--- crates/secret/src/lib.rs | 1 - src/main.rs | 34 +++++++++++++++--------------- 5 files changed, 61 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ac68f9d..a219e85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2622,7 +2622,7 @@ dependencies = [ [[package]] name = "secret" -version = "0.6.0" +version = "0.7.0" dependencies = [ "anyhow", "async-trait", diff --git a/crates/http-service/src/lib.rs b/crates/http-service/src/lib.rs index 46ec437..7661363 100644 --- a/crates/http-service/src/lib.rs +++ b/crates/http-service/src/lib.rs @@ -571,10 +571,10 @@ mod tests { use wasmtime::component::Component; use wasmtime::{Engine, Module}; + use super::*; use crate::executor::HttpExecutorImpl; use runtime::util::stats::StatRow; - - use super::*; + use secret::Secret; #[test_case("app.server.com", "server.com", "app"; "get app name from server_name header")] fn test_app_name_from_request(server_name: &str, uri: &str, expected: &str) { @@ -661,19 +661,29 @@ mod tests { } } - impl ExecutorFactory> for TestContext { - type Executor = HttpExecutorImpl; + #[derive(Clone)] + struct TestSecret; + + impl SecretStrategy for TestSecret { + fn get(&self, _key: String) -> Result>> { + Ok(Some(b"secret".to_vec())) + } + } + + impl ExecutorFactory> for TestContext { + type Executor = HttpExecutorImpl; fn get_executor( &self, name: SmolStr, cfg: &App, - engine: &WasmEngine>, + engine: &WasmEngine>, ) -> Result { let mut dictionary = Dictionary::new(); for (k, v) in cfg.env.iter() { dictionary.insert(k.to_string(), v.to_string()); } + let secret = Secret::new(TestSecret); let env = cfg.env.iter().collect::>(); @@ -695,6 +705,7 @@ mod tests { store_builder, self.backend(), dictionary, + secret, )) } } @@ -715,6 +726,7 @@ mod tests { plan: "test_plan".to_smolstr(), status, debug_until: None, + secrets: vec![], }) } @@ -755,7 +767,7 @@ mod tests { engine: make_engine(), }; - let http_service: HttpService = + let http_service: HttpService = assert_ok!(ServiceBuilder::new(context).build()); let res = assert_ok!(http_service.handle_request("1", req).await); @@ -796,6 +808,7 @@ mod tests { plan: "test_plan".to_smolstr(), status: Status::Enabled, debug_until: None, + secrets: vec![], }); let context = TestContext { @@ -804,7 +817,7 @@ mod tests { engine: make_engine(), }; - let http_service: HttpService = + let http_service: HttpService = assert_ok!(ServiceBuilder::new(context).build()); let res = assert_ok!(http_service.handle_request("2", req).await); @@ -844,6 +857,7 @@ mod tests { plan: "test_plan".to_smolstr(), status: Status::Enabled, debug_until: None, + secrets: vec![], }); let context = TestContext { @@ -852,7 +866,7 @@ mod tests { engine: make_engine(), }; - let http_service: HttpService = + let http_service: HttpService = assert_ok!(ServiceBuilder::new(context).build()); let res = assert_ok!(http_service.handle_request("3", req).await); @@ -886,7 +900,7 @@ mod tests { engine: make_engine(), }; - let http_service: HttpService = + let http_service: HttpService = assert_ok!(ServiceBuilder::new(context).build()); let res = assert_ok!(http_service.handle_request("4", req).await); assert_eq!(StatusCode::NOT_FOUND, res.status()); @@ -912,7 +926,7 @@ mod tests { engine: make_engine(), }; - let http_service: HttpService = + let http_service: HttpService = assert_ok!(ServiceBuilder::new(context).build()); let res = assert_ok!(http_service.handle_request("5", req).await); assert_eq!(StatusCode::NOT_FOUND, res.status()); @@ -938,7 +952,7 @@ mod tests { engine: make_engine(), }; - let http_service: HttpService = + let http_service: HttpService = assert_ok!(ServiceBuilder::new(context).build()); let res = assert_ok!(http_service.handle_request("6", req).await); assert_eq!(StatusCode::TOO_MANY_REQUESTS, res.status()); @@ -964,7 +978,7 @@ mod tests { engine: make_engine(), }; - let http_service: HttpService = + let http_service: HttpService = assert_ok!(ServiceBuilder::new(context).build()); let res = assert_ok!(http_service.handle_request("7", req).await); assert_eq!(StatusCode::NOT_ACCEPTABLE, res.status()); diff --git a/crates/runtime/src/app.rs b/crates/runtime/src/app.rs index 9f52eba..2ee1b35 100644 --- a/crates/runtime/src/app.rs +++ b/crates/runtime/src/app.rs @@ -26,7 +26,7 @@ pub struct App { #[serde(default)] pub debug_until: Option>, #[serde(default)] - pub secrets: HashMap, + pub secrets: Vec, } pub type SecretValues = Vec; @@ -37,6 +37,12 @@ pub struct SecretValue { pub value: String, } +#[derive(Debug, Clone, PartialEq, Deserialize)] +pub struct Secret { + pub name: SmolStr, + pub secret_values: SecretValues, +} + #[derive(Debug, Default, Clone, Copy, PartialEq, Deserialize)] #[serde(rename_all = "snake_case")] pub enum Log { @@ -71,7 +77,7 @@ impl<'de> Visitor<'de> for StatusVisitor { formatter.write_str("unsigned integer value") } - fn visit_u64(self, v: u64) -> std::result::Result + fn visit_u64(self, v: u64) -> Result where E: serde::de::Error, { @@ -124,7 +130,8 @@ mod tests { "client_id": 23456, "plan": "test_plan", "status": 1, - "debug_until": "2037-01-01T12:00:27.87Z" + "debug_until": "2037-01-01T12:00:27.87Z", + "secrets":[{"name":"SECRET","secret_values":[{"effective_from":0,"value":"encrypted"}]}] }); let json = assert_ok!(serde_json::to_string_pretty(&json)); @@ -141,6 +148,13 @@ mod tests { plan: "test_plan".to_smolstr(), status: Status::Enabled, debug_until: Some(assert_ok!("2037-01-01T12:00:27.87Z".parse())), + secrets: vec![Secret { + name: "SECRET".to_smolstr(), + secret_values: vec![SecretValue { + effective_from: 0, + value: "encrypted".to_string(), + }], + }], }; assert_eq!(expected, assert_ok!(serde_json::from_str(&json))); diff --git a/crates/secret/src/lib.rs b/crates/secret/src/lib.rs index 51638b7..864058e 100644 --- a/crates/secret/src/lib.rs +++ b/crates/secret/src/lib.rs @@ -32,4 +32,3 @@ impl Secret { Self { strategy } } } - diff --git a/src/main.rs b/src/main.rs index 478977a..61d6dc1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -111,6 +111,19 @@ async fn main() -> anyhow::Result<()> { builder.propagate_headers_names(run.propagate_headers); let backend = builder.build(backend_connector); + let mut secrets = vec![]; + if let Some(secret) = run.secret { + for (name, s) in secret.into_iter() { + secrets.push(runtime::app::Secret { + name, + secret_values: vec![SecretValue { + effective_from: 0, + value: s.to_string(), + }], + }); + } + } + let cli_app = App { binary_id: 0, max_duration: run.max_duration.map(|m| m / 10).unwrap_or(60000), @@ -123,20 +136,7 @@ async fn main() -> anyhow::Result<()> { plan: SmolStr::new("cli"), status: Status::Enabled, debug_until: None, - secrets: run - .secret - .unwrap_or_default() - .into_iter() - .map(|(k, v)| { - ( - k, - vec![SecretValue { - effective_from: 0, - value: v.to_string(), - }], - ) - }) - .collect(), + secrets, }; let mut headers: HashMap = @@ -262,9 +262,9 @@ impl ExecutorFactory, SecretImpl>> for C dictionary.insert(k.to_string(), v.to_string()); } let mut secret_impl = SecretImpl::new(); - for (k, v) in app.secrets.iter() { - if let Some(value) = v.first() { - secret_impl.insert(k.to_string(), value.value.to_string()); + for s in app.secrets.iter() { + if let Some(value) = s.secret_values.first() { + secret_impl.insert(s.name.to_string(), value.value.to_string()); } } let secret = Secret::new(secret_impl); From a987b5419410fcc2f61d8da88306f3648f35e358 Mon Sep 17 00:00:00 2001 From: Ruslan Pislari Date: Mon, 21 Oct 2024 15:55:08 +0300 Subject: [PATCH 4/4] fix: minor clippy error fix --- src/main.rs | 2 +- src/secret.rs | 18 +----------------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/src/main.rs b/src/main.rs index 61d6dc1..1383668 100644 --- a/src/main.rs +++ b/src/main.rs @@ -261,7 +261,7 @@ impl ExecutorFactory, SecretImpl>> for C for (k, v) in app.env.iter() { dictionary.insert(k.to_string(), v.to_string()); } - let mut secret_impl = SecretImpl::new(); + let mut secret_impl = SecretImpl::default(); for s in app.secrets.iter() { if let Some(value) = s.secret_values.first() { secret_impl.insert(s.name.to_string(), value.value.to_string()); diff --git a/src/secret.rs b/src/secret.rs index 795e30b..2ddcf89 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -2,7 +2,7 @@ use secret::SecretStrategy; use std::collections::HashMap; use std::ops::{Deref, DerefMut}; -#[derive(Clone)] +#[derive(Clone, Default)] pub struct SecretImpl { inner: HashMap, } @@ -13,22 +13,6 @@ impl SecretStrategy for SecretImpl { } } -impl Default for SecretImpl { - fn default() -> Self { - Self { - inner: Default::default(), - } - } -} - -impl SecretImpl { - pub fn new() -> Self { - Self { - inner: Default::default(), - } - } -} - impl Deref for SecretImpl { type Target = HashMap;