Blame SOURCES/scap-security-guide-0.1.53-ansible_platforms-PR_6025.patch

fe0dde
From 844be904d8de624abe9bbe620d7a06417dfff842 Mon Sep 17 00:00:00 2001
fe0dde
From: Watson Sato <wsato@redhat.com>
fe0dde
Date: Thu, 27 Aug 2020 13:19:01 +0200
fe0dde
Subject: [PATCH 1/5] Align Ansible task applicability with CPE platform
fe0dde
fe0dde
Adds a when clause to Ansible snippets of rules with Package CPE platform.
fe0dde
fe0dde
If the when clause is added, a fact_packages Task needs to added as
fe0dde
well.
fe0dde
---
fe0dde
 ssg/build_remediations.py | 52 ++++++++++++++++++++++++++++++++++++---
fe0dde
 1 file changed, 49 insertions(+), 3 deletions(-)
fe0dde
fe0dde
diff --git a/ssg/build_remediations.py b/ssg/build_remediations.py
fe0dde
index a9ef3014ac..597aed5889 100644
fe0dde
--- a/ssg/build_remediations.py
fe0dde
+++ b/ssg/build_remediations.py
fe0dde
@@ -6,8 +6,7 @@
fe0dde
 import os.path
fe0dde
 import re
fe0dde
 import codecs
fe0dde
-from collections import defaultdict, namedtuple
fe0dde
-
fe0dde
+from collections import defaultdict, namedtuple, OrderedDict
fe0dde
 
fe0dde
 import ssg.yaml
fe0dde
 from . import build_yaml
fe0dde
@@ -343,10 +342,46 @@ def _get_rule_reference(self, ref_class):
fe0dde
         else:
fe0dde
             return []
fe0dde
 
fe0dde
+    def inject_package_facts_task(self, parsed_snippet):
fe0dde
+        """ Injects a package_facts task only if
fe0dde
+            the snippet has a task with a when clause with ansible_facts.packages,
fe0dde
+            and the snippet doesn't already have an package_facts task
fe0dde
+        """
fe0dde
+        has_package_facts_task = False
fe0dde
+        has_ansible_facts_packages_clause = False
fe0dde
+
fe0dde
+        for p_task in parsed_snippet:
fe0dde
+            # We are only interested in the OrderedDicts, which represent Ansible tasks
fe0dde
+            if not isinstance(p_task, dict):
fe0dde
+                continue
fe0dde
+
fe0dde
+            if "package_facts" in p_task:
fe0dde
+                has_package_facts_task = True
fe0dde
+
fe0dde
+            if "ansible_facts.packages" in p_task.get("when", ""):
fe0dde
+                has_ansible_facts_packages_clause = True
fe0dde
+
fe0dde
+        if has_ansible_facts_packages_clause and not has_package_facts_task:
fe0dde
+            facts_task = OrderedDict({'name': 'Gather the package facts',
fe0dde
+                                      'package_facts': {'manager': 'auto'}})
fe0dde
+            parsed_snippet.insert(0, facts_task)
fe0dde
+
fe0dde
     def update_when_from_rule(self, to_update):
fe0dde
         additional_when = ""
fe0dde
-        if self.associated_rule.platform == "machine":
fe0dde
+        rule_platform = self.associated_rule.platform
fe0dde
+        if rule_platform == "machine":
fe0dde
             additional_when = 'ansible_virtualization_type not in ["docker", "lxc", "openvz"]'
fe0dde
+        elif rule_platform is not None:
fe0dde
+            # Assume any other platform is a Package CPE
fe0dde
+
fe0dde
+            # It doesn't make sense to add a conditional on the task that
fe0dde
+            # gathers data for the conditional
fe0dde
+            if "package_facts" in to_update:
fe0dde
+                return
fe0dde
+
fe0dde
+            additional_when = '"' + rule_platform + '" in ansible_facts.packages'
fe0dde
+            # After adding the conditional, we need to make sure package_facts are collected.
fe0dde
+            # This is done via inject_package_facts_task()
fe0dde
         to_update.setdefault("when", "")
fe0dde
         new_when = ssg.yaml.update_yaml_list_or_string(to_update["when"], additional_when)
fe0dde
         if not new_when:
fe0dde
@@ -355,10 +390,21 @@ def update_when_from_rule(self, to_update):
fe0dde
             to_update["when"] = new_when
fe0dde
 
fe0dde
     def update(self, parsed, config):
fe0dde
+        # We split the remediation update in three steps
fe0dde
+
fe0dde
+        # 1. Update the when clause
fe0dde
         for p in parsed:
fe0dde
             if not isinstance(p, dict):
fe0dde
                 continue
fe0dde
             self.update_when_from_rule(p)
fe0dde
+
fe0dde
+        # 2. Inject any extra task necessary
fe0dde
+        self.inject_package_facts_task(parsed)
fe0dde
+
fe0dde
+        # 3. Add tags to all tasks, including the ones we have injected
fe0dde
+        for p in parsed:
fe0dde
+            if not isinstance(p, dict):
fe0dde
+                continue
fe0dde
             self.update_tags_from_config(p, config)
fe0dde
             self.update_tags_from_rule(p)
fe0dde
 
fe0dde
fe0dde
From 60e5723e0e35ec8d79bafdd113f04691e61738e7 Mon Sep 17 00:00:00 2001
fe0dde
From: Watson Sato <wsato@redhat.com>
fe0dde
Date: Thu, 27 Aug 2020 17:09:06 +0200
fe0dde
Subject: [PATCH 2/5] Add inherited_platform to Rule
fe0dde
fe0dde
This field is exported to the rule when it is resolved.
fe0dde
---
fe0dde
 ssg/build_yaml.py | 5 +++++
fe0dde
 1 file changed, 5 insertions(+)
fe0dde
fe0dde
diff --git a/ssg/build_yaml.py b/ssg/build_yaml.py
fe0dde
index 4ba114eee4..fe290ffc05 100644
fe0dde
--- a/ssg/build_yaml.py
fe0dde
+++ b/ssg/build_yaml.py
fe0dde
@@ -832,6 +832,7 @@ class Rule(object):
fe0dde
         "conflicts": lambda: list(),
fe0dde
         "requires": lambda: list(),
fe0dde
         "platform": lambda: None,
fe0dde
+        "inherited_platforms": lambda: list(),
fe0dde
         "template": lambda: None,
fe0dde
     }
fe0dde
 
fe0dde
@@ -851,6 +852,7 @@ def __init__(self, id_):
fe0dde
         self.requires = []
fe0dde
         self.conflicts = []
fe0dde
         self.platform = None
fe0dde
+        self.inherited_platforms = [] # platforms inherited from the group
fe0dde
         self.template = None
fe0dde
 
fe0dde
     @classmethod
fe0dde
@@ -1293,6 +1295,9 @@ def _process_rules(self):
fe0dde
                 continue
fe0dde
             self.all_rules.add(rule)
fe0dde
             self.loaded_group.add_rule(rule)
fe0dde
+
fe0dde
+            rule.inherited_platforms.append(self.loaded_group.platform)
fe0dde
+
fe0dde
             if self.resolved_rules_dir:
fe0dde
                 output_for_rule = os.path.join(
fe0dde
                     self.resolved_rules_dir, "{id_}.yml".format(id_=rule.id_))
fe0dde
fe0dde
From 3a0bb0d2981670e90a8eaca53b28e1a6f7cc29d6 Mon Sep 17 00:00:00 2001
fe0dde
From: Watson Sato <wsato@redhat.com>
fe0dde
Date: Thu, 27 Aug 2020 17:21:35 +0200
fe0dde
Subject: [PATCH 3/5] Add when clauses for inherited platforms too
fe0dde
fe0dde
Consider the Rule's Group platform while including 'when' clauses to
fe0dde
Ansible snippets.
fe0dde
fe0dde
Some rules have two platforms, a machine platform and a package
fe0dde
platform. One of them is represented of the Rule, and the other is
fe0dde
represented in the Rule's Group.
fe0dde
fe0dde
The platforms are organized like this to due limiation in XCCDF,
fe0dde
multiple platforms in a Rule are ORed, not ANDed.
fe0dde
---
fe0dde
 ssg/build_remediations.py | 44 ++++++++++++++++++++++++---------------
fe0dde
 1 file changed, 27 insertions(+), 17 deletions(-)
fe0dde
fe0dde
diff --git a/ssg/build_remediations.py b/ssg/build_remediations.py
fe0dde
index 597aed5889..a2a996d0af 100644
fe0dde
--- a/ssg/build_remediations.py
fe0dde
+++ b/ssg/build_remediations.py
fe0dde
@@ -358,8 +358,13 @@ def inject_package_facts_task(self, parsed_snippet):
fe0dde
             if "package_facts" in p_task:
fe0dde
                 has_package_facts_task = True
fe0dde
 
fe0dde
-            if "ansible_facts.packages" in p_task.get("when", ""):
fe0dde
-                has_ansible_facts_packages_clause = True
fe0dde
+            # When clause of the task can be string or a list, lets normalize to list
fe0dde
+            task_when = p_task.get("when", "")
fe0dde
+            if type(task_when) is str:
fe0dde
+                task_when = [ task_when ]
fe0dde
+            for when in task_when:
fe0dde
+                if "ansible_facts.packages" in when:
fe0dde
+                    has_ansible_facts_packages_clause = True
fe0dde
 
fe0dde
         if has_ansible_facts_packages_clause and not has_package_facts_task:
fe0dde
             facts_task = OrderedDict({'name': 'Gather the package facts',
fe0dde
@@ -367,21 +372,26 @@ def inject_package_facts_task(self, parsed_snippet):
fe0dde
             parsed_snippet.insert(0, facts_task)
fe0dde
 
fe0dde
     def update_when_from_rule(self, to_update):
fe0dde
-        additional_when = ""
fe0dde
-        rule_platform = self.associated_rule.platform
fe0dde
-        if rule_platform == "machine":
fe0dde
-            additional_when = 'ansible_virtualization_type not in ["docker", "lxc", "openvz"]'
fe0dde
-        elif rule_platform is not None:
fe0dde
-            # Assume any other platform is a Package CPE
fe0dde
-
fe0dde
-            # It doesn't make sense to add a conditional on the task that
fe0dde
-            # gathers data for the conditional
fe0dde
-            if "package_facts" in to_update:
fe0dde
-                return
fe0dde
-
fe0dde
-            additional_when = '"' + rule_platform + '" in ansible_facts.packages'
fe0dde
-            # After adding the conditional, we need to make sure package_facts are collected.
fe0dde
-            # This is done via inject_package_facts_task()
fe0dde
+        additional_when = []
fe0dde
+
fe0dde
+        rule_platforms = set([self.associated_rule.platform] +
fe0dde
+                              self.associated_rule.inherited_platforms)
fe0dde
+
fe0dde
+        for platform in rule_platforms:
fe0dde
+            if platform == "machine":
fe0dde
+                additional_when.append('ansible_virtualization_type not in ["docker", "lxc", "openvz"]')
fe0dde
+            elif platform is not None:
fe0dde
+                # Assume any other platform is a Package CPE
fe0dde
+
fe0dde
+                # It doesn't make sense to add a conditional on the task that
fe0dde
+                # gathers data for the conditional
fe0dde
+                if "package_facts" in to_update:
fe0dde
+                    continue
fe0dde
+
fe0dde
+                additional_when.append('"' + platform + '" in ansible_facts.packages')
fe0dde
+                # After adding the conditional, we need to make sure package_facts are collected.
fe0dde
+                # This is done via inject_package_facts_task()
fe0dde
+
fe0dde
         to_update.setdefault("when", "")
fe0dde
         new_when = ssg.yaml.update_yaml_list_or_string(to_update["when"], additional_when)
fe0dde
         if not new_when:
fe0dde
fe0dde
From 99c92e39bccc3fcfadca41096e66ca146137b207 Mon Sep 17 00:00:00 2001
fe0dde
From: Watson Sato <wsato@redhat.com>
fe0dde
Date: Mon, 31 Aug 2020 16:06:14 +0200
fe0dde
Subject: [PATCH 4/5] Improve inherihted and rule's platforms handling
fe0dde
fe0dde
Add a quick comment too.
fe0dde
---
fe0dde
 ssg/build_remediations.py | 5 +++--
fe0dde
 1 file changed, 3 insertions(+), 2 deletions(-)
fe0dde
fe0dde
diff --git a/ssg/build_remediations.py b/ssg/build_remediations.py
fe0dde
index a2a996d0af..9e622ef740 100644
fe0dde
--- a/ssg/build_remediations.py
fe0dde
+++ b/ssg/build_remediations.py
fe0dde
@@ -374,8 +374,9 @@ def inject_package_facts_task(self, parsed_snippet):
fe0dde
     def update_when_from_rule(self, to_update):
fe0dde
         additional_when = []
fe0dde
 
fe0dde
-        rule_platforms = set([self.associated_rule.platform] +
fe0dde
-                              self.associated_rule.inherited_platforms)
fe0dde
+        # There can be repeated inherited platforms and rule platforms
fe0dde
+        rule_platforms = set(self.associated_rule.inherited_platforms)
fe0dde
+        rule_platforms.add(self.associated_rule.platform)
fe0dde
 
fe0dde
         for platform in rule_platforms:
fe0dde
             if platform == "machine":
fe0dde
fe0dde
From 596da9993edfbd244cbaa6d797abbd68b2e82185 Mon Sep 17 00:00:00 2001
fe0dde
From: Watson Sato <wsato@redhat.com>
fe0dde
Date: Mon, 31 Aug 2020 16:10:53 +0200
fe0dde
Subject: [PATCH 5/5] Code style and grammar changes
fe0dde
fe0dde
---
fe0dde
 ssg/build_remediations.py | 4 ++--
fe0dde
 1 file changed, 2 insertions(+), 2 deletions(-)
fe0dde
fe0dde
diff --git a/ssg/build_remediations.py b/ssg/build_remediations.py
fe0dde
index 9e622ef740..866450dd8c 100644
fe0dde
--- a/ssg/build_remediations.py
fe0dde
+++ b/ssg/build_remediations.py
fe0dde
@@ -345,7 +345,7 @@ def _get_rule_reference(self, ref_class):
fe0dde
     def inject_package_facts_task(self, parsed_snippet):
fe0dde
         """ Injects a package_facts task only if
fe0dde
             the snippet has a task with a when clause with ansible_facts.packages,
fe0dde
-            and the snippet doesn't already have an package_facts task
fe0dde
+            and the snippet doesn't already have a package_facts task
fe0dde
         """
fe0dde
         has_package_facts_task = False
fe0dde
         has_ansible_facts_packages_clause = False
fe0dde
@@ -361,7 +361,7 @@ def inject_package_facts_task(self, parsed_snippet):
fe0dde
             # When clause of the task can be string or a list, lets normalize to list
fe0dde
             task_when = p_task.get("when", "")
fe0dde
             if type(task_when) is str:
fe0dde
-                task_when = [ task_when ]
fe0dde
+                task_when = [task_when]
fe0dde
             for when in task_when:
fe0dde
                 if "ansible_facts.packages" in when:
fe0dde
                     has_ansible_facts_packages_clause = True