Skip to main content
Glama
secret.rs35.8 kB
use dal::{ Component, DalContext, EncryptedSecret, Prop, Secret, SecretAlgorithm, SecretVersion, diagram::view::View, prop::PropPath, property_editor::values::PropertyEditorValues, qualification::QualificationSubCheckStatus, secret::DecryptedSecret, }; use dal_test::{ Result, WorkspaceSignup, expected::{ self, ExpectComponent, }, helpers::{ ChangeSetTestHelpers, attribute::value, change_set, component, create_component_for_default_schema_name_in_default_view, encrypt_message, generate_fake_name, }, test, }; use pretty_assertions_sorted::assert_eq; use serde_json::Value; mod with_actions; mod with_schema_variant_authoring; #[test] async fn new(ctx: &DalContext, nw: &WorkspaceSignup) { let name = generate_fake_name().expect("could not generate fake name"); // Ensure that secret creation works. let secret = Secret::new( ctx, &name, "Mock".to_owned(), Some("Description".to_owned()), "im-crypted-bytes-maybe".as_bytes(), nw.key_pair.pk(), SecretVersion::V1, SecretAlgorithm::Sealedbox, ) .await .expect("failed to create secret"); assert_eq!(name, secret.name()); assert_eq!("Mock", secret.definition()); assert_eq!(Some("Description"), secret.description().as_deref()); // Ensure that the underlying encrypted secret was created and that we can fetch its key pair. let encrypted_secret = EncryptedSecret::get_by_key(ctx, secret.encrypted_secret_key()) .await .expect("failed to perform get by key for encrypted secret") .expect("no encrypted secret found"); let key_pair = encrypted_secret .key_pair(ctx) .await .expect("failed to fetch key pair"); assert_eq!(nw.key_pair.pk(), key_pair.pk()); // Fetch the secret by id too. let found_secret = Secret::get_by_id(ctx, secret.id()) .await .expect("could not perform get by id or secret not found"); assert_eq!(secret, found_secret); } #[test] async fn encrypt_decrypt_round_trip(ctx: &DalContext, nw: &WorkspaceSignup) { let pkey = nw.key_pair.public_key(); let name = generate_fake_name().expect("could not generate fake name"); // Create an encrypted message. let message = serde_json::json!({"song": "Bar Round Here"}); let crypted = sodiumoxide::crypto::sealedbox::seal( &serde_json::to_vec(&message).expect("failed to serialize message"), pkey, ); // Create a secret with the encrypted message. let secret = Secret::new( ctx, &name, "imasecret".to_owned(), None, &crypted, nw.key_pair.pk(), Default::default(), Default::default(), ) .await .expect("failed to create encrypted secret"); // Ensure that the fetched secret looks as we expected. let found_secret = Secret::get_by_id(ctx, secret.id()) .await .expect("could not perform get by id or secret not found"); assert_eq!(secret.name(), found_secret.name()); assert_eq!(secret.description(), found_secret.description()); assert_eq!(secret.definition(), found_secret.definition()); assert_eq!( secret.encrypted_secret_key(), found_secret.encrypted_secret_key() ); // Ensure that the decrypted contents match our message. let decrypted = EncryptedSecret::get_by_key(ctx, found_secret.encrypted_secret_key()) .await .expect("failed to perform get by key for encrypted secret") .expect("no encrypted secret found") .decrypt(ctx) .await .expect("failed to decrypt encrypted secret"); let actual_message = prepare_decrypted_secret_for_assertions(&decrypted); assert_eq!(message, actual_message); } #[test] async fn update_metadata_and_encrypted_contents(ctx: &DalContext, nw: &WorkspaceSignup) { let pkey = nw.key_pair.public_key(); let key_pair_pk = nw.key_pair.pk(); let version = SecretVersion::default(); let algorithm = SecretAlgorithm::default(); let name = generate_fake_name().expect("could not generate fake name"); // Create a message to encrypt and use for the secret. let message = serde_json::json!({"song": "Smile", "artist": "midwxst"}); let crypted = sodiumoxide::crypto::sealedbox::seal( &serde_json::to_vec(&message).expect("failed to serialize message"), pkey, ); // Create the secret. let secret = Secret::new( ctx, &name, "my flight might be delayed, but I'm writing this test, so it's all good", None, &crypted, key_pair_pk, version, algorithm, ) .await .expect("failed to create encrypted secret"); // Ensure that the fetched secret looks as we expect. let found_secret = Secret::get_by_id(ctx, secret.id()) .await .expect("could not perform get by id or secret not found"); assert_eq!(secret.name(), found_secret.name()); assert_eq!(secret.description(), found_secret.description()); assert_eq!(secret.definition(), found_secret.definition()); assert_eq!( secret.encrypted_secret_key(), found_secret.encrypted_secret_key() ); // Ensure that the decrypted message matches the original message. let decrypted = EncryptedSecret::get_by_key(ctx, found_secret.encrypted_secret_key()) .await .expect("failed to perform get by key for encrypted secret") .expect("no encrypted secret found") .decrypt(ctx) .await .expect("failed to decrypt encrypted secret"); let actual_message = prepare_decrypted_secret_for_assertions(&decrypted); assert_eq!(message, actual_message); // Update the encrypted contents and the secret. let updated_message = serde_json::json!({"song": "Smile", "artist": "midwxst", "featuredArtists": ["glaive"]}); let updated_crypted = sodiumoxide::crypto::sealedbox::seal( &serde_json::to_vec(&updated_message).expect("failed to serialize message"), pkey, ); let original_key = secret.encrypted_secret_key(); let updated_secret = secret .update_encrypted_contents( ctx, updated_crypted.as_slice(), key_pair_pk, version, algorithm, ) .await .expect("could not update encrypted contents"); let found_updated_secret = Secret::get_by_id(ctx, updated_secret.id()) .await .expect("could not perform get by id or secret not found"); // Check that the key has changed. assert_ne!(original_key, updated_secret.encrypted_secret_key()); assert_eq!( found_updated_secret.encrypted_secret_key(), updated_secret.encrypted_secret_key() ); // Check that the decrypted contents match. let updated_decrypted = EncryptedSecret::get_by_key(ctx, found_updated_secret.encrypted_secret_key()) .await .expect("failed to perform get by key for encrypted secret") .expect("no encrypted secret found") .decrypt(ctx) .await .expect("failed to decrypt encrypted secret"); let actual_updated_message = prepare_decrypted_secret_for_assertions(&updated_decrypted); assert_eq!(updated_message, actual_updated_message); // Ensure the metadata has not changed assert_eq!(found_secret.name(), updated_secret.name()); assert_eq!(found_secret.definition(), updated_secret.definition()); assert_eq!(found_updated_secret.name(), updated_secret.name()); assert_eq!( found_updated_secret.definition(), updated_secret.definition() ); // Now, update the metadata. let double_updated_secret = updated_secret.update_metadata(ctx, name, Some("alright, so now we are in the air and I am writing this test offline, which is awesome!".to_string())).await.expect("could not update metadata"); let found_double_updated_secret = Secret::get_by_id(ctx, double_updated_secret.id()) .await .expect("could not perform get by id or secret not found"); // Ensure the description has changed. assert_eq!( double_updated_secret.description(), found_double_updated_secret.description() ); assert_ne!( double_updated_secret.description(), found_updated_secret.description() ); // Ensure the key has not changed. assert_eq!( double_updated_secret.encrypted_secret_key(), found_double_updated_secret.encrypted_secret_key() ); assert_eq!( double_updated_secret.encrypted_secret_key(), found_updated_secret.encrypted_secret_key() ); // Ensure the definition has not changed. assert_eq!( double_updated_secret.definition(), found_double_updated_secret.definition() ); assert_eq!( double_updated_secret.definition(), found_updated_secret.definition() ); // Check that the decrypted contents have not changed. let updated_decrypted_should_not_have_changed = EncryptedSecret::get_by_key(ctx, found_double_updated_secret.encrypted_secret_key()) .await .expect("failed to perform get by key for encrypted secret") .expect("no encrypted secret found") .decrypt(ctx) .await .expect("failed to decrypt encrypted secret"); let actual_updated_message_should_not_have_changed = prepare_decrypted_secret_for_assertions(&updated_decrypted_should_not_have_changed); assert_eq!( updated_message, actual_updated_message_should_not_have_changed ); } #[test] async fn copy_paste_component_with_secrets_being_used( ctx: &mut DalContext, nw: &WorkspaceSignup, ) -> Result<()> { // Create a component and commit. component::create(ctx, "dummy-secret", "secret").await?; component::create(ctx, "fallout", "user").await?; value::subscribe( ctx, ("user", "/secrets/dummy"), ("secret", "/secrets/dummy"), ) .await?; change_set::commit(ctx).await?; // Create a secret with a value that will pass the qualification and commit. let secret_message = encrypt_message(ctx, nw.key_pair.pk(), &serde_json::json![{"value": "todd"}]).await?; let secret = Secret::new( ctx, "secret that will pass the qualification", "dummy", None, &secret_message, nw.key_pair.pk(), Default::default(), Default::default(), ) .await?; change_set::commit(ctx).await?; // Set the secret on the component and commit let secret_av_id = value::id(ctx, ("secret", "/secrets/dummy")).await?; Secret::attach_for_attribute_value(ctx, secret_av_id, Some(secret.id())).await?; change_set::commit(ctx).await?; // Copy and paste the secret component Component::duplicate( ctx, View::get_id_for_default(ctx).await?, vec![component::id(ctx, "secret").await?], "dup-", ) .await?; change_set::commit(ctx).await?; // Copy and paste the user component Component::duplicate( ctx, View::get_id_for_default(ctx).await?, vec![component::id(ctx, "user").await?], "dup-", ) .await?; change_set::commit(ctx).await?; Ok(()) } // TODO it's unclear how / whether this should work this way with subscriptions #[ignore] #[test] async fn consumed_secrets_work_when_dvu_not_up_to_date( ctx: &mut DalContext, nw: &WorkspaceSignup, ) -> Result<()> { // Create a secret and consumer component. component::create(ctx, "dummy-secret", "secret").await?; component::create(ctx, "fallout", "user").await?; value::subscribe( ctx, ("user", "/secrets/dummy"), ("secret", "/secrets/dummy"), ) .await?; change_set::commit(ctx).await?; // Create a secret with a value and commit. let secret_message = encrypt_message(ctx, nw.key_pair.pk(), &serde_json::json![{"value": "todd"}]).await?; let secret = Secret::new( ctx, "secret", "dummy", None, &secret_message, nw.key_pair.pk(), Default::default(), Default::default(), ) .await?; let secret_message = secret.encrypted_secret_key(); change_set::commit(ctx).await?; // Set the secret on the component and commit let dummy_secret_attribute_value_id = value::id(ctx, ("secret", "/secrets/dummy")).await?; Secret::attach_for_attribute_value(ctx, dummy_secret_attribute_value_id, Some(secret.id())) .await?; change_set::commit(ctx).await?; let found_secret = Secret::get_by_id(ctx, secret.id()).await?; assert_eq!(secret_message, found_secret.encrypted_secret_key()); // Check the secret values. assert_eq!( found_secret.encrypted_secret_key().to_string(), value::get(ctx, ("secret", "/secrets/dummy")).await? ); assert_eq!( found_secret.encrypted_secret_key().to_string(), value::get(ctx, ("user", "/secrets/dummy")).await? ); // Update the secret. let updated_secret_message = encrypt_message( ctx, nw.key_pair.pk(), &serde_json::json![{"value": "sweeney"}], ) .await?; let updated_secret = Secret::get_by_id(ctx, secret.id()) .await? .update_encrypted_contents( ctx, updated_secret_message.as_slice(), nw.key_pair.pk(), Default::default(), Default::default(), ) .await?; let updated_secret_message = updated_secret.encrypted_secret_key(); // Validate that the secret has the new value. let found_secret = Secret::get_by_id(ctx, secret.id()).await?; assert_eq!(updated_secret_message, found_secret.encrypted_secret_key()); // Check the secret values again *before* running DVU. assert_eq!( Value::Null, value::get(ctx, ("secret", "/secrets/dummy")).await? ); assert_eq!( Value::Null, value::get(ctx, ("user", "/secrets/dummy")).await? ); change_set::commit(ctx).await?; // Check the secret values *after* running DVU. assert_eq!( found_secret.encrypted_secret_key().to_string(), value::get(ctx, ("secret", "/secrets/dummy")).await? ); assert_eq!( found_secret.encrypted_secret_key().to_string(), value::get(ctx, ("user", "/secrets/dummy")).await? ); Ok(()) } #[test] async fn update_encrypted_contents_with_dependent_values( ctx: &mut DalContext, nw: &WorkspaceSignup, ) { // Create a component and commit. let component = create_component_for_default_schema_name_in_default_view( ctx, "dummy-secret", "secret-definition", ) .await .expect("could not create component"); let schema_variant_id = Component::schema_variant_id(ctx, component.id()) .await .expect("could not get schema variant id for component"); let component_id = component.id(); ChangeSetTestHelpers::commit_and_update_snapshot_to_visibility(ctx) .await .expect("could not commit and update snapshot to visibility"); // Cache the name of the secret definition from the test exclusive schema and cache the prop we // need for attribute value update. let secret_definition_name = "dummy"; let dummy_secret_prop = Prop::find_prop_by_path( ctx, schema_variant_id, &PropPath::new(["root", "secrets", secret_definition_name]), ) .await .expect("could not find prop by path"); // Create a secret with a value that will fail the qualification and commit. let encrypted_message_that_will_fail_the_qualification = encrypt_message( ctx, nw.key_pair.pk(), &serde_json::json![{"value": "howard"}], ) .await .expect("could not encrypt message"); let secret = Secret::new( ctx, generate_fake_name().expect("could not generate fake name"), secret_definition_name, None, &encrypted_message_that_will_fail_the_qualification, nw.key_pair.pk(), Default::default(), Default::default(), ) .await .expect("cannot create secret"); ChangeSetTestHelpers::commit_and_update_snapshot_to_visibility(ctx) .await .expect("could not commit and update snapshot to visibility"); // Use the secret in the component and commit. let property_values = PropertyEditorValues::assemble(ctx, component_id) .await .expect("unable to list prop values"); let dummy_secret_attribute_value_id = property_values .find_by_prop_id(dummy_secret_prop.id) .expect("unable to find attribute value"); Secret::attach_for_attribute_value(ctx, dummy_secret_attribute_value_id, Some(secret.id())) .await .expect("could not attach secret"); ChangeSetTestHelpers::commit_and_update_snapshot_to_visibility(ctx) .await .expect("could not commit and update snapshot to visibility"); // Check that the qualification fails. let qualifications = Component::list_qualifications(ctx, component_id) .await .expect("could not list qualifications"); let qualification = qualifications .iter() .find(|q| q.qualification_name == "test:qualificationDummySecretStringIsTodd") .expect("qualification not found") .to_owned(); assert_eq!( QualificationSubCheckStatus::Failure, // expected qualification.result.expect("no result found").status // actual ); // Update the encrypted contents. let encrypted_message_that_will_pass_the_qualification = encrypt_message(ctx, nw.key_pair.pk(), &serde_json::json![{"value": "todd"}]) .await .expect("could not encrypt message"); let updated_secret = secret .update_encrypted_contents( ctx, encrypted_message_that_will_pass_the_qualification.as_slice(), nw.key_pair.pk(), Default::default(), Default::default(), ) .await .expect("could not update encrypted contents"); ChangeSetTestHelpers::commit_and_update_snapshot_to_visibility(ctx) .await .expect("could not commit and update snapshot to visibility"); // Check that the qualification succeeds. let qualifications = Component::list_qualifications(ctx, component_id) .await .expect("could not list qualifications"); let qualification = qualifications .iter() .find(|q| q.qualification_name == "test:qualificationDummySecretStringIsTodd") .expect("qualification not found") .to_owned(); assert_eq!( QualificationSubCheckStatus::Success, // expected qualification.result.expect("no result found").status // actual ); // Unset the secret and commit. let property_values = PropertyEditorValues::assemble(ctx, component_id) .await .expect("unable to list prop values"); let dummy_secret_attribute_value_id = property_values .find_by_prop_id(dummy_secret_prop.id) .expect("unable to find attribute value"); Secret::attach_for_attribute_value(ctx, dummy_secret_attribute_value_id, None) .await .expect("could not attach for attribute value"); ChangeSetTestHelpers::commit_and_update_snapshot_to_visibility(ctx) .await .expect("could not commit and update snapshot to visibility"); // Ensure that the qualification fails. let qualifications = Component::list_qualifications(ctx, component_id) .await .expect("could not list qualifications"); let qualification = qualifications .iter() .find(|q| q.qualification_name == "test:qualificationDummySecretStringIsTodd") .expect("qualification not found") .to_owned(); assert_eq!( QualificationSubCheckStatus::Failure, // expected qualification.result.expect("no result found").status // actual ); // Use the secret again. let property_values = PropertyEditorValues::assemble(ctx, component_id) .await .expect("unable to list prop values"); let dummy_secret_attribute_value_id = property_values .find_by_prop_id(dummy_secret_prop.id) .expect("unable to find attribute value"); Secret::attach_for_attribute_value( ctx, dummy_secret_attribute_value_id, Some(updated_secret.id()), ) .await .expect("could not attach secret"); ChangeSetTestHelpers::commit_and_update_snapshot_to_visibility(ctx) .await .expect("could not commit and update snapshot to visibility"); // Ensure that the qualification succeeds. let qualifications = Component::list_qualifications(ctx, component_id) .await .expect("could not list qualifications"); let qualification = qualifications .iter() .find(|q| q.qualification_name == "test:qualificationDummySecretStringIsTodd") .expect("qualification not found") .to_owned(); assert_eq!( QualificationSubCheckStatus::Success, // expected qualification.result.expect("no result found").status // actual ); } #[test] async fn secret_definition_works_with_dummy_qualification( ctx: &mut DalContext, nw: &WorkspaceSignup, ) { // Create a component and commit. let component = ExpectComponent::create(ctx, "dummy-secret").await; let secret_name = "dummy"; let output_socket = component.output_socket(ctx, secret_name).await; let secret_prop = component.prop(ctx, ["root", "secrets", secret_name]).await; expected::commit_and_update_snapshot_to_visibility(ctx).await; // First scenario: create and use a secret that will fail the qualification. { // Create a secret with a value that will fail the qualification and commit. let encrypted_message_that_will_fail_the_qualification = encrypt_message( ctx, nw.key_pair.pk(), &serde_json::json![{"value": "howard"}], ) .await .expect("could not encrypt message"); let secret_that_will_fail_the_qualification = Secret::new( ctx, "secret that will fail the qualification", secret_name.to_string(), None, &encrypted_message_that_will_fail_the_qualification, nw.key_pair.pk(), Default::default(), Default::default(), ) .await .expect("cannot create secret"); expected::commit_and_update_snapshot_to_visibility(ctx).await; // Update the reference to secret prop with the secret it that will fail the qualification // and commit. Secret::attach_for_attribute_value( ctx, secret_prop.attribute_value(ctx).await.id(), Some(secret_that_will_fail_the_qualification.id()), ) .await .expect("could not attach secret"); expected::commit_and_update_snapshot_to_visibility(ctx).await; // Check that the output socket value looks correct. assert_eq!( Secret::payload_for_prototype_execution( ctx, secret_that_will_fail_the_qualification.id() ) .await .expect("could not get payload"), // expected output_socket.get(ctx).await // actual ); // Check that the qualification fails. let qualifications = Component::list_qualifications(ctx, component.id()) .await .expect("could not list qualifications"); let qualification = qualifications .into_iter() .find(|q| q.qualification_name == "test:qualificationDummySecretStringIsTodd") .expect("could not find qualification"); assert_eq!( QualificationSubCheckStatus::Failure, // expected qualification.result.expect("no result found").status // actual ); } // Second scenario: create and use a secret that will pass the qualification. { // Create a secret with a value that will pass the qualification and commit. let encrypted_message_that_will_pass_the_qualification = encrypt_message(ctx, nw.key_pair.pk(), &serde_json::json![{"value": "todd"}]) .await .expect("could not encrypt message"); let secret_that_will_pass_the_qualification = Secret::new( ctx, "secret that will pass the qualification", secret_name.to_string(), None, &encrypted_message_that_will_pass_the_qualification, nw.key_pair.pk(), Default::default(), Default::default(), ) .await .expect("cannot create secret"); expected::commit_and_update_snapshot_to_visibility(ctx).await; // Update the reference to secret prop with the secret it that will pass the qualification // and commit. Secret::attach_for_attribute_value( ctx, secret_prop.attribute_value(ctx).await.id(), Some(secret_that_will_pass_the_qualification.id()), ) .await .expect("could not attach secret"); expected::commit_and_update_snapshot_to_visibility(ctx).await; // Check that the output socket value looks correct. assert_eq!( Secret::payload_for_prototype_execution( ctx, secret_that_will_pass_the_qualification.id() ) .await .expect("could not get payload"), // expected output_socket.get(ctx).await // actual ); // Check that the qualification passes. let qualifications = Component::list_qualifications(ctx, component.id()) .await .expect("could not list qualifications"); let qualification = qualifications .into_iter() .find(|q| q.qualification_name == "test:qualificationDummySecretStringIsTodd") .expect("could not find qualification"); assert_eq!( QualificationSubCheckStatus::Success, // expected qualification.result.expect("no result found").status // actual ); } } fn prepare_decrypted_secret_for_assertions(decrypted_secret: &DecryptedSecret) -> Value { // We don't provide a direct getter for the raw decrypted message (higher effort should mean // less chance of developer error when handling `DecryptedSecret` types), so we'll serialize to // a `Value` to compare messages let decrypted_value = serde_json::to_value(decrypted_secret).expect("failed to serialize decrypted contents"); decrypted_value["message"].to_owned() } #[test] async fn secret_definition_daisy_chain_subscriptions(ctx: &mut DalContext, nw: &WorkspaceSignup) { // Create secret that secret defining component uses and commit. let dummy = ExpectComponent::create(ctx, "dummy-secret").await; let dummy_secret_name = "dummy"; let dummy_output_socket = dummy.output_socket(ctx, dummy_secret_name).await; let dummy_secret_prop = dummy .prop(ctx, ["root", "secrets", dummy_secret_name]) .await; // Create double secret defining component (which uses the daisy chain) let double = ExpectComponent::create(ctx, "dummy-double-secret").await; let double_secret_name = "dummyDouble"; let double_output_socket = double.output_socket(ctx, double_secret_name).await; let double_secret_prop = double .prop(ctx, ["root", "secrets", double_secret_name]) .await; let double_dummy_secret_prop = double .prop(ctx, ["root", "secrets", dummy_secret_name]) .await; expected::commit_and_update_snapshot_to_visibility(ctx).await; // Subscribe to the dummy secret from the double component value::subscribe( ctx, double_dummy_secret_prop.attribute_value(ctx).await.id(), (dummy.id(), "/secrets/dummy"), ) .await .expect("could not subscribe"); expected::commit_and_update_snapshot_to_visibility(ctx).await; // First scenario: create and use secrets that will fail the qualification. { // Create secrets with a value that will fail the qualification and commit. let encrypted_message_that_will_fail_the_qualification_dummy = encrypt_message( ctx, nw.key_pair.pk(), &serde_json::json![{"value": "howard"}], ) .await .expect("could not encrypt message"); let dummy_secret_that_will_fail_the_qualification = Secret::new( ctx, "secret that will fail the qualification", dummy_secret_name.to_string(), None, &encrypted_message_that_will_fail_the_qualification_dummy, nw.key_pair.pk(), Default::default(), Default::default(), ) .await .expect("cannot create secret"); let encrypted_message_that_will_fail_the_qualification_double = encrypt_message( ctx, nw.key_pair.pk(), &serde_json::json![{"value": "howard"}], ) .await .expect("could not encrypt message"); let double_secret_that_will_fail_the_qualification = Secret::new( ctx, "secret that will fail the qualification", double_secret_name.to_string(), None, &encrypted_message_that_will_fail_the_qualification_double, nw.key_pair.pk(), Default::default(), Default::default(), ) .await .expect("cannot create secret"); expected::commit_and_update_snapshot_to_visibility(ctx).await; // Update the reference to secret prop for both components // with the secret it that will fail the qualification Secret::attach_for_attribute_value( ctx, dummy_secret_prop.attribute_value(ctx).await.id(), Some(dummy_secret_that_will_fail_the_qualification.id()), ) .await .expect("could not attach secret"); Secret::attach_for_attribute_value( ctx, double_secret_prop.attribute_value(ctx).await.id(), Some(double_secret_that_will_fail_the_qualification.id()), ) .await .expect("could not attach secret"); expected::commit_and_update_snapshot_to_visibility(ctx).await; // Check that the output socket values looks correct. assert_eq!( Secret::payload_for_prototype_execution( ctx, dummy_secret_that_will_fail_the_qualification.id() ) .await .expect("could not get payload"), // expected dummy_output_socket.get(ctx).await // actual ); assert_eq!( Secret::payload_for_prototype_execution( ctx, double_secret_that_will_fail_the_qualification.id() ) .await .expect("could not get payload"), // expected double_output_socket.get(ctx).await // actual ); // Check that the qualification fails. let qualifications = Component::list_qualifications(ctx, double.id()) .await .expect("could not list qualifications"); let qualification = qualifications .into_iter() .find(|q| q.qualification_name == "test:qualificationDummyDoubleSecretStringIsTodd") .expect("could not find qualification"); assert_eq!( QualificationSubCheckStatus::Failure, // expected qualification.result.expect("no result found").status // actual ); } // Second scenario: create and use secrets that will pass the qualification. { // Create a secret with a value that will pass the qualification and commit. let dummy_encrypted_message_that_will_pass_the_qualification = encrypt_message(ctx, nw.key_pair.pk(), &serde_json::json![{"value": "todd"}]) .await .expect("could not encrypt message"); let dummy_secret_that_will_pass_the_qualification = Secret::new( ctx, "secret that will pass the qualification", dummy_secret_name.to_string(), None, &dummy_encrypted_message_that_will_pass_the_qualification, nw.key_pair.pk(), Default::default(), Default::default(), ) .await .expect("cannot create secret"); let double_encrypted_message_that_will_pass_the_qualification = encrypt_message(ctx, nw.key_pair.pk(), &serde_json::json![{"value": "todd"}]) .await .expect("could not encrypt message"); let double_secret_that_will_pass_the_qualification = Secret::new( ctx, "secret that will pass the qualification", double_secret_name.to_string(), None, &double_encrypted_message_that_will_pass_the_qualification, nw.key_pair.pk(), Default::default(), Default::default(), ) .await .expect("cannot create secret"); expected::commit_and_update_snapshot_to_visibility(ctx).await; // Update the reference to secret props with the secret it that will pass the qualification // and commit. Secret::attach_for_attribute_value( ctx, dummy_secret_prop.attribute_value(ctx).await.id(), Some(dummy_secret_that_will_pass_the_qualification.id()), ) .await .expect("could not attach secret"); Secret::attach_for_attribute_value( ctx, double_secret_prop.attribute_value(ctx).await.id(), Some(double_secret_that_will_pass_the_qualification.id()), ) .await .expect("could not attach secret"); expected::commit_and_update_snapshot_to_visibility(ctx).await; // Check that the output socket value looks correct. assert_eq!( Secret::payload_for_prototype_execution( ctx, dummy_secret_that_will_pass_the_qualification.id() ) .await .expect("could not get payload"), // expected dummy_output_socket.get(ctx).await // actual ); assert_eq!( Secret::payload_for_prototype_execution( ctx, double_secret_that_will_pass_the_qualification.id() ) .await .expect("could not get payload"), // expected double_output_socket.get(ctx).await // actual ); // Check that the qualification passes. let qualifications = Component::list_qualifications(ctx, double.id()) .await .expect("could not list qualifications"); let qualification = qualifications .into_iter() .find(|q| q.qualification_name == "test:qualificationDummyDoubleSecretStringIsTodd") .expect("could not find qualification"); assert_eq!( QualificationSubCheckStatus::Success, // expected qualification.result.expect("no result found").status // actual ); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server