From 18559e3799d321f7a97ca54362522db4d5be323d Mon Sep 17 00:00:00 2001 From: Lukas Puehringer Date: Wed, 24 Oct 2018 15:03:09 +0200 Subject: [PATCH] Update verify_*_rules docstrings Update code documentation for verifylib functions related to rule verification, to align with changes introduced by in-toto/in-toto#204. --- in_toto/verifylib.py | 130 +++++++++++++++++++++++++++++-------------- 1 file changed, 88 insertions(+), 42 deletions(-) diff --git a/in_toto/verifylib.py b/in_toto/verifylib.py index 640614ab4..8e05b1a8c 100644 --- a/in_toto/verifylib.py +++ b/in_toto/verifylib.py @@ -563,12 +563,25 @@ def verify_all_steps_command_alignment(layout, chain_link_dict): def verify_match_rule(rule, source_artifacts_queue, source_artifacts, links): """ - Verifies that for each queued source artifact filtered by the specified - source pattern there is a destination artifact filtered by the specified - destination pattern and they are equal in terms of path and file hash. + Verifies that for each queued source artifact, filtered by the specified + source pattern, there is a destination artifact, filtered by the specified + destination pattern, and they are equal in terms of path and file hash. This guarantees that artifacts were not modified between steps/inspections. + The rule only modifies the source artifacts queue, by removing artifacts + that were successfully consumed by the rule, i.e. if there was a match with + a target artifact. + + FIXME: + In in-toto/in-toto#204 the behavior of the match rule was changed to NOT + FAIL if a required destination artifact could not be found in the + corresponding destination link, or if a source and destination artifact + pair has no matching hashes. However, the rule verification still fails + if a required destination link is not found. + As failing the overall rule verification is now left to a subsequent + DISALLOW rule, the "fail on missing destination link" should be removed. + queued source artifacts: Artifacts reported by the link for the step/inspection containing passed @@ -641,16 +654,12 @@ def verify_match_rule(rule, source_artifacts_queue, source_artifacts, links): RuleVerificationError if the destination link is not found in the passed link dictionary. - if the corresponding destination artifact of a filtered source artifact - is not found. - if a hash of a source artifact and the hash of a corresponding target - artifact are not equal. None. - A list of artifacts that were matched by the rule. + A list of source artifacts that were not consumed by the rule. """ rule_data = in_toto.rulelib.unpack_rule(rule) @@ -658,6 +667,8 @@ def verify_match_rule(rule, source_artifacts_queue, source_artifacts, links): dest_type = rule_data["dest_type"] # Extract destination link + # FIXME: In alignment with in-toto/in-toto#204, we should return the + # unmodified source artifact queue instead of raising an exception. try: dest_link = links[dest_name] except KeyError: @@ -705,8 +716,8 @@ def verify_match_rule(rule, source_artifacts_queue, source_artifacts, links): else: full_source_path = path - # If a destination prefix was specified, the destionation artifact should - # be queried with the full destionation path, i.e. the prefix joined with + # If a destination prefix was specified, the destination artifact should + # be queried with the full destination path, i.e. the prefix joined with # the globbed path. if rule_data["dest_prefix"]: full_dest_path = os.path.join(rule_data["dest_prefix"], path) @@ -722,18 +733,20 @@ def verify_match_rule(rule, source_artifacts_queue, source_artifacts, links): try: dest_artifact = dest_artifacts[full_dest_path] - # If there is no such key (i.e., target path), we won't mark this file - # as matched + # If there is no destination artifact with the same path as the source + # artifact, we won't mark this artifact as matched, i.e. we leave it in the + # queue except KeyError: continue - # finally, if both paths exist, make sure they do in fact have the same - # hash + # Finally, if source and destination artifact exist, make sure they do in + # fact have the same hash. If not, we won't mark it as matched, i.e. we + # leave it in the queue if source_artifact != dest_artifact: continue - # Matching went well, let's remove the path from the queue. Subsequent - # rules won't see this artifact anymore. + # Only if matching went well, do we remove it from the queue. Subsequent + # rules (e.g. DISALLOW) won't see this artifact anymore. source_artifacts_queue.remove(full_source_path) return source_artifacts_queue @@ -742,8 +755,10 @@ def verify_match_rule(rule, source_artifacts_queue, source_artifacts, links): def verify_create_rule(rule, source_materials_queue, source_products_queue): """ - The create rule guarantees that no product filtered by the pattern, already - appears in the materials queue, i.e. that it was created in that step. + Verifies that no products matched by applying the rule pattern on the + product queue, are already in the material queue, i.e. that all matched + products were created in that step. If the rule finds an artifact to be + indeed created, it is taken from the products queue. The create rule always passes if the pattern does not match any products: @@ -771,9 +786,8 @@ def verify_create_rule(rule, source_materials_queue, source_products_queue): A list of product paths that were not matched by a previous rule. - RuleVerificationError - if a product filtered by the pattern also appears in the materials - queue. + FormatError + if the rule does not conform with the rule format. None. @@ -801,8 +815,16 @@ def verify_create_rule(rule, source_materials_queue, source_products_queue): def verify_delete_rule(rule, source_materials_queue, source_products_queue): """ - The delete rule guarantees that no material filtered by the pattern also - appears in the products queue, i.e. that it was deleted in that step. + Verifies that no materials matched by applying the rule pattern on the + material queue, are still in the product queue, i.e. that all matched + materials were deleted in that step. If the rule finds an artifact to be + indeed deleted, it is taken from the products queue, otherwise a + RuleVerificationError is raised. + + FIXME: Currently, the DELETE rule is the only other rule besides DISALLOW + that can fail the overall verification. Changing the DELETE rule to only + modify the queue and leave it up to a subsequent DISALLOW rule to fail the + overall verification probably should have been part of in-toto/in-toto#204. The delete rule always passes if the pattern does not match any materials: @@ -830,6 +852,8 @@ def verify_delete_rule(rule, source_materials_queue, source_products_queue): A list of product paths that were not matched by a previous rule. + FormatError + if the rule does not conform with the rule format. RuleVerificationError if a material filtered by the pattern also appears in the products queue. @@ -859,9 +883,14 @@ def verify_modify_rule(rule, source_materials_queue, source_products_queue, source_materials, source_products): """ - The modify rule guarantees that for each material filtered by the pattern - there is a product filtered by the pattern (and vice versa) and that their - hashes are not equal, i.e. the artifact was modified. + Verifies that artifacts matched by applying the rule pattern on the + product queue are already in the material queue and have different + hashes, i.e. were modified in that step. If the rule finds an artifact to + be indeed modified, it is taken from the products queue. + + TODO: + Rethink rule, it is unclear why it only modifies the products queue. + rule: @@ -883,16 +912,15 @@ def verify_modify_rule(rule, source_materials_queue, source_products_queue, as values. Format is: { : HASHDICT} - RuleVerificationError - if the materials and products matched by the pattern are not equal in - terms of paths. - if any material-product pair has the same hash (was not modified). + FormatError + if the rule does not conform with the rule format. None. - The updated materials and products queues (minus modified artifacts). + The updated materials and products queues (the latter minus modified + artifacts). """ rule_data = in_toto.rulelib.unpack_rule(rule) @@ -923,12 +951,8 @@ def verify_modify_rule(rule, source_materials_queue, source_products_queue, def verify_allow_rule(rule, source_artifacts_queue): """ - Authorizes the materials or products reported by a link metadata file - and filtered by the specified pattern. - - The allow rule verification will never fail, but it modifies the artifact - queue which affects the rest of the rules verification routine. See - `verify_item_rules`. + Authorizes an artifact in the corresponding queue, by removing any + artifacts filtered by the rule pattern from the queue. rule: @@ -960,8 +984,20 @@ def verify_allow_rule(rule, source_artifacts_queue): def verify_disallow_rule(rule, source_artifacts_queue): """ - Verifies that the specified pattern does not match any materials or - products. + Verifies that the specified pattern does not match any artifacts in the + passed artifacts queue and fails if it does. + + IMPORTANT NOTE: + All other artifact rules(**) only modify artifact queues, that is if any of + the other rules can be applied successfully, they remove the corresponding + artifact from the queue. + + In a reverse conclusion, a rule that can not be applied successfully, + leaves the artifact in the queue, and hence requires a subsequent + disallow rule (e.g. DISALLOW *) to fail the overall verification. + + + (**) (see `verify_delete_rule` for an exception) rule: @@ -972,8 +1008,10 @@ def verify_disallow_rule(rule, source_artifacts_queue): A list of artifact paths that were not matched by a previous rule. + FormatError + if the rule does not conform with any rule format. RuleVerificationError - if path pattern matches artifacts in artifact queue. + if the rule pattern matches artifacts in the artifact queue. None. @@ -1003,6 +1041,11 @@ def verify_item_rules(source_name, source_type, rules, links): type. If an artifact gets consumed by a rule it is removed from the queue, hence an artifact can only be consumed once. + Most rules only remove artifacts from the corresponding queues on success, + and leave the queue unchanged on failure. Hence, it is left to a subsequent + DISALLOW rule to fail overall verification, if any artifacts are left in + the queue that should have been consumed be preceding rules. + 1. Create materials queue and products queue, and a generic artifacts @@ -1036,9 +1079,12 @@ def verify_item_rules(source_name, source_type, rules, links): FormatError - if source_type is not "materials" or "products" + if source_type is not "materials" or "products", or + if a rule in the passed list of rules does not conform with any rule + format. RuleVerificationError - if the artifacts queue is not empty after all rules were applied + if a DISALLOW rule matches any artifacts in the corresponding artifact + queue. None.