From 439913af2c08ed4f3898157f0c6ca2a2e3af7a84 Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Fri, 22 Mar 2024 18:25:35 -0700 Subject: [PATCH 1/7] Adds Action changed field as option vec of serde_json value There are no Rust APIS for this yet. But it allows the values to pass through via actions. --- sdk/src/assertions/actions.rs | 58 ++++++++++++++++++++----- sdk/src/manifest.rs | 82 ++++++++++++++++++++++++++++++++++- 2 files changed, 127 insertions(+), 13 deletions(-) diff --git a/sdk/src/assertions/actions.rs b/sdk/src/assertions/actions.rs index b5aa03396..d3933dfa3 100644 --- a/sdk/src/assertions/actions.rs +++ b/sdk/src/assertions/actions.rs @@ -105,11 +105,17 @@ pub struct Action { /// A semicolon-delimited list of the parts of the resource that were changed since the previous event history. /// + /// This is deprecated in favor of the `changes` field. + #[serde(skip_serializing_if = "Option::is_none")] + changed: Option, + + /// A list of the regions of interest of the resource that were changed. + /// /// If not present, presumed to be undefined. /// When tracking changes and the scope of the changed components is unknown, /// it should be assumed that anything might have changed. #[serde(skip_serializing_if = "Option::is_none")] - changed: Option, + changes: Option>, /// The value of the `xmpMM:InstanceID` property for the modified (output) resource. #[serde(rename = "instanceId", skip_serializing_if = "Option::is_none")] @@ -152,7 +158,7 @@ impl Action { matches!( self.software_agent, Some(SoftwareAgent::ClaimGeneratorInfo(_)) - ) + ) || self.changed.is_some() // was a String in v1 but never used so presume v2 if see it } /// Returns the label for this action. @@ -243,6 +249,7 @@ impl Action { /// Sets the list of the parts of the resource that were changed /// since the previous event history. + #[deprecated(since = "0.33.0", note = "Use add_changed instead")] pub fn set_changed(mut self, changed: Option<&Vec<&str>>) -> Self { self.changed = changed.map(|v| v.join(";")); self @@ -516,7 +523,6 @@ pub mod tests { .unwrap() .set_parameter("ingredient".to_owned(), make_hashed_uri1()) .unwrap() - .set_changed(Some(&["this", "that"].to_vec())) .set_instance_id("xmp.iid:cb9f5498-bb58-4572-8043-8c369e6bfb9b") .set_actors(Some( &[Actor::new( @@ -703,19 +709,19 @@ pub mod tests { fn test_json_v2_round_trip() { let json = serde_json::json!({ "actions": [ - { + { "action": "c2pa.edited", "parameters": { - "description": "gradient", - "name": "any value" + "description": "gradient", + "name": "any value" }, "softwareAgent": "TestApp" - }, - { + }, + { "action": "c2pa.opened", "instanceId": "xmp.iid:7b57930e-2f23-47fc-affe-0400d70b738d", "parameters": { - "description": "import" + "description": "import" }, "digitalSourceType": "http://cv.iptc.org/newscodes/digitalsourcetype/algorithmicMedia", "softwareAgent": { @@ -723,10 +729,32 @@ pub mod tests { "version": "1.0", "something": "else" }, - }, - { + }, + { "action": "com.joesphoto.filter", - } + }, + { + "action": "c2pa.dubbed", + "changes": [ + { + "description": "translated to klingon", + "region": [ + { + "type": "temporal", + "time": {} + }, + { + "type": "identified", + "item": { + "identifier": "https://bioportal.bioontology.org/ontologies/FMA", + "value": "lips" + } + } + ] + } + ] + } + ], "templates": [ { @@ -755,5 +783,11 @@ pub mod tests { result.actions[0].software_agent().unwrap(), &SoftwareAgent::String("TestApp".to_string()) ); + assert_eq!( + result.actions[3].changes.as_deref().unwrap()[0] + .get("description") + .unwrap(), + "translated to klingon" + ); } } diff --git a/sdk/src/manifest.rs b/sdk/src/manifest.rs index 89ee20726..1073d88ea 100644 --- a/sdk/src/manifest.rs +++ b/sdk/src/manifest.rs @@ -1423,6 +1423,68 @@ pub(crate) mod tests { assert!(result.is_err()) } + #[test] + #[cfg(feature = "file_io")] + /// test assertion validation on actions, should generate an error + fn ws_valid_labeled_assertion() { + // copy an image to use as our target for embedding + let ap = fixture_path(TEST_SMALL_JPEG); + let temp_dir = tempdir().expect("temp dir"); + let test_output = temp_dir_path(&temp_dir, "ws_bad_assertion.jpg"); + std::fs::copy(ap, test_output).expect("copy"); + + let mut manifest = test_manifest(); + + manifest + .add_labeled_assertion( + "c2pa.actions", + &serde_json::json!({ + "actions": [ + { + "action": "c2pa.edited", + "parameters": { + "description": "gradient", + "name": "any value" + }, + "softwareAgent": "TestApp" + }, + { + "action": "c2pa.dubbed", + "changes": [ + { + "description": "translated to klingon", + "region": [ + { + "type": "temporal", + "time": {} + }, + { + "type": "identified", + "item": { + "identifier": "https://bioportal.bioontology.org/ontologies/FMA", + "value": "lips" + } + } + ] + } + ] + } + ] + }), + ) + .expect("add_assertion"); + + // convert to store + let store = manifest.to_store().expect("valid action to_store"); + let m2 = Manifest::from_store(&store, &store.provenance_label().unwrap(), None) + .expect("from_store"); + //println!("{m2:?}"); + // todo:: this looks correct, but it isn't since it is stored as a JSON assertion instead of CBOR + let actions: Actions = m2.find_assertion("c2pa.actions").expect("find_assertion"); + assert_eq!(actions.actions()[0].action(), "c2pa.edited"); + assert_eq!(actions.actions()[1].action(), "c2pa.dubbed"); + } + #[test] fn test_verifiable_credential() { let mut manifest = test_manifest(); @@ -1974,7 +2036,25 @@ pub(crate) mod tests { "identifier": "sample1.svg" }, "something": "else" - } + }, + "changes": [ + { + "region" : [ + { + "type" : "temporal", + "time" : {} + }, + { + "type" : "identified", + "item" : { + "identifier" : "https://bioportal.bioontology.org/ontologies/FMA", + "value" : "lips" + } + } + ], + "description": "lip synced area" + } + ] } ], "templates": [ From 7cc9f6216df469699ad3c58fb48c99cb555d3902 Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Fri, 22 Mar 2024 20:53:17 -0700 Subject: [PATCH 2/7] Fix some CBOR assertions were reporting as JSON. --- sdk/src/manifest.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sdk/src/manifest.rs b/sdk/src/manifest.rs index 1073d88ea..709bcb610 100644 --- a/sdk/src/manifest.rs +++ b/sdk/src/manifest.rs @@ -639,7 +639,13 @@ impl Manifest { _ => { // inject assertions for all other assertions match assertion.decode_data() { - AssertionData::Json(_) | AssertionData::Cbor(_) => { + AssertionData::Cbor(_) => { + let value = assertion.as_json_object()?; + let ma = ManifestAssertion::new(base_label, value) + .set_instance(claim_assertion.instance()); + manifest.assertions.push(ma); + } + AssertionData::Json(_) => { let value = assertion.as_json_object()?; let ma = ManifestAssertion::new(base_label, value) .set_instance(claim_assertion.instance()) From cbf209bec551a035b2b791aea431f2e0e7911f32 Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Fri, 22 Mar 2024 21:07:16 -0700 Subject: [PATCH 3/7] fix v2 Action test --- sdk/src/assertions/actions.rs | 5 +++-- sdk/src/manifest.rs | 4 +--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/sdk/src/assertions/actions.rs b/sdk/src/assertions/actions.rs index d3933dfa3..eeb19388d 100644 --- a/sdk/src/assertions/actions.rs +++ b/sdk/src/assertions/actions.rs @@ -158,7 +158,8 @@ impl Action { matches!( self.software_agent, Some(SoftwareAgent::ClaimGeneratorInfo(_)) - ) || self.changed.is_some() // was a String in v1 but never used so presume v2 if see it + ) || + self.changes.is_some() // only defined for v2 } /// Returns the label for this action. @@ -249,7 +250,6 @@ impl Action { /// Sets the list of the parts of the resource that were changed /// since the previous event history. - #[deprecated(since = "0.33.0", note = "Use add_changed instead")] pub fn set_changed(mut self, changed: Option<&Vec<&str>>) -> Self { self.changed = changed.map(|v| v.join(";")); self @@ -523,6 +523,7 @@ pub mod tests { .unwrap() .set_parameter("ingredient".to_owned(), make_hashed_uri1()) .unwrap() + .set_changed(Some(&["this", "that"].to_vec())) .set_instance_id("xmp.iid:cb9f5498-bb58-4572-8043-8c369e6bfb9b") .set_actors(Some( &[Actor::new( diff --git a/sdk/src/manifest.rs b/sdk/src/manifest.rs index 709bcb610..b21f82386 100644 --- a/sdk/src/manifest.rs +++ b/sdk/src/manifest.rs @@ -1484,9 +1484,7 @@ pub(crate) mod tests { let store = manifest.to_store().expect("valid action to_store"); let m2 = Manifest::from_store(&store, &store.provenance_label().unwrap(), None) .expect("from_store"); - //println!("{m2:?}"); - // todo:: this looks correct, but it isn't since it is stored as a JSON assertion instead of CBOR - let actions: Actions = m2.find_assertion("c2pa.actions").expect("find_assertion"); + let actions: Actions = m2.find_assertion("c2pa.actions.v2").expect("find_assertion"); assert_eq!(actions.actions()[0].action(), "c2pa.edited"); assert_eq!(actions.actions()[1].action(), "c2pa.dubbed"); } From df6cc20b68b2f447aeb0c6a4e110ad23375c3c15 Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Fri, 22 Mar 2024 21:09:04 -0700 Subject: [PATCH 4/7] fmt fussiness --- sdk/src/assertions/actions.rs | 3 +-- sdk/src/manifest.rs | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/sdk/src/assertions/actions.rs b/sdk/src/assertions/actions.rs index eeb19388d..545f1db8c 100644 --- a/sdk/src/assertions/actions.rs +++ b/sdk/src/assertions/actions.rs @@ -158,8 +158,7 @@ impl Action { matches!( self.software_agent, Some(SoftwareAgent::ClaimGeneratorInfo(_)) - ) || - self.changes.is_some() // only defined for v2 + ) || self.changes.is_some() // only defined for v2 } /// Returns the label for this action. diff --git a/sdk/src/manifest.rs b/sdk/src/manifest.rs index b21f82386..fbbb078ae 100644 --- a/sdk/src/manifest.rs +++ b/sdk/src/manifest.rs @@ -1484,7 +1484,9 @@ pub(crate) mod tests { let store = manifest.to_store().expect("valid action to_store"); let m2 = Manifest::from_store(&store, &store.provenance_label().unwrap(), None) .expect("from_store"); - let actions: Actions = m2.find_assertion("c2pa.actions.v2").expect("find_assertion"); + let actions: Actions = m2 + .find_assertion("c2pa.actions.v2") + .expect("find_assertion"); assert_eq!(actions.actions()[0].action(), "c2pa.edited"); assert_eq!(actions.actions()[1].action(), "c2pa.dubbed"); } From 51230f33848359882d18f3bd182b6ed75278e4ed Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Mon, 25 Mar 2024 08:38:15 -0700 Subject: [PATCH 5/7] remove changed deprecated comment --- sdk/src/assertions/actions.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/sdk/src/assertions/actions.rs b/sdk/src/assertions/actions.rs index 545f1db8c..d4db2e0cd 100644 --- a/sdk/src/assertions/actions.rs +++ b/sdk/src/assertions/actions.rs @@ -105,7 +105,6 @@ pub struct Action { /// A semicolon-delimited list of the parts of the resource that were changed since the previous event history. /// - /// This is deprecated in favor of the `changes` field. #[serde(skip_serializing_if = "Option::is_none")] changed: Option, From cb0fec0374f6891472f262cdf461f0f9d0e3a4d3 Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Mon, 25 Mar 2024 09:44:33 -0700 Subject: [PATCH 6/7] remove yaml support for config due to unsupported crate --- sdk/Cargo.toml | 2 +- sdk/src/assertions/actions.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index a1ae2352d..e9ca1d638 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -71,7 +71,7 @@ chrono = { version = "0.4.27", default-features = false, features = [ "wasmbind", ] } ciborium = "0.2.0" -config = "0.14.0" +config = {version = "0.14.0", features = ["json", "json5", "toml"]} conv = "0.3.3" coset = "0.3.1" extfmt = "0.1.1" diff --git a/sdk/src/assertions/actions.rs b/sdk/src/assertions/actions.rs index d4db2e0cd..2377b5dc5 100644 --- a/sdk/src/assertions/actions.rs +++ b/sdk/src/assertions/actions.rs @@ -104,7 +104,6 @@ pub struct Action { software_agent: Option, /// A semicolon-delimited list of the parts of the resource that were changed since the previous event history. - /// #[serde(skip_serializing_if = "Option::is_none")] changed: Option, From ec627d3847edaaa1af96ad78897ecc5c8d582a1e Mon Sep 17 00:00:00 2001 From: Gavin Peacock Date: Mon, 25 Mar 2024 10:09:18 -0700 Subject: [PATCH 7/7] no_default on config, remove yaml option --- sdk/Cargo.toml | 2 +- sdk/src/settings.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index e9ca1d638..02c9d2d04 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -71,7 +71,7 @@ chrono = { version = "0.4.27", default-features = false, features = [ "wasmbind", ] } ciborium = "0.2.0" -config = {version = "0.14.0", features = ["json", "json5", "toml"]} +config = {version = "0.14.0", default-features = false, features = ["json", "json5", "toml", "ron", "ini"]} conv = "0.3.3" coset = "0.3.1" extfmt = "0.1.1" diff --git a/sdk/src/settings.rs b/sdk/src/settings.rs index 8b84bd8ad..292da43c3 100644 --- a/sdk/src/settings.rs +++ b/sdk/src/settings.rs @@ -222,7 +222,7 @@ impl Settings { "json5" => FileFormat::Json5, "ini" => FileFormat::Ini, "toml" => FileFormat::Toml, - "yaml" => FileFormat::Yaml, + //"yaml" => FileFormat::Yaml, "ron" => FileFormat::Ron, _ => return Err(Error::UnsupportedType), };