Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 14 additions & 2 deletions crates/codegen/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,19 +93,31 @@ pub(super) fn is_reducer_invokable(reducer: &ReducerDef) -> bool {

/// Iterate over all the [`ReducerDef`]s defined by the module, in alphabetical order by name.
///
/// The init reducer is skipped because it should never be visible to the clients.
/// Skipping the `init` reducer and internal [`FunctionVisibiity::Internal`] reducers because
/// they should not be directly invokable.
/// Sorting is not necessary for reducers because they are already stored in an IndexMap.
pub(super) fn iter_reducers(module: &ModuleDef) -> impl Iterator<Item = &ReducerDef> {
module
.reducers()
// `RawModuleDefV10` already marks all lifecycle reducers as private, but we keep
// this filter for backward compatibility with older versions where `init`
// reducers were not private.
.filter(|reducer| reducer.lifecycle != Some(Lifecycle::Init))
// Prior to `RawModuleDefV10`, all reducers were public by default. Filtering out
// internal reducers here does not break SDKs built against older versions.
.filter(|reducer| !reducer.visibility.is_private())
}

/// Iterate over all the [`ProcedureDef`]s defined by the module, in alphabetical order by name.
///
/// Skipping internal [`FunctionVisibiity::Internal`] procedures because they should not be
/// directly invokable.
/// Sorting is necessary to have deterministic reproducible codegen.
pub(super) fn iter_procedures(module: &ModuleDef) -> impl Iterator<Item = &ProcedureDef> {
module.procedures().sorted_by_key(|procedure| &procedure.name)
module
.procedures()
.sorted_by_key(|procedure| &procedure.name)
.filter(|reducer| !reducer.visibility.is_private())
}

/// Iterate over all the [`TableDef`]s defined by the module, in alphabetical order by name.
Expand Down
15 changes: 15 additions & 0 deletions crates/core/src/host/module_host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1520,6 +1520,11 @@ impl ModuleHost {
if let Some(lifecycle) = reducer_def.lifecycle {
return Err(ReducerCallError::LifecycleReducer(lifecycle));
}

if reducer_def.visibility.is_private() && !self.is_database_owner(caller_identity) {
return Err(ReducerCallError::NoSuchReducer);
}

self.call_reducer_inner(
caller_identity,
caller_connection_id,
Expand Down Expand Up @@ -1696,6 +1701,11 @@ impl ModuleHost {
.module_def
.procedure_full(procedure_name)
.ok_or(ProcedureCallError::NoSuchProcedure)?;

if procedure_def.visibility.is_private() && !self.is_database_owner(caller_identity) {
return Err(ProcedureCallError::NoSuchProcedure);
}

self.call_procedure_inner(
caller_identity,
caller_connection_id,
Expand Down Expand Up @@ -1755,6 +1765,11 @@ impl ModuleHost {
Ok(self.call_procedure_with_params(&procedure_def.name, params).await?)
}

//TODO(shub) #4195: Also allow for collaborators along with owner
fn is_database_owner(&self, caller_identity: Identity) -> bool {
self.info.owner_identity == caller_identity
}

pub async fn call_procedure_with_params(
&self,
name: &str,
Expand Down
16 changes: 10 additions & 6 deletions crates/lib/src/db/raw_def/v10.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,13 @@ pub struct RawReducerDefV10 {
#[sats(crate = crate)]
#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
pub enum FunctionVisibility {
/// Internal-only, not callable from clients.
/// Typically used for lifecycle reducers and scheduled functions.
Internal,
/// Not callable by arbitrary clients.
///
/// Still callable by the module owner, collaborators,
/// and internal module code.
///
/// Enabled for lifecycle reducers and scheduled functions by default.
Private,

/// Callable from client code.
ClientCallable,
Expand Down Expand Up @@ -872,7 +876,7 @@ impl RawModuleDefV10Builder {
self.reducers_mut().push(RawReducerDefV10 {
source_name: function_name,
params,
visibility: FunctionVisibility::Internal,
visibility: FunctionVisibility::Private,
ok_return_type: reducer_default_ok_return_type(),
err_return_type: reducer_default_err_return_type(),
});
Expand Down Expand Up @@ -936,15 +940,15 @@ impl RawModuleDefV10Builder {
.iter_mut()
.find(|r| r.source_name == internal_function)
{
r.visibility = FunctionVisibility::Internal;
r.visibility = FunctionVisibility::Private;
}

if let Some(p) = self
.procedures_mut()
.iter_mut()
.find(|p| p.source_name == internal_function)
{
p.visibility = FunctionVisibility::Internal;
p.visibility = FunctionVisibility::Private;
}
}
self.module
Expand Down
16 changes: 12 additions & 4 deletions crates/schema/src/def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1298,19 +1298,27 @@ impl From<ViewDef> for RawMiscModuleExportV9 {
/// The visibility of a function (reducer or procedure).
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum FunctionVisibility {
/// Internal-only, not callable from clients.
/// Typically used for lifecycle reducers and scheduled functions.
Internal,
/// Not callable by arbitrary clients.
///
/// Still callable by the module owner, collaborators,
/// and internal module code.
Private,

/// Callable from client code.
ClientCallable,
}

impl FunctionVisibility {
pub fn is_private(&self) -> bool {
matches!(self, FunctionVisibility::Private)
}
}

use spacetimedb_lib::db::raw_def::v10::FunctionVisibility as RawFunctionVisibility;
impl From<RawFunctionVisibility> for FunctionVisibility {
fn from(val: RawFunctionVisibility) -> Self {
match val {
RawFunctionVisibility::Internal => FunctionVisibility::Internal,
RawFunctionVisibility::Private => FunctionVisibility::Private,
RawFunctionVisibility::ClientCallable => FunctionVisibility::ClientCallable,
}
}
Expand Down
4 changes: 2 additions & 2 deletions crates/schema/src/def/validate/v10.rs
Original file line number Diff line number Diff line change
Expand Up @@ -946,9 +946,9 @@ mod tests {

assert_eq!(
def.reducers[&check_deliveries_name].visibility,
FunctionVisibility::Internal,
FunctionVisibility::Private,
);
assert_eq!(def.reducers[&init_name].visibility, FunctionVisibility::Internal);
assert_eq!(def.reducers[&init_name].visibility, FunctionVisibility::Private);
assert_eq!(
def.reducers[&extra_reducer_name].visibility,
FunctionVisibility::ClientCallable
Expand Down
Loading