diff --git a/crates/manager-core/src/api.rs b/crates/manager-core/src/api.rs index fd38f23..275e63a 100644 --- a/crates/manager-core/src/api.rs +++ b/crates/manager-core/src/api.rs @@ -260,7 +260,7 @@ async fn create_script( /// real KV bridge — defense against author confusion, not a security /// boundary (stdlib namespaces and module imports already live in /// disjoint Rhai scopes). -const RESERVED_MODULE_NAMES: &[&str] = &[ +pub(crate) const RESERVED_MODULE_NAMES: &[&str] = &[ "log", "regex", "random", diff --git a/crates/manager-core/src/apply_service.rs b/crates/manager-core/src/apply_service.rs index dc8bdae..38adcf0 100644 --- a/crates/manager-core/src/apply_service.rs +++ b/crates/manager-core/src/apply_service.rs @@ -886,6 +886,15 @@ impl ApplyService { ))); } let res = if s.kind == ScriptKind::Module { + // Parity with the interactive create path (`api.rs`): a module + // may not shadow a built-in SDK namespace, or `import "kv"` + // could resolve to a user module instead of the real bridge. + if crate::api::RESERVED_MODULE_NAMES.contains(&s.name.as_str()) { + return Err(ApplyError::Invalid(format!( + "script `{}`: reserved module name (shadows a built-in SDK namespace)", + s.name + ))); + } self.validator.validate_module(&s.source) } else { self.validator.validate(&s.source)