Skip to content

Commit

Permalink
Merge pull request #4231 from systeminit/brit/bug-462-auth-funcs-cant…
Browse files Browse the repository at this point in the history
…-be-detached

fix(dal, sdf): auth funcs can be detached
  • Loading branch information
stack72 authored Jul 25, 2024
2 parents 6de5cfe + 397fc39 commit e511d36
Show file tree
Hide file tree
Showing 4 changed files with 205 additions and 4 deletions.
7 changes: 6 additions & 1 deletion lib/dal/src/func/binding/authentication.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ impl AuthBinding {
#[instrument(
level = "info",
skip(ctx),
name = "func.binding.authentication.create_auth_binding"
name = "func.binding.authentication.delete_auth_binding"
)]
/// Deletes an Auth Binding for a Schema Variant
pub async fn delete_auth_binding(
Expand All @@ -63,6 +63,11 @@ impl AuthBinding {
Ok(EventualParent::SchemaVariant(schema_variant_id))
}

#[instrument(
level = "info",
skip(ctx),
name = "func.binding.authentication.port_binding_to_new_func"
)]
pub(crate) async fn port_binding_to_new_func(
&self,
ctx: &DalContext,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,154 @@ async fn attach_multiple_auth_funcs_with_creation(ctx: &mut DalContext) {
funcs.len() // actual
);
}

#[test]
async fn detach_auth_func(ctx: &mut DalContext) {
let schema = Schema::find_by_name(ctx, "dummy-secret")
.await
.expect("unable to find by name")
.expect("no schema found");
let schema_variant_id = SchemaVariant::get_default_id_for_schema(ctx, schema.id())
.await
.expect("unable to get default schema variant");

// Cache the total number of funcs before continuing.
let funcs = FuncSummary::list_for_schema_variant_id(ctx, schema_variant_id)
.await
.expect("unable to get the funcs for a schema variant");
let total_funcs = funcs.len();

// Get the Auth Func
let fn_name = "test:setDummySecretString";
let func_id = Func::find_id_by_name(ctx, fn_name)
.await
.expect("found auth func")
.expect("has a func");

// Try to detach and see it fails
let delete_result = AuthBinding::delete_auth_binding(ctx, func_id, schema_variant_id).await;
assert!(delete_result.is_err());

// now create unlocked copy
let unlocked_schema_variant =
VariantAuthoringClient::create_unlocked_variant_copy(ctx, schema_variant_id)
.await
.expect("could create unlocked copy")
.id();

// detach auth func for unlocked copy
AuthBinding::delete_auth_binding(ctx, func_id, unlocked_schema_variant)
.await
.expect("could not delete auth binding");

// check that there's one less func
let funcs = FuncSummary::list_for_schema_variant_id(ctx, unlocked_schema_variant)
.await
.expect("unable to get the funcs for a schema variant");
assert_eq!(funcs.len(), total_funcs - 1);
}

#[test]
async fn edit_auth_func(ctx: &mut DalContext) {
ChangeSetTestHelpers::fork_from_head_change_set(ctx)
.await
.expect("could not fork head");
// find the variant we know is default and attached to this func already
let schema = Schema::find_by_name(ctx, "dummy-secret")
.await
.expect("unable to find by name")
.expect("no schema found");

let schema_variant_id = SchemaVariant::get_default_id_for_schema(ctx, schema.id())
.await
.expect("unable to get default schema variant");
// Cache the total number of funcs before continuing.
let funcs = FuncSummary::list_for_schema_variant_id(ctx, schema_variant_id)
.await
.expect("unable to get the funcs for a schema variant");

// Get the Auth Func
let fn_name = "test:setDummySecretString";
let func_id = Func::find_id_by_name(ctx, fn_name)
.await
.expect("found auth func")
.expect("has a func");

// ensure the func is attached
assert!(funcs.into_iter().any(|func| func.id == func_id));

// create unlocked copy of it
let unlocked_func_id = FuncAuthoringClient::create_unlocked_func_copy(ctx, func_id, None)
.await
.expect("could not create unlocked copy");

// find unlocked copy of the variant
let unlocked_schema_variant = SchemaVariant::get_unlocked_for_schema(ctx, schema.id())
.await
.expect("unable to get default schema variant")
.expect("has unlocked variant");

ChangeSetTestHelpers::commit_and_update_snapshot_to_visibility(ctx)
.await
.expect("unable to commit");

assert!(!unlocked_schema_variant.is_locked());

// ensure the unlocked variant has the new func attached and not the old one
let funcs = FuncSummary::list_for_schema_variant_id(ctx, unlocked_schema_variant.id)
.await
.expect("could not get func summaries");

assert!(funcs
.clone()
.into_iter()
.any(|func| func.id == unlocked_func_id.id));
assert!(funcs.into_iter().any(|func| func.id != func_id));

// edit the func
let new_auth_func_code = "async function auth(secret: Input): Promise<Output> { requestStorage.setItem('dummySecretString', secret.value); requestStorage.setItem('workspaceToken', secret.WorkspaceToken); console.log('success');}";

FuncAuthoringClient::save_code(ctx, unlocked_func_id.id, new_auth_func_code.to_string())
.await
.expect("could not save code");

let unlocked_func = Func::get_by_id_or_error(ctx, unlocked_func_id.id)
.await
.expect("could not get func");
// ensure it saved
let maybe_new_code = unlocked_func
.code_plaintext()
.expect("got code")
.expect("has code");

assert_eq!(new_auth_func_code.to_string(), maybe_new_code);

// commit and apply
ChangeSetTestHelpers::apply_change_set_to_base(ctx)
.await
.expect("could not apply to base");

// ensure new func is locked
let new_locked_func = Func::get_by_id_or_error(ctx, unlocked_func.id)
.await
.expect("could not get func");

assert!(new_locked_func.is_locked);
assert_eq!(
new_locked_func
.code_plaintext()
.expect("got code")
.expect("has code"),
new_auth_func_code.to_string()
);

//ensure new schema variant is locked and default
let maybe_locked_schema_variant_id = SchemaVariant::get_default_id_for_schema(ctx, schema.id())
.await
.expect("unable to get default schema variant");
let maybe_locked_schema_variant =
SchemaVariant::get_by_id_or_error(ctx, maybe_locked_schema_variant_id)
.await
.expect("could not get schema variant");
assert!(maybe_locked_schema_variant.is_locked());
}
2 changes: 2 additions & 0 deletions lib/sdf-server/src/server/service/v2/func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ pub mod update_func;
#[remain::sorted]
#[derive(Debug, Error)]
pub enum FuncAPIError {
#[error("cannot delete binding for func kind")]
CannotDeleteBindingForFunc,
#[error("cannot delete locked func: {0}")]
CannotDeleteLockedFunc(FuncId),
#[error("change set error: {0}")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ use axum::{
Json,
};
use dal::{
func::binding::{action::ActionBinding, leaf::LeafBinding, EventualParent},
func::binding::{
action::ActionBinding, authentication::AuthBinding, leaf::LeafBinding, EventualParent,
},
ChangeSet, ChangeSetId, Func, FuncId, SchemaVariant, WorkspacePk, WsEvent,
};
use si_frontend_types as frontend_types;
Expand Down Expand Up @@ -135,9 +137,50 @@ pub async fn delete_binding(
}
}
}
_ => {
return Err(FuncAPIError::WrongFunctionKindForBinding);
dal::func::FuncKind::Authentication => {
for binding in request.bindings {
if let frontend_types::FuncBinding::Authentication {
schema_variant_id,
func_id,
} = binding
{
match func_id {
Some(func_id) => {
let eventual_parent = AuthBinding::delete_auth_binding(
&ctx,
func_id.into(),
schema_variant_id.into(),
)
.await?;
if let EventualParent::SchemaVariant(schema_variant_id) =
eventual_parent
{
let schema = SchemaVariant::schema_id_for_schema_variant_id(
&ctx,
schema_variant_id,
)
.await?;
let schema_variant =
SchemaVariant::get_by_id_or_error(&ctx, schema_variant_id)
.await?;

WsEvent::schema_variant_updated(&ctx, schema, schema_variant)
.await?
.publish_on_commit(&ctx)
.await?;
}
}
None => return Err(FuncAPIError::MissingFuncId),
}
} else {
return Err(FuncAPIError::WrongFunctionKindForBinding);
}
}
}
dal::func::FuncKind::Attribute
| dal::func::FuncKind::Intrinsic
| dal::func::FuncKind::SchemaVariantDefinition
| dal::func::FuncKind::Unknown => return Err(FuncAPIError::CannotDeleteBindingForFunc),
};

track(
Expand Down

0 comments on commit e511d36

Please sign in to comment.