prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  postfix integration should not require sudo to root
  Reading the source code to integrations-core/postfix/check.py I note that it does a sudo to root to run the find command.
  
  This is noted in the docs / comments :
  
  > WARNING: the user that dd-agent runs as must have sudo access for the 'find' command
  > --
  >   | sudo access is not required when running dd-agent as root (not recommended)
  >   |  
  >   | example /etc/sudoers entry:
  >   | dd-agent ALL=(ALL) NOPASSWD:/usr/bin/find /var/spool/postfix* -type f
  
  root should not be required here - postfix user should be sufficient. That would be combined with a '-u postfix' on line 64's sudo command to allow this to work.
  
  This is a concern because find has a -exec parameter and your command list has a wildcard in it - this could be used to run arbitrary commands as root if the dd-agent user is compromised.
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `postfix/check.py`
  Content:
  ```
  1 # (C) Datadog, Inc. 2013-2016
  2 # (C) Josiah C Webb <rootkix@gmail.com> 2013
  3 # All rights reserved
  4 # Licensed under Simplified BSD License (see LICENSE)
  5 
  6 # stdlib
  7 import os
  8 
  9 # project
  10 from checks import AgentCheck
  11 from utils.subprocess_output import get_subprocess_output
  12 
  13 class PostfixCheck(AgentCheck):
  14     """This check provides metrics on the number of messages in a given postfix queue
  15 
  16     WARNING: the user that dd-agent runs as must have sudo access for the 'find' command
  17              sudo access is not required when running dd-agent as root (not recommended)
  18 
  19     example /etc/sudoers entry:
  20              dd-agent ALL=(ALL) NOPASSWD:/usr/bin/find /var/spool/postfix* -type f
  21 
  22     YAML config options:
  23         "directory" - the value of 'postconf -h queue_directory'
  24         "queues" - the postfix mail queues you would like to get message count totals for
  25     """
  26     def check(self, instance):
  27         config = self._get_config(instance)
  28 
  29         directory = config['directory']
  30         queues = config['queues']
  31         tags = config['tags']
  32 
  33         self._get_queue_count(directory, queues, tags)
  34 
  35     def _get_config(self, instance):
  36         directory = instance.get('directory', None)
  37         queues = instance.get('queues', None)
  38         tags = instance.get('tags', [])
  39         if not queues or not directory:
  40             raise Exception('missing required yaml config entry')
  41 
  42         instance_config = {
  43             'directory': directory,
  44             'queues': queues,
  45             'tags': tags,
  46         }
  47 
  48         return instance_config
  49 
  50     def _get_queue_count(self, directory, queues, tags):
  51         for queue in queues:
  52             queue_path = os.path.join(directory, queue)
  53             if not os.path.exists(queue_path):
  54                 raise Exception('%s does not exist' % queue_path)
  55 
  56             count = 0
  57             if os.geteuid() == 0:
  58                 # dd-agent is running as root (not recommended)
  59                 count = sum(len(files) for root, dirs, files in os.walk(queue_path))
  60             else:
  61                 # can dd-agent user run sudo?
  62                 test_sudo = os.system('setsid sudo -l < /dev/null')
  63                 if test_sudo == 0:
  64                     output, _, _ = get_subprocess_output(['sudo', 'find', queue_path, '-type', 'f'], self.log, False)
  65                     count = len(output.splitlines())
  66                 else:
  67                     raise Exception('The dd-agent user does not have sudo access')
  68 
  69             # emit an individually tagged metric
  70             self.gauge('postfix.queue.size', count, tags=tags + ['queue:%s' % queue, 'instance:%s' % os.path.basename(directory)])
  71 
  72             # these can be retrieved in a single graph statement
  73             # for example:
  74             #     sum:postfix.queue.size{instance:postfix-2,queue:incoming,host:hostname.domain.tld}
  75
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/postfix/check.py b/postfix/check.py
  --- a/postfix/check.py
  +++ b/postfix/check.py
  @@ -17,7 +17,9 @@
                sudo access is not required when running dd-agent as root (not recommended)
   
       example /etc/sudoers entry:
  -             dd-agent ALL=(ALL) NOPASSWD:/usr/bin/find /var/spool/postfix* -type f
  +        dd-agent ALL=(postfix) NOPASSWD:/usr/bin/find /var/spool/postfix/incoming -type f
  +        dd-agent ALL=(postfix) NOPASSWD:/usr/bin/find /var/spool/postfix/active -type f
  +        dd-agent ALL=(postfix) NOPASSWD:/usr/bin/find /var/spool/postfix/deferred -type f
   
       YAML config options:
           "directory" - the value of 'postconf -h queue_directory'
  @@ -61,7 +63,9 @@
                   # can dd-agent user run sudo?
                   test_sudo = os.system('setsid sudo -l < /dev/null')
                   if test_sudo == 0:
  -                    output, _, _ = get_subprocess_output(['sudo', 'find', queue_path, '-type', 'f'], self.log, False)
  +                    # default to `root` for backward compatibility
  +                    postfix_user = self.init_config.get('postfix_user', 'root')
  +                    output, _, _ = get_subprocess_output(['sudo', '-u', postfix_user, 'find', queue_path, '-type', 'f'], self.log, False)
                       count = len(output.splitlines())
                   else:
                       raise Exception('The dd-agent user does not have sudo access')
  
verification_info: {"golden_diff": "diff --git a/postfix/check.py b/postfix/check.py\n--- a/postfix/check.py\n+++ b/postfix/check.py\n@@ -17,7 +17,9 @@\n              sudo access is not required when running dd-agent as root (not recommended)\n \n     example /etc/sudoers entry:\n-             dd-agent ALL=(ALL) NOPASSWD:/usr/bin/find /var/spool/postfix* -type f\n+        dd-agent ALL=(postfix) NOPASSWD:/usr/bin/find /var/spool/postfix/incoming -type f\n+        dd-agent ALL=(postfix) NOPASSWD:/usr/bin/find /var/spool/postfix/active -type f\n+        dd-agent ALL=(postfix) NOPASSWD:/usr/bin/find /var/spool/postfix/deferred -type f\n \n     YAML config options:\n         \"directory\" - the value of 'postconf -h queue_directory'\n@@ -61,7 +63,9 @@\n                 # can dd-agent user run sudo?\n                 test_sudo = os.system('setsid sudo -l < /dev/null')\n                 if test_sudo == 0:\n-                    output, _, _ = get_subprocess_output(['sudo', 'find', queue_path, '-type', 'f'], self.log, False)\n+                    # default to `root` for backward compatibility\n+                    postfix_user = self.init_config.get('postfix_user', 'root')\n+                    output, _, _ = get_subprocess_output(['sudo', '-u', postfix_user, 'find', queue_path, '-type', 'f'], self.log, False)\n                     count = len(output.splitlines())\n                 else:\n                     raise Exception('The dd-agent user does not have sudo access')\n", "issue": "postfix integration should not require sudo to root\nReading the source code to integrations-core/postfix/check.py I note that it does a sudo to root to run the find command.\r\n\r\nThis is noted in the docs / comments :\r\n\r\n> WARNING: the user that dd-agent runs as must have sudo access for the 'find' command\r\n> --\r\n> \u00a0 | sudo access is not required when running dd-agent as root (not recommended)\r\n> \u00a0 | \u00a0\r\n> \u00a0 | example /etc/sudoers entry:\r\n> \u00a0 | dd-agent ALL=(ALL) NOPASSWD:/usr/bin/find /var/spool/postfix* -type f\r\n\r\nroot should not be required here - postfix user should be sufficient. That would be combined with a '-u postfix' on line 64's sudo command to allow this to work.\r\n\r\nThis is a concern because find has a -exec parameter and your command list has a wildcard in it - this could be used to run arbitrary commands as root if the dd-agent user is compromised.\r\n\n", "before_files": [{"content": "# (C) Datadog, Inc. 2013-2016\n# (C) Josiah C Webb <rootkix@gmail.com> 2013\n# All rights reserved\n# Licensed under Simplified BSD License (see LICENSE)\n\n# stdlib\nimport os\n\n# project\nfrom checks import AgentCheck\nfrom utils.subprocess_output import get_subprocess_output\n\nclass PostfixCheck(AgentCheck):\n    \"\"\"This check provides metrics on the number of messages in a given postfix queue\n\n    WARNING: the user that dd-agent runs as must have sudo access for the 'find' command\n             sudo access is not required when running dd-agent as root (not recommended)\n\n    example /etc/sudoers entry:\n             dd-agent ALL=(ALL) NOPASSWD:/usr/bin/find /var/spool/postfix* -type f\n\n    YAML config options:\n        \"directory\" - the value of 'postconf -h queue_directory'\n        \"queues\" - the postfix mail queues you would like to get message count totals for\n    \"\"\"\n    def check(self, instance):\n        config = self._get_config(instance)\n\n        directory = config['directory']\n        queues = config['queues']\n        tags = config['tags']\n\n        self._get_queue_count(directory, queues, tags)\n\n    def _get_config(self, instance):\n        directory = instance.get('directory', None)\n        queues = instance.get('queues', None)\n        tags = instance.get('tags', [])\n        if not queues or not directory:\n            raise Exception('missing required yaml config entry')\n\n        instance_config = {\n            'directory': directory,\n            'queues': queues,\n            'tags': tags,\n        }\n\n        return instance_config\n\n    def _get_queue_count(self, directory, queues, tags):\n        for queue in queues:\n            queue_path = os.path.join(directory, queue)\n            if not os.path.exists(queue_path):\n                raise Exception('%s does not exist' % queue_path)\n\n            count = 0\n            if os.geteuid() == 0:\n                # dd-agent is running as root (not recommended)\n                count = sum(len(files) for root, dirs, files in os.walk(queue_path))\n            else:\n                # can dd-agent user run sudo?\n                test_sudo = os.system('setsid sudo -l < /dev/null')\n                if test_sudo == 0:\n                    output, _, _ = get_subprocess_output(['sudo', 'find', queue_path, '-type', 'f'], self.log, False)\n                    count = len(output.splitlines())\n                else:\n                    raise Exception('The dd-agent user does not have sudo access')\n\n            # emit an individually tagged metric\n            self.gauge('postfix.queue.size', count, tags=tags + ['queue:%s' % queue, 'instance:%s' % os.path.basename(directory)])\n\n            # these can be retrieved in a single graph statement\n            # for example:\n            #     sum:postfix.queue.size{instance:postfix-2,queue:incoming,host:hostname.domain.tld}\n", "path": "postfix/check.py"}], "after_files": [{"content": "# (C) Datadog, Inc. 2013-2016\n# (C) Josiah C Webb <rootkix@gmail.com> 2013\n# All rights reserved\n# Licensed under Simplified BSD License (see LICENSE)\n\n# stdlib\nimport os\n\n# project\nfrom checks import AgentCheck\nfrom utils.subprocess_output import get_subprocess_output\n\nclass PostfixCheck(AgentCheck):\n    \"\"\"This check provides metrics on the number of messages in a given postfix queue\n\n    WARNING: the user that dd-agent runs as must have sudo access for the 'find' command\n             sudo access is not required when running dd-agent as root (not recommended)\n\n    example /etc/sudoers entry:\n        dd-agent ALL=(postfix) NOPASSWD:/usr/bin/find /var/spool/postfix/incoming -type f\n        dd-agent ALL=(postfix) NOPASSWD:/usr/bin/find /var/spool/postfix/active -type f\n        dd-agent ALL=(postfix) NOPASSWD:/usr/bin/find /var/spool/postfix/deferred -type f\n\n    YAML config options:\n        \"directory\" - the value of 'postconf -h queue_directory'\n        \"queues\" - the postfix mail queues you would like to get message count totals for\n    \"\"\"\n    def check(self, instance):\n        config = self._get_config(instance)\n\n        directory = config['directory']\n        queues = config['queues']\n        tags = config['tags']\n\n        self._get_queue_count(directory, queues, tags)\n\n    def _get_config(self, instance):\n        directory = instance.get('directory', None)\n        queues = instance.get('queues', None)\n        tags = instance.get('tags', [])\n        if not queues or not directory:\n            raise Exception('missing required yaml config entry')\n\n        instance_config = {\n            'directory': directory,\n            'queues': queues,\n            'tags': tags,\n        }\n\n        return instance_config\n\n    def _get_queue_count(self, directory, queues, tags):\n        for queue in queues:\n            queue_path = os.path.join(directory, queue)\n            if not os.path.exists(queue_path):\n                raise Exception('%s does not exist' % queue_path)\n\n            count = 0\n            if os.geteuid() == 0:\n                # dd-agent is running as root (not recommended)\n                count = sum(len(files) for root, dirs, files in os.walk(queue_path))\n            else:\n                # can dd-agent user run sudo?\n                test_sudo = os.system('setsid sudo -l < /dev/null')\n                if test_sudo == 0:\n                    # default to `root` for backward compatibility\n                    postfix_user = self.init_config.get('postfix_user', 'root')\n                    output, _, _ = get_subprocess_output(['sudo', '-u', postfix_user, 'find', queue_path, '-type', 'f'], self.log, False)\n                    count = len(output.splitlines())\n                else:\n                    raise Exception('The dd-agent user does not have sudo access')\n\n            # emit an individually tagged metric\n            self.gauge('postfix.queue.size', count, tags=tags + ['queue:%s' % queue, 'instance:%s' % os.path.basename(directory)])\n\n            # these can be retrieved in a single graph statement\n            # for example:\n            #     sum:postfix.queue.size{instance:postfix-2,queue:incoming,host:hostname.domain.tld}\n", "path": "postfix/check.py"}]}