commit d5b2c2045996b3879a3a9c5051683437a42c67ba
parent e0b7fcd4b707e1170e928d0606e344c9f393f6b8
Author: Gavin Peacock <gpeacock@adobe.com>
Date: Mon, 25 Mar 2024 10:31:37 -0700
Adds Action changes field as option vec of serde_json value (#431)
* 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.
* Fix some CBOR assertions were reporting as JSON.
* fix v2 Action test
* remove yaml config support for config due to unsupported yaml-rust crate
Diffstat:
4 files changed, 133 insertions(+), 15 deletions(-)
diff --git 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", 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/assertions/actions.rs b/sdk/src/assertions/actions.rs
@@ -104,12 +104,16 @@ pub struct Action {
software_agent: Option<SoftwareAgent>,
/// 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<String>,
+
+ /// 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<String>,
+ changes: Option<Vec<serde_json::Value>>,
/// The value of the `xmpMM:InstanceID` property for the modified (output) resource.
#[serde(rename = "instanceId", skip_serializing_if = "Option::is_none")]
@@ -152,7 +156,7 @@ impl Action {
matches!(
self.software_agent,
Some(SoftwareAgent::ClaimGeneratorInfo(_))
- )
+ ) || self.changes.is_some() // only defined for v2
}
/// Returns the label for this action.
@@ -703,19 +707,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 +727,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 +781,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
@@ -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())
@@ -1424,6 +1430,68 @@ pub(crate) mod tests {
}
#[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");
+ 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");
+ }
+
+ #[test]
fn test_verifiable_credential() {
let mut manifest = test_manifest();
let vc: serde_json::Value = serde_json::from_str(TEST_VC).unwrap();
@@ -1974,7 +2042,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": [
diff --git 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),
};