feat(vars): VarsService + vars:: SDK + config capabilities
Scripts can now read group-inherited config via vars::get(key) / vars::all(). - shared: VarsService trait (read-only get/all) + NoopVarsService; added as the 14th field on the Services bundle. - manager-core: VarsServiceImpl resolves the calling app's config via config_resolver (derives app_id from cx.app_id; AppVarsRead-gated for authed principals, script-as-gate for anon). - executor-core: vars:: Rhai bridge (get/all), registered in the SDK. - authz: AppVarsRead/Write, GroupVarsRead/Write, GroupSecretsRead/Write capabilities (group caps resolve via the Phase-2 ancestor walk; the GroupSecretsRead human-read gate is group_admin-only, distinct from an app's runtime injection). - wired VarsServiceImpl into the picloud binary; updated the executor-core test Services::new call sites. 386 manager-core lib tests green; clippy clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,7 @@ pub mod retry;
|
||||
pub mod secrets;
|
||||
pub mod stdlib;
|
||||
pub mod users;
|
||||
pub mod vars;
|
||||
|
||||
pub use bridge::{dynamic_to_json, json_to_dynamic};
|
||||
pub use cx::SdkCallCx;
|
||||
@@ -62,6 +63,7 @@ pub fn register_all(
|
||||
queue::register(engine, services, cx.clone());
|
||||
retry::register(engine, services, cx.clone());
|
||||
secrets::register(engine, services, cx.clone());
|
||||
vars::register(engine, services, cx.clone());
|
||||
email::register(engine, services, cx.clone());
|
||||
users::register(engine, services, cx.clone());
|
||||
invoke::register(engine, services, cx, limits, self_engine);
|
||||
|
||||
57
crates/executor-core/src/sdk/vars.rs
Normal file
57
crates/executor-core/src/sdk/vars.rs
Normal file
@@ -0,0 +1,57 @@
|
||||
//! `vars::` Rhai bridge — read-only access to the app's resolved,
|
||||
//! group-inherited config (Phase 3).
|
||||
//!
|
||||
//! ```rhai
|
||||
//! let region = vars::get("region"); // value or ()
|
||||
//! let all = vars::all(); // #{ key: value, ... }
|
||||
//! ```
|
||||
//!
|
||||
//! Values are inherited down the group tree and env-filtered (§3); the
|
||||
//! resolution happens server-side in manager-core. Writes go through the
|
||||
//! admin API, not the SDK. `app_id` is derived from `cx.app_id` in the
|
||||
//! service — never a script argument — preserving cross-app isolation.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use picloud_shared::{SdkCallCx, Services};
|
||||
use rhai::{Dynamic, Engine as RhaiEngine, EvalAltResult, Map, Module};
|
||||
|
||||
use super::bridge::{block_on, json_to_dynamic};
|
||||
|
||||
pub(super) fn register(engine: &mut RhaiEngine, services: &Services, cx: Arc<SdkCallCx>) {
|
||||
let svc = services.vars.clone();
|
||||
let mut module = Module::new();
|
||||
|
||||
// vars::get(key) — resolved value, or () if no level defines it.
|
||||
{
|
||||
let svc = svc.clone();
|
||||
let cx = cx.clone();
|
||||
module.set_native_fn(
|
||||
"get",
|
||||
move |key: &str| -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let svc = svc.clone();
|
||||
let cx = cx.clone();
|
||||
let opt = block_on("vars", async move { svc.get(&cx, key).await })?;
|
||||
Ok(opt.map_or(Dynamic::UNIT, json_to_dynamic))
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// vars::all() — the fully-resolved config map.
|
||||
{
|
||||
let svc = svc.clone();
|
||||
let cx = cx.clone();
|
||||
module.set_native_fn("all", move || -> Result<Map, Box<EvalAltResult>> {
|
||||
let svc = svc.clone();
|
||||
let cx = cx.clone();
|
||||
let resolved = block_on("vars", async move { svc.all(&cx).await })?;
|
||||
let mut m = Map::new();
|
||||
for (k, v) in resolved {
|
||||
m.insert(k.into(), json_to_dynamic(v));
|
||||
}
|
||||
Ok(m)
|
||||
});
|
||||
}
|
||||
|
||||
engine.register_static_module("vars", module.into());
|
||||
}
|
||||
@@ -107,6 +107,7 @@ async fn original_backend_error_is_logged_at_error_level() {
|
||||
Arc::new(picloud_shared::NoopUsersService),
|
||||
Arc::new(picloud_shared::NoopQueueService),
|
||||
Arc::new(picloud_shared::NoopInvokeService),
|
||||
Arc::new(picloud_shared::NoopVarsService),
|
||||
);
|
||||
let engine = Engine::new(Limits::default(), services);
|
||||
|
||||
|
||||
@@ -104,6 +104,7 @@ fn services_with(modules: Arc<dyn ModuleSource>) -> Services {
|
||||
Arc::new(picloud_shared::NoopUsersService),
|
||||
Arc::new(picloud_shared::NoopQueueService),
|
||||
Arc::new(picloud_shared::NoopInvokeService),
|
||||
Arc::new(picloud_shared::NoopVarsService),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -235,6 +235,7 @@ fn make_engine() -> Arc<Engine> {
|
||||
Arc::new(picloud_shared::NoopUsersService),
|
||||
Arc::new(picloud_shared::NoopQueueService),
|
||||
Arc::new(picloud_shared::NoopInvokeService),
|
||||
Arc::new(picloud_shared::NoopVarsService),
|
||||
);
|
||||
Arc::new(Engine::new(Limits::default(), services))
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ fn engine_with(rec: Arc<RecordingEmail>) -> Arc<Engine> {
|
||||
Arc::new(picloud_shared::NoopUsersService),
|
||||
Arc::new(picloud_shared::NoopQueueService),
|
||||
Arc::new(picloud_shared::NoopInvokeService),
|
||||
Arc::new(picloud_shared::NoopVarsService),
|
||||
);
|
||||
Arc::new(Engine::new(Limits::default(), services))
|
||||
}
|
||||
|
||||
@@ -172,6 +172,7 @@ fn make_engine() -> Arc<Engine> {
|
||||
Arc::new(picloud_shared::NoopUsersService),
|
||||
Arc::new(picloud_shared::NoopQueueService),
|
||||
Arc::new(picloud_shared::NoopInvokeService),
|
||||
Arc::new(picloud_shared::NoopVarsService),
|
||||
);
|
||||
Arc::new(Engine::new(Limits::default(), services))
|
||||
}
|
||||
|
||||
@@ -95,6 +95,7 @@ fn engine_with(http: Arc<dyn HttpService>) -> Arc<Engine> {
|
||||
Arc::new(picloud_shared::NoopUsersService),
|
||||
Arc::new(picloud_shared::NoopQueueService),
|
||||
Arc::new(picloud_shared::NoopInvokeService),
|
||||
Arc::new(picloud_shared::NoopVarsService),
|
||||
);
|
||||
Arc::new(Engine::new(Limits::default(), services))
|
||||
}
|
||||
|
||||
@@ -90,6 +90,7 @@ fn build_engine(svc: Arc<FakeInvokeService>) -> Arc<Engine> {
|
||||
Arc::new(NoopUsersService),
|
||||
Arc::new(NoopQueueService),
|
||||
svc,
|
||||
Arc::new(picloud_shared::NoopVarsService),
|
||||
);
|
||||
let engine = Arc::new(Engine::new(Limits::default(), services));
|
||||
engine.set_self_weak(Arc::downgrade(&engine));
|
||||
|
||||
@@ -114,6 +114,7 @@ fn make_engine() -> Arc<Engine> {
|
||||
Arc::new(picloud_shared::NoopUsersService),
|
||||
Arc::new(picloud_shared::NoopQueueService),
|
||||
Arc::new(picloud_shared::NoopInvokeService),
|
||||
Arc::new(picloud_shared::NoopVarsService),
|
||||
);
|
||||
Arc::new(Engine::new(Limits::default(), services))
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ fn make_engine(svc: Arc<RecordingPubsub>) -> Arc<Engine> {
|
||||
Arc::new(picloud_shared::NoopUsersService),
|
||||
Arc::new(picloud_shared::NoopQueueService),
|
||||
Arc::new(picloud_shared::NoopInvokeService),
|
||||
Arc::new(picloud_shared::NoopVarsService),
|
||||
);
|
||||
Arc::new(Engine::new(Limits::default(), services))
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@ fn make_engine(svc: Arc<RecordingQueue>) -> Arc<Engine> {
|
||||
Arc::new(picloud_shared::NoopUsersService),
|
||||
svc,
|
||||
Arc::new(picloud_shared::NoopInvokeService),
|
||||
Arc::new(picloud_shared::NoopVarsService),
|
||||
);
|
||||
Arc::new(Engine::new(Limits::default(), services))
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ fn build_engine() -> Arc<Engine> {
|
||||
Arc::new(NoopUsersService),
|
||||
Arc::new(NoopQueueService),
|
||||
Arc::new(NoopInvokeService),
|
||||
Arc::new(picloud_shared::NoopVarsService),
|
||||
);
|
||||
Arc::new(Engine::new(Limits::default(), services))
|
||||
}
|
||||
|
||||
@@ -105,6 +105,7 @@ fn make_engine() -> Arc<Engine> {
|
||||
Arc::new(picloud_shared::NoopUsersService),
|
||||
Arc::new(picloud_shared::NoopQueueService),
|
||||
Arc::new(picloud_shared::NoopInvokeService),
|
||||
Arc::new(picloud_shared::NoopVarsService),
|
||||
);
|
||||
Arc::new(Engine::new(Limits::default(), services))
|
||||
}
|
||||
|
||||
@@ -99,6 +99,7 @@ fn make_engine() -> Arc<Engine> {
|
||||
Arc::new(picloud_shared::NoopUsersService),
|
||||
Arc::new(picloud_shared::NoopQueueService),
|
||||
Arc::new(picloud_shared::NoopInvokeService),
|
||||
Arc::new(picloud_shared::NoopVarsService),
|
||||
);
|
||||
Arc::new(Engine::new(Limits::default(), services))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user