| // Copyright 2026 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| |
| #include "assertion/actions_assertion_validator.h" |
| |
| #include <string> |
| |
| #include "absl/strings/str_format.h" |
| #include "absl/strings/string_view.h" |
| #include "constants/status_codes.h" |
| #include "gmock/gmock.h" |
| #include "gtest/gtest.h" |
| #include "proto/manifest.pb.h" |
| #include "testing/proto_test_utils.h" |
| #include "testing/test_validation_tracker.h" |
| |
| namespace credentio { |
| namespace { |
| |
| using ::credentio_testing::ParseTextProtoOrDie; |
| using ::testing::IsEmpty; |
| using ::testing::TestWithParam; |
| using ::testing::ValuesIn; |
| |
| // Returns the appropriate ingredient relationship for the given action. |
| std::string IngredientRelation(absl::string_view action) { |
| return (action == "c2pa.placed" || action == "c2pa.removed") ? "componentOf" |
| : "parentOf"; |
| } |
| |
| TEST(ActionsAssertionValidatorTest, Okay) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(R"pb( |
| claim { |
| created_assertions { url: "self#jumbf=c2pa.assertions/c2pa.actions.v2" } |
| } |
| assertions { |
| label: "c2pa.actions.v2" |
| actions { actions { action: "c2pa.created" } } |
| } |
| )pb"); |
| EXPECT_TRUE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT(tracker.GetFailures(), IsEmpty()); |
| } |
| |
| TEST(ActionsAssertionValidatorTest, OkayV1) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(R"pb( |
| claim { |
| created_assertions { url: "self#jumbf=c2pa.assertions/c2pa.actions" } |
| } |
| assertions { |
| label: "c2pa.actions" |
| actions_v1 { actions { action: "c2pa.created" } } |
| } |
| )pb"); |
| EXPECT_TRUE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT(tracker.GetFailures(), IsEmpty()); |
| } |
| |
| TEST(ActionsAssertionValidatorTest, NoActions) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(R"pb( |
| assertions { actions {} } |
| )pb"); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT(tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionMalformed)); |
| } |
| |
| TEST(ActionsAssertionValidatorTest, NoActionsV1) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(R"pb( |
| assertions { actions_v1 {} } |
| )pb"); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT(tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionMalformed)); |
| } |
| |
| TEST(ActionsAssertionValidatorTest, CreatedNotFirst) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(R"pb( |
| assertions { |
| actions { |
| actions { action: "c2pa.drawing" } |
| actions { action: "c2pa.created" } |
| } |
| } |
| )pb"); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT(tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionMalformed)); |
| } |
| |
| TEST(ActionsAssertionValidatorTest, CreatedNotFirstV1) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(R"pb( |
| assertions { |
| actions_v1 { |
| actions { action: "c2pa.drawing" } |
| actions { action: "c2pa.created" } |
| } |
| } |
| )pb"); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT(tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionMalformed)); |
| } |
| |
| TEST(ActionsAssertionValidatorTest, OpenedNotFirst) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(R"pb( |
| assertions { |
| actions { |
| actions { action: "c2pa.drawing" } |
| actions { action: "c2pa.opened" } |
| } |
| } |
| )pb"); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT(tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionMalformed)); |
| } |
| |
| TEST(ActionsAssertionValidatorTest, OpenedNotFirstV1) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(R"pb( |
| assertions { |
| actions_v1 { |
| actions { action: "c2pa.drawing" } |
| actions { action: "c2pa.opened" } |
| } |
| } |
| )pb"); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT(tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionMalformed)); |
| } |
| |
| TEST(ActionsAssertionValidatorTest, EmptyAction) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(R"pb( |
| assertions { actions { actions { action: "" } } } |
| )pb"); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT(tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionMalformed)); |
| } |
| |
| TEST(ActionsAssertionValidatorTest, EmptyActionV1) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(R"pb( |
| assertions { actions_v1 { actions { action: "" } } } |
| )pb"); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT(tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionMalformed)); |
| } |
| |
| struct ActionParam { |
| std::string action_name; |
| }; |
| |
| using ValidateIngredientTest = TestWithParam<ActionParam>; |
| TEST_P(ValidateIngredientTest, MissingParameters) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>( |
| absl::StrFormat(R"pb( |
| assertions { actions { actions { action: "%s" } } } |
| )pb", |
| GetParam().action_name)); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT( |
| tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionIngredientMismatch)); |
| } |
| |
| TEST_P(ValidateIngredientTest, MissingParametersV1) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>( |
| absl::StrFormat(R"pb( |
| assertions { actions_v1 { actions { action: "%s" } } } |
| )pb", |
| GetParam().action_name)); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT( |
| tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionIngredientMismatch)); |
| } |
| |
| TEST_P(ValidateIngredientTest, MissingIngredients) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = |
| ParseTextProtoOrDie<Manifest>(absl::StrFormat(R"pb( |
| assertions { |
| actions { |
| actions { |
| action: "%s" |
| parameters {} |
| } |
| } |
| } |
| )pb", |
| GetParam().action_name)); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT( |
| tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionIngredientMismatch)); |
| } |
| |
| TEST_P(ValidateIngredientTest, MissingIngredientsV1) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = |
| ParseTextProtoOrDie<Manifest>(absl::StrFormat(R"pb( |
| assertions { |
| actions_v1 { |
| actions { |
| action: "%s" |
| parameters {} |
| } |
| } |
| } |
| )pb", |
| GetParam().action_name)); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT( |
| tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionIngredientMismatch)); |
| } |
| |
| TEST_P(ValidateIngredientTest, EmptyIngredientUrl) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>( |
| absl::StrFormat(R"pb( |
| assertions { |
| actions { |
| actions { |
| action: "%s" |
| parameters { ingredients {} } |
| } |
| } |
| } |
| )pb", |
| GetParam().action_name)); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT( |
| tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionIngredientMismatch)); |
| } |
| |
| TEST_P(ValidateIngredientTest, EmptyIngredientUrlV1) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>( |
| absl::StrFormat(R"pb( |
| assertions { |
| actions_v1 { |
| actions { |
| action: "%s" |
| parameters { ingredients {} } |
| } |
| } |
| } |
| )pb", |
| GetParam().action_name)); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT( |
| tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionIngredientMismatch)); |
| } |
| |
| TEST_P(ValidateIngredientTest, MissingIngredientAssertion) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(absl::StrFormat( |
| R"pb( |
| assertions { |
| actions { |
| actions { |
| action: "%s" |
| parameters { |
| ingredients { |
| url: "self#jumbf=c2pa.assertions/c2pa.ingredient.v3" |
| } |
| } |
| } |
| } |
| } |
| )pb", |
| GetParam().action_name)); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT( |
| tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionIngredientMismatch)); |
| } |
| |
| TEST_P(ValidateIngredientTest, WrongAssertionType) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(absl::StrFormat( |
| R"pb( |
| assertions { |
| actions { |
| actions { |
| action: "%s" |
| parameters { |
| ingredients { |
| url: "self#jumbf=c2pa.assertions/c2pa.ingredient.v3" |
| } |
| } |
| } |
| } |
| } |
| assertions { |
| label: "c2pa.ingredient.v3" |
| actions {} |
| } |
| )pb", |
| GetParam().action_name)); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT( |
| tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionIngredientMismatch)); |
| } |
| |
| TEST_P(ValidateIngredientTest, NoC2paManifestInIngredientV1) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(absl::StrFormat( |
| R"pb( |
| assertions { |
| actions { |
| actions { |
| action: "%s" |
| parameters { |
| ingredients { |
| url: "self#jumbf=c2pa.assertions/c2pa.ingredient.v3" |
| } |
| } |
| } |
| } |
| } |
| assertions { |
| label: "c2pa.ingredient.v3" |
| ingredient_v3 { relationship: "%s" } |
| } |
| )pb", |
| GetParam().action_name, IngredientRelation(GetParam().action_name))); |
| EXPECT_TRUE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT(tracker.GetFailureStatuses(), IsEmpty()); |
| } |
| |
| TEST_P(ValidateIngredientTest, NoC2paManifestInIngredientV2) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(absl::StrFormat( |
| R"pb( |
| assertions { |
| actions { |
| actions { |
| action: "%s" |
| parameters { |
| ingredients { |
| url: "self#jumbf=c2pa.assertions/c2pa.ingredient.v3" |
| } |
| } |
| } |
| } |
| } |
| assertions { |
| label: "c2pa.ingredient.v3" |
| ingredient_v3 { relationship: "%s" } |
| } |
| )pb", |
| GetParam().action_name, IngredientRelation(GetParam().action_name))); |
| EXPECT_TRUE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT(tracker.GetFailureStatuses(), IsEmpty()); |
| } |
| |
| TEST_P(ValidateIngredientTest, NoC2paManifestInIngredientV3) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(absl::StrFormat( |
| R"pb( |
| assertions { |
| actions { |
| actions { |
| action: "%s" |
| parameters { |
| ingredients { |
| url: "self#jumbf=c2pa.assertions/c2pa.ingredient.v3" |
| } |
| } |
| } |
| } |
| } |
| assertions { |
| label: "c2pa.ingredient.v3" |
| ingredient_v3 { relationship: "%s" } |
| } |
| )pb", |
| GetParam().action_name, IngredientRelation(GetParam().action_name))); |
| EXPECT_TRUE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT(tracker.GetFailureStatuses(), IsEmpty()); |
| } |
| |
| constexpr ActionParam kActionParams[] = { |
| {.action_name = "c2pa.opened"}, {.action_name = "c2pa.placed"}, |
| {.action_name = "c2pa.removed"}, {.action_name = "c2pa.repackaged"}, |
| {.action_name = "c2pa.transcoded"}, |
| }; |
| INSTANTIATE_TEST_SUITE_P(ActionsAssertionValidatorTest, ValidateIngredientTest, |
| ValuesIn(kActionParams)); |
| |
| using ValidateIngredientParentOfTest = TestWithParam<ActionParam>; |
| TEST_P(ValidateIngredientParentOfTest, Valid) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(absl::StrFormat( |
| R"pb( |
| assertions { |
| actions { |
| actions { |
| action: "%s" |
| parameters { |
| ingredients { |
| url: "self#jumbf=c2pa.assertions/c2pa.ingredient.v3" |
| } |
| } |
| } |
| } |
| } |
| assertions { |
| label: "c2pa.ingredient.v3" |
| ingredient_v3 { |
| relationship: "parentOf", |
| active_manifest {} |
| } |
| } |
| )pb", |
| GetParam().action_name)); |
| EXPECT_TRUE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT(tracker.GetFailureStatuses(), IsEmpty()); |
| } |
| |
| TEST_P(ValidateIngredientParentOfTest, WrongRelationshipIngredientV1) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(absl::StrFormat( |
| R"pb( |
| assertions { |
| actions { |
| actions { |
| action: "%s" |
| parameters { |
| ingredients { |
| url: "self#jumbf=c2pa.assertions/c2pa.ingredient.v3" |
| } |
| } |
| } |
| } |
| } |
| assertions { |
| label: "c2pa.ingredient.v3" |
| ingredient_v3 { relationship: "childOf" } |
| } |
| )pb", |
| GetParam().action_name)); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT( |
| tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionIngredientMismatch)); |
| } |
| |
| TEST_P(ValidateIngredientParentOfTest, WrongRelationshipIngredientV2) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(absl::StrFormat( |
| R"pb( |
| assertions { |
| actions { |
| actions { |
| action: "%s" |
| parameters { |
| ingredients { |
| url: "self#jumbf=c2pa.assertions/c2pa.ingredient.v3" |
| } |
| } |
| } |
| } |
| } |
| assertions { |
| label: "c2pa.ingredient.v3" |
| ingredient_v3 { relationship: "childOf" } |
| } |
| )pb", |
| GetParam().action_name)); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT( |
| tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionIngredientMismatch)); |
| } |
| |
| TEST_P(ValidateIngredientParentOfTest, WrongRelationshipIngredientV3) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(absl::StrFormat( |
| R"pb( |
| assertions { |
| actions { |
| actions { |
| action: "%s" |
| parameters { |
| ingredients { |
| url: "self#jumbf=c2pa.assertions/c2pa.ingredient.v3" |
| } |
| } |
| } |
| } |
| } |
| assertions { |
| label: "c2pa.ingredient.v3" |
| ingredient_v3 { relationship: "childOf" } |
| } |
| )pb", |
| GetParam().action_name)); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT( |
| tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionIngredientMismatch)); |
| } |
| constexpr ActionParam kParentOfActionParams[] = { |
| {.action_name = "c2pa.opened"}, |
| {.action_name = "c2pa.repackaged"}, |
| {.action_name = "c2pa.transcoded"}, |
| }; |
| INSTANTIATE_TEST_SUITE_P(ActionsAssertionValidatorTest, |
| ValidateIngredientParentOfTest, |
| ValuesIn(kParentOfActionParams)); |
| |
| using ValidateIngredientComponentOfTest = TestWithParam<ActionParam>; |
| TEST_P(ValidateIngredientComponentOfTest, Valid) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(absl::StrFormat( |
| R"pb( |
| assertions { |
| actions { |
| actions { |
| action: "%s" |
| parameters { |
| ingredients { |
| url: "self#jumbf=c2pa.assertions/c2pa.ingredient.v3" |
| } |
| } |
| } |
| } |
| } |
| assertions { |
| label: "c2pa.ingredient.v3" |
| ingredient_v3 { |
| relationship: "componentOf", |
| active_manifest {} |
| } |
| } |
| )pb", |
| GetParam().action_name)); |
| EXPECT_TRUE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT(tracker.GetFailureStatuses(), IsEmpty()); |
| } |
| |
| TEST_P(ValidateIngredientComponentOfTest, WrongRelationshipIngredientV1) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(absl::StrFormat( |
| R"pb( |
| assertions { |
| actions { |
| actions { |
| action: "%s" |
| parameters { |
| ingredients { |
| url: "self#jumbf=c2pa.assertions/c2pa.ingredient.v3" |
| } |
| } |
| } |
| } |
| } |
| assertions { |
| label: "c2pa.ingredient.v3" |
| ingredient_v3 { relationship: "parentOf" } |
| } |
| )pb", |
| GetParam().action_name)); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT( |
| tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionIngredientMismatch)); |
| } |
| |
| TEST_P(ValidateIngredientComponentOfTest, WrongRelationshipIngredientV2) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(absl::StrFormat( |
| R"pb( |
| assertions { |
| actions { |
| actions { |
| action: "%s" |
| parameters { |
| ingredients { |
| url: "self#jumbf=c2pa.assertions/c2pa.ingredient.v3" |
| } |
| } |
| } |
| } |
| } |
| assertions { |
| label: "c2pa.ingredient.v3" |
| ingredient_v3 { relationship: "parentOf" } |
| } |
| )pb", |
| GetParam().action_name)); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT( |
| tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionIngredientMismatch)); |
| } |
| |
| TEST_P(ValidateIngredientComponentOfTest, WrongRelationshipIngredientV3) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(absl::StrFormat( |
| R"pb( |
| assertions { |
| actions { |
| actions { |
| action: "%s" |
| parameters { |
| ingredients { |
| url: "self#jumbf=c2pa.assertions/c2pa.ingredient.v3" |
| } |
| } |
| } |
| } |
| } |
| assertions { |
| label: "c2pa.ingredient.v3" |
| ingredient_v3 { relationship: "parentOf" } |
| } |
| )pb", |
| GetParam().action_name)); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT( |
| tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionIngredientMismatch)); |
| } |
| constexpr ActionParam kComponentOfActionParams[] = { |
| {.action_name = "c2pa.placed"}, |
| {.action_name = "c2pa.removed"}, |
| }; |
| INSTANTIATE_TEST_SUITE_P(ActionsAssertionValidatorTest, |
| ValidateIngredientComponentOfTest, |
| ValuesIn(kComponentOfActionParams)); |
| |
| TEST(ActionsAssertionValidatorTest, ValidateRedactedActionMissingRedactedUri) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(R"pb( |
| assertions { |
| actions { |
| actions { |
| action: "c2pa.redacted" |
| parameters {} |
| } |
| } |
| } |
| )pb"); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT( |
| tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionRedactionMismatch)); |
| } |
| |
| TEST(ActionsAssertionValidatorTest, |
| ValidateRedactedActionMissingRedactedAssertion) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(R"pb( |
| assertions { |
| actions { |
| actions { |
| action: "c2pa.redacted" |
| parameters { |
| redacted_uri: "self#jumbf=c2pa.assertions/c2pa.ingredient.v3" |
| } |
| } |
| } |
| } |
| )pb"); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT( |
| tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionRedactionMismatch)); |
| } |
| |
| TEST(ActionsAssertionValidatorTest, ValidateRedactedActionOkay) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(R"pb( |
| assertions { |
| actions { |
| actions { |
| action: "c2pa.redacted" |
| parameters { |
| redacted_uri: "self#jumbf=c2pa.assertions/c2pa.ingredient.v3" |
| } |
| } |
| } |
| } |
| assertions { |
| label: "c2pa.ingredient.v3" |
| ingredient_v3 {} |
| } |
| )pb"); |
| EXPECT_TRUE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT(tracker.GetFailureStatuses(), IsEmpty()); |
| } |
| |
| TEST(ActionsAssertionValidatorTest, ValidCreatedAssertions) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(R"pb( |
| claim { |
| created_assertions { url: "self#jumbf=c2pa.assertions/c2pa.actions.v2" } |
| created_assertions { |
| url: "self#jumbf=c2pa.assertions/c2pa.actions.v2__1" |
| } |
| } |
| assertions { |
| label: "c2pa.actions.v2" |
| actions { actions { action: "c2pa.created" } } |
| } |
| assertions { |
| label: "c2pa.actions.v2__1" |
| actions { actions { action: "c2pa.resized" } } |
| } |
| )pb"); |
| EXPECT_TRUE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT(tracker.GetFailures(), IsEmpty()); |
| } |
| |
| TEST(ActionsAssertionValidatorTest, ValidOpenedAssertions) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(R"pb( |
| claim { |
| created_assertions { url: "self#jumbf=c2pa.assertions/c2pa.actions.v2" } |
| created_assertions { |
| url: "self#jumbf=c2pa.assertions/c2pa.actions.v2__1" |
| } |
| } |
| assertions { |
| label: "c2pa.actions.v2" |
| actions { |
| actions { |
| action: "c2pa.opened" |
| parameters { |
| ingredients { url: "self#jumbf=c2pa.assertions/c2pa.ingredient.v3" } |
| } |
| } |
| } |
| } |
| assertions { |
| label: "c2pa.actions.v2__1" |
| actions { actions { action: "c2pa.resized" } } |
| } |
| assertions { |
| label: "c2pa.ingredient.v3" |
| ingredient_v3 { |
| relationship: "parentOf", |
| active_manifest {} |
| } |
| } |
| )pb"); |
| EXPECT_TRUE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT(tracker.GetFailures(), IsEmpty()); |
| } |
| |
| TEST(ActionsAssertionValidatorTest, MalformedFirstAssertion) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(R"pb( |
| claim { |
| created_assertions { url: "self#jumbf=c2pa.assertions/c2pa.actions.v2" } |
| } |
| assertions { |
| label: "c2pa.actions.v2" |
| actions { actions { action: "c2pa.resized" } } |
| } |
| )pb"); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT(tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionMalformed)); |
| } |
| |
| TEST(ActionsAssertionValidatorTest, MalformedCreatedAssertions) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(R"pb( |
| claim { |
| created_assertions { url: "self#jumbf=c2pa.assertions/c2pa.actions" } |
| created_assertions { url: "self#jumbf=c2pa.assertions/c2pa.actions.v2" } |
| } |
| assertions { |
| label: "c2pa.actions" |
| actions_v1 { actions { action: "c2pa.resized" } } |
| } |
| assertions { |
| label: "c2pa.actions.v2" |
| actions { actions { action: "c2pa.created" } } |
| } |
| )pb"); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT(tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionMalformed)); |
| } |
| |
| TEST(ActionsAssertionValidatorTest, MalformedOpenedAssertions) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(R"pb( |
| claim { |
| created_assertions { url: "self#jumbf=c2pa.assertions/c2pa.actions" } |
| created_assertions { url: "self#jumbf=c2pa.assertions/c2pa.actions.v2" } |
| } |
| assertions { |
| label: "c2pa.actions.v2" |
| actions_v1 { actions { action: "c2pa.resized" } } |
| } |
| assertions { |
| label: "c2pa.actions" |
| actions { actions { action: "c2pa.opened" } } |
| } |
| )pb"); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT(tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionMalformed)); |
| } |
| |
| TEST(ActionsAssertionValidatorTest, MalformedDuplicatedCreatedAssertion) { |
| TestValidationTracker tracker; |
| ActionsAssertionValidator validator; |
| auto manifest = ParseTextProtoOrDie<Manifest>(R"pb( |
| claim { |
| created_assertions { url: "self#jumbf=c2pa.assertions/c2pa.actions" } |
| created_assertions { url: "self#jumbf=c2pa.assertions/c2pa.actions.v2" } |
| } |
| assertions { |
| label: "c2pa.actions.v2" |
| actions_v1 { actions { action: "c2pa.created" } } |
| } |
| assertions { |
| label: "c2pa.actions" |
| actions { actions { action: "c2pa.created" } } |
| } |
| )pb"); |
| EXPECT_FALSE(validator.Validate(manifest, tracker.tracker())); |
| EXPECT_THAT(tracker.GetFailures(), |
| ContainsFailure(FailureStatusCode::kAssertionActionMalformed)); |
| } |
| |
| } // namespace |
| } // namespace credentio |