Skip to content
This repository has been archived by the owner on Feb 3, 2023. It is now read-only.

Add validation for agent entry #1497

Merged
merged 34 commits into from
Jul 18, 2019
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
f1bc17b
add validation function for agent_entry that is dispatched on validat…
willemolding Jun 10, 2019
4f686f7
adds dispatcher to zome code and stub zome validation function
willemolding Jun 10, 2019
8cd0203
adds __hdk_validate_app_entry callback to existing wasm tests
willemolding Jun 10, 2019
d46c2af
adds calling of non-existent AgentValidator on the zome definition
willemolding Jun 10, 2019
67d35b0
add stringified error for no registered agent validator
willemolding Jun 10, 2019
d2cf5d8
adds macro field for adding validate_agent
willemolding Jun 10, 2019
242ea6b
fmt
willemolding Jun 10, 2019
13ab846
start fixing test zomes
willemolding Jun 10, 2019
8f71407
add validate agent proc macro
willemolding Jun 10, 2019
e595dd1
add validate_agent to proc macro hdk
willemolding Jun 10, 2019
1a0b234
update changelog
willemolding Jun 10, 2019
8b18d56
Merge branch 'develop' into add-validation-for-agent-entry
willemolding Jun 10, 2019
98d892b
fmt
willemolding Jun 10, 2019
63a42e8
Merge branch 'add-validation-for-agent-entry' of https://github.com/h…
willemolding Jun 10, 2019
da76f4d
Merge branch 'develop' into add-validation-for-agent-entry
willemolding Jun 10, 2019
6991be8
Merge branch 'develop' of https://github.com/holochain/holochain-rust…
willemolding Jun 11, 2019
600d7ea
fix up hdk-proc-macro tests
willemolding Jun 11, 2019
1305de5
change type formatting on hdk-proc-macro tests
willemolding Jun 11, 2019
5cbc759
adds updated app spec dna to node conductor test dir
willemolding Jun 11, 2019
468218b
Merge branch 'develop' into add-validation-for-agent-entry
willemolding Jun 12, 2019
c04d948
Merge branch 'develop' into add-validation-for-agent-entry
Jun 17, 2019
c8a8d80
Whitespace
Jun 17, 2019
aa677ba
merge develop into add-validation-for-agent-entry
zippy Jun 22, 2019
206dd83
fix merge problem
zippy Jun 24, 2019
f59674b
Merge branch 'develop' into add-validation-for-agent-entry
zippy Jun 24, 2019
6410d7b
Merge branch 'develop' into add-validation-for-agent-entry
willemolding Jun 29, 2019
b882210
Merge branch 'develop' into add-validation-for-agent-entry
willemolding Jul 1, 2019
638173e
Merge branch 'develop' into add-validation-for-agent-entry
willemolding Jul 3, 2019
40bb8e5
Merge branch 'develop' into add-validation-for-agent-entry
lucksus Jul 4, 2019
d125666
merge develop
willemolding Jul 17, 2019
aa5160d
update simple zome in app spec
willemolding Jul 17, 2019
d09bdc6
add app-spec test for rejecting agents via validate_agent
willemolding Jul 17, 2019
fff9f62
add test to proc macro tests also
willemolding Jul 17, 2019
0dffcd6
Merge branch 'develop' into add-validation-for-agent-entry
willemolding Jul 18, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG-UNRELEASED.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Error log output added for errors occurring during `hdk::call`, including bridge call errors [#1448](https://github.com/holochain/holochain-rust/pull/1448).
- New `uuid` parameter for `admin/dna/install_from_file`, to set the UUID of the installed DNA, changing its hash
- **BREAKING:** Conductor configuration checks for bridges added [#1461](https://github.com/holochain/holochain-rust/pull/1461). Conductor will bail with an error message if the configuration of bridges between instances does not match the bridge requirements defined in the caller instance's DNA (required bridge missing, DNA hash mismatch, trait mismatch) or if a bridge with the handle specified in the config can not be found in the caller's DNA.
- **BREAKING:** Zomes must now include a `validate_agent` callback. If this rejects in any zome the DNA will not start. This can be used to enforce membrane requirements. [#1497](https://github.com/holochain/holochain-rust/pull/1497)

### Changed
- Added a Vagrant file to support nix-shell compatible VMs on windows etc. [#1433](https://github.com/holochain/holochain-rust/pull/1433)
Expand Down
4 changes: 4 additions & 0 deletions app_spec/zomes/blog/code/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ define_zome! {
Ok(())
}

validate_agent: |validation_data : EntryValidationData::<AgentId>| {
Ok(())
}

receive: |from, msg_json| {
blog::handle_receive(from, JsonString::from_json(&msg_json))
}
Expand Down
4 changes: 4 additions & 0 deletions app_spec/zomes/converse/code/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ define_zome! {
}
}

validate_agent: |validation_data : EntryValidationData::<AgentId>| {
Ok(())
}

functions: [
sign_message: {
inputs: |key_id: String, message: String|,
Expand Down
4 changes: 4 additions & 0 deletions app_spec/zomes/summer/code/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ define_zome! {
Ok(())
}

validate_agent: |validation_data : EntryValidationData::<AgentId>| {
Ok(())
}

functions: [
sum: {
inputs: |num1: u32, num2: u32|,
Expand Down
5 changes: 5 additions & 0 deletions app_spec_proc_macro/zomes/blog/code/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ pub mod blog {
Ok(())
}

#[validate_agent]
pub fn validate_agent(validation_data: EntryValidationData<AgentId>) {
Ok(())
}

#[receive]
pub fn receive(from: Address, msg_json: String) {
blog::handle_receive(from, JsonString::from_json(&msg_json))
Expand Down
5 changes: 5 additions & 0 deletions app_spec_proc_macro/zomes/converse/code/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ pub mod converse {
.map_err(|err| format!("new seed generation failed: {}",err) )
}

#[validate_agent]
pub fn validate_agent(validation_data: EntryValidationData<AgentId>) {
Ok(())
}

#[zome_fn("hc_public")]
pub fn sign_message(key_id: String, message: String) -> ZomeApiResult<Signature> {
if key_id == "" {
Expand Down
5 changes: 5 additions & 0 deletions app_spec_proc_macro/zomes/summer/code/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ pub mod summer {
Ok(())
}

#[validate_agent]
pub fn validate_agent(validation_data: EntryValidationData<AgentId>) {
Ok(())
}

#[zome_fn("hc_public")]
fn sum(num1: u32, num2: u32) -> ZomeApiResult<u32> {
Ok(num1 + num2)
Expand Down
8 changes: 8 additions & 0 deletions conductor_api/src/conductor/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1404,6 +1404,14 @@ pub mod tests {
(i64.const 0)
)

(func
(export "__hdk_validate_agent_entry")
(param $allocation i64)
(result i64)

(i64.const 0)
)

(func
(export "__hdk_validate_link")
(param $allocation i64)
Expand Down
4 changes: 4 additions & 0 deletions conductor_api/test-bridge-caller/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ define_zome! {
Ok(())
}

validate_agent: |validation_data : EntryValidationData::<AgentId>| {
Ok(())
}

functions: [
call_bridge: {
inputs: | |,
Expand Down
8 changes: 8 additions & 0 deletions core/src/network/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ pub fn test_wat_always_valid() -> String {
(i64.const 0)
)

(func
(export "__hdk_validate_agent_entry")
(param $allocation i64)
(result i64)

(i64.const 0)
)

(func
(export "__hdk_validate_link")
(param $allocation i64)
Expand Down
4 changes: 4 additions & 0 deletions core/src/nucleus/actions/wasm-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ define_zome! {
Ok(())
}

validate_agent: |validation_data : EntryValidationData::<AgentId>| {
Ok(())
}

functions: [
test_fn: {
inputs: | |,
Expand Down
8 changes: 8 additions & 0 deletions core/src/nucleus/ribosome/api/get_entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,14 @@ pub mod tests {
(i64.const 0)
)

(func
(export "__hdk_validate_agent_entry")
(param $allocation i64)
(result i64)

(i64.const 0)
)

(func
(export "__hdk_get_validation_package_for_entry_type")
(param $allocation i64)
Expand Down
8 changes: 8 additions & 0 deletions core/src/nucleus/ribosome/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,14 @@ pub mod tests {
(i64.const 0)
)

(func
(export "__hdk_validate_agent_entry")
(param $allocation i64)
(result i64)

(i64.const 0)
)

(func
(export "__hdk_validate_link")
(param $allocation i64)
Expand Down
62 changes: 62 additions & 0 deletions core/src/nucleus/validation/agent_entry.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use crate::{
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is really the only new piece of core code. The rest is fixing tests and dealing with the macros

context::Context,
nucleus::{
actions::run_validation_callback::run_validation_callback,
validation::{ValidationError, ValidationResult},
CallbackFnCall,
},
};
use holochain_core_types::{
agent::AgentId,
cas::content::AddressableContent,
entry::Entry,
validation::{EntryValidationData, ValidationData},
};
use holochain_wasm_utils::api_serialization::validation::AgentIdValidationArgs;

use futures::future;
use futures_util::future::FutureExt;
use std::sync::Arc;

pub async fn validate_agent_entry(
entry: Entry,
validation_data: ValidationData,
context: &Arc<Context>,
) -> ValidationResult {
let dna = context.get_dna().expect("Callback called without DNA set!");

let agent_id = unwrap_to!(entry => Entry::AgentId);

let params = AgentIdValidationArgs {
validation_data: EntryValidationData::<AgentId>::Create {
entry: agent_id.to_owned(),
validation_data,
},
};

context.log(format!("Validating agent entry with args: {:?}", params));

let results = await!(future::join_all(dna.zomes.iter().map(|(zome_name, _)| {
let call = CallbackFnCall::new(&zome_name, "__hdk_validate_agent_entry", params.clone());
// Need to return a boxed future for it to work with join_all
// https://users.rust-lang.org/t/the-trait-unpin-is-not-implemented-for-genfuture-error-when-using-join-all/23612/2
run_validation_callback(entry.address(), call, &context).boxed()
})));

let errors: Vec<ValidationError> = results
.iter()
.filter_map(|r| match r {
Ok(_) => None,
Err(e) => Some(e.to_owned()),
})
.collect();

if errors.is_empty() {
context.log(format!("Validating agent entry success!: {:?}", results));
Ok(())
} else {
Err(ValidationError::Error(
format!("Failed to validate agent ID on a zome, {:?}", errors).into(),
))
}
}
13 changes: 6 additions & 7 deletions core/src/nucleus/validation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use holochain_core_types::{

use std::sync::Arc;

mod agent_entry;
mod app_entry;
mod header_address;
mod link_entry;
Expand Down Expand Up @@ -116,13 +117,11 @@ pub async fn validate_entry(
// a grant should always be private, so it should always pass
EntryType::CapTokenGrant => Ok(()),

// TODO: actually check agent against app specific membrane validation rule
// like for instance: validate_agent_id(
// entry.clone(),
// validation_data,
// context,
// )?
EntryType::AgentId => Ok(()),
EntryType::AgentId => await!(agent_entry::validate_agent_entry(
entry.clone(),
validation_data,
context,
)),

_ => Err(ValidationError::NotImplemented),
}
Expand Down
8 changes: 8 additions & 0 deletions hdk-proc-macros/src/code_generators/zome_setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,21 @@ impl ZomeCodeDef {
.map(|func| func.ident.clone())
.clone();

let agent_validation_param = &self.validate_agent.validation_data_param;
let agent_validation_expr = &self.validate_agent.code;

quote! {
#[no_mangle]
#[allow(unused_variables)]
pub extern "C" fn zome_setup(zd: &mut hdk::meta::ZomeDefinition) {
#(
zd.define(#entry_fn_idents ());
)*
let validator = Box::new(|validation_data: hdk::holochain_wasm_utils::holochain_core_types::validation::EntryValidationData<hdk::holochain_core_types::agent::AgentId>| {
let #agent_validation_param = validation_data;
#agent_validation_expr
});
zd.define_agent_validator(validator);
}
}
}
Expand Down
55 changes: 53 additions & 2 deletions hdk-proc-macros/src/into_zome.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
extern crate proc_macro2;

use crate::zome_code_def::{
EntryDefCallbacks, FnDeclaration, FnParameter, GenesisCallback, ReceiveCallback, ZomeCodeDef,
ZomeFunction, ZomeFunctions,
EntryDefCallbacks, FnDeclaration, FnParameter, GenesisCallback, ReceiveCallback,
ValidateAgentCallback, ZomeCodeDef, ZomeFunction, ZomeFunctions,
};

use hdk::holochain_core_types::dna::{fn_declarations::TraitFns, zome::ZomeTraits};
use std::collections::BTreeMap;

static GENESIS_ATTRIBUTE: &str = "genesis";
static VALIDATE_AGENT_ATTRIBUTE: &str = "validate_agent";
static ZOME_FN_ATTRIBUTE: &str = "zome_fn";
static ENTRY_DEF_ATTRIBUTE: &str = "entry_def";
static RECEIVE_CALLBACK_ATTRIBUTE: &str = "receive";
Expand All @@ -17,6 +18,7 @@ pub trait IntoZome {
fn extract_zome_fns(&self) -> ZomeFunctions;
fn extract_entry_defs(&self) -> EntryDefCallbacks;
fn extract_genesis(&self) -> GenesisCallback;
fn extract_validate_agent(&self) -> ValidateAgentCallback;
fn extract_traits(&self) -> ZomeTraits;
fn extract_receive_callback(&self) -> Option<ReceiveCallback>;
fn extract_extra(&self) -> Vec<syn::Item>;
Expand All @@ -26,6 +28,7 @@ pub trait IntoZome {
traits: self.extract_traits(),
entry_def_fns: self.extract_entry_defs(),
genesis: self.extract_genesis(),
validate_agent: self.extract_validate_agent(),
receive_callback: self.extract_receive_callback(),
zome_fns: self.extract_zome_fns(),
extra: self.extract_extra(),
Expand Down Expand Up @@ -127,6 +130,53 @@ impl IntoZome for syn::ItemMod {
}
}

fn extract_validate_agent(&self) -> ValidateAgentCallback {
// find all the functions tagged as the genesis callback
let callbacks: Vec<syn::ItemFn> = funcs_iter(self)
.filter(is_tagged_with(VALIDATE_AGENT_ATTRIBUTE))
.fold(Vec::new(), |mut acc, func| {
acc.push(func);
acc
});
// only a single function can be tagged as validate_agent in a valid Zome.
// Error if there is more than one
// Also error if tagged function
match callbacks.len() {
0 => {
emit_error(&self.ident,
"No validate_agent function defined! A zome definition requires a callback tagged with #[validate_agent]");
panic!()
}
1 => {
let callback = callbacks[0].clone();
let fn_def = zome_fn_dec_from_syn(&callback);

// must have the valid function signature which is ($ident: EntryValidationData::<AgentId>)
let validation_data_param = match fn_def.inputs.len() {
1 => {
let param = fn_def.inputs[0].clone();
param.ident
}
_ => {
emit_error(&self.ident,
"incorrect number of params for validate_agent callback. Must have a single param with type `EntryValidationData::<AgentId>`");
panic!()
}
};

ValidateAgentCallback {
validation_data_param,
code: (*callback.block),
}
}
_ => {
emit_error(&self.ident,
"Multiple functions tagged as validate_agent callback! Only one is permitted per zome definition.");
panic!()
}
}
}

fn extract_zome_fns(&self) -> ZomeFunctions {
// find all the functions tagged as the zome_fn
funcs_iter(self)
Expand Down Expand Up @@ -196,6 +246,7 @@ impl IntoZome for syn::ItemMod {
&& !is_tagged_with(GENESIS_ATTRIBUTE)(func)
&& !is_tagged_with(ENTRY_DEF_ATTRIBUTE)(func)
&& !is_tagged_with(RECEIVE_CALLBACK_ATTRIBUTE)(func)
&& !is_tagged_with(VALIDATE_AGENT_ATTRIBUTE)(func)
} else {
true // and anything that is not a function
}
Expand Down
7 changes: 7 additions & 0 deletions hdk-proc-macros/src/zome_code_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ pub struct ReceiveCallback {
pub code: syn::Block,
}

#[derive(Clone, PartialEq, Debug)]
pub struct ValidateAgentCallback {
pub validation_data_param: Ident,
pub code: syn::Block,
}

#[derive(Clone, PartialEq, Debug)]
pub struct FnParameter {
pub ident: Ident,
Expand Down Expand Up @@ -74,6 +80,7 @@ pub type EntryDefCallbacks = Vec<EntryDefCallback>;

pub struct ZomeCodeDef {
pub genesis: GenesisCallback,
pub validate_agent: ValidateAgentCallback,
pub zome_fns: ZomeFunctions, // receive: ReceiveCallbacks
pub entry_def_fns: Vec<syn::ItemFn>,
pub traits: ZomeTraits,
Expand Down