def test_9_external_config_update(self): # Start an extension without a daemon, with a timeout. extension = self._run_extension(timeout=EXTENSION_TIMEOUT) self.assertTrue(extension.isAlive()) # Now start a daemon daemon = self._run_daemon({ "disable_watchdog": True, "extensions_timeout": EXTENSION_TIMEOUT, "extensions_socket": extension.options["extensions_socket"], }) self.assertTrue(daemon.isAlive()) # Get a python-based thrift client to the manager and extension. client = test_base.EXClient(extension.options["extensions_socket"]) test_base.expectTrue(client.open) self.assertTrue(client.open(timeout=EXTENSION_TIMEOUT)) em = client.getEM() # Need the manager to request the extension's UUID. result = test_base.expect(em.extensions, 1) self.assertTrue(result is not None) ex_uuid = result.keys()[0] client2 = test_base.EXClient(extension.options["extensions_socket"], uuid=ex_uuid) test_base.expectTrue(client2.open) self.assertTrue(client2.open(timeout=EXTENSION_TIMEOUT)) ex = client2.getEX() # Trigger an async update from the extension. request = { "action": "update", "source": "test", "data": "{\"options\": {\"config_plugin\": \"update_test\"}}" } ex.call("config", "example", request) # The update call in the extension should filter to the core. options = em.options() self.assertTrue("config_plugin" in options.keys()) self.assertTrue(options["config_plugin"], "update_test") # Cleanup thrift connections and subprocesses. client2.close() client.close() extension.kill() daemon.kill()
def test_2_daemon_api(self): daemon = self._run_daemon({"disable_watchdog": True}) self.assertTrue(daemon.isAlive()) # Get a python-based thrift client client = test_base.EXClient(daemon.options["extensions_socket"]) self.assertTrue(client.open(timeout=EXTENSION_TIMEOUT)) em = client.getEM() # List the number of extensions print(em.ping()) result = test_base.expect(em.extensions, 0) self.assertEqual(len(result), 0) # Try the basic ping API self.assertEqual(em.ping().code, 0) # Try a query response = em.query("select * from time") self.assertEqual(response.status.code, 0) self.assertEqual(len(response.response), 1) self.assertTrue("seconds" in response.response[0].keys()) # Try to get the query columns response = em.getQueryColumns("select seconds as s from time") self.assertEqual(response.status.code, 0) self.assertEqual(len(response.response), 1) self.assertTrue("s" in response.response[0]) client.close() daemon.kill()
def test_5_extension_timeout(self): # Start an extension without a daemon, with a timeout. extension = self._run_extension(timeout=EXTENSION_TIMEOUT) self.assertTrue(extension.isAlive()) # Now start a daemon daemon = self._run_daemon({ "disable_watchdog": True, "extensions_socket": extension.options["extensions_socket"], "verbose": True, }) self.assertTrue(daemon.isAlive()) # Get a python-based thrift client client = test_base.EXClient(extension.options["extensions_socket"]) self.assertTrue(client.open(timeout=EXTENSION_TIMEOUT)) em = client.getEM() # The waiting extension should have connected to the daemon. result = test_base.expect(em.extensions, 1) self.assertEqual(len(result), 1) client.close() daemon.kill(True) extension.kill()
def test_91_extensions_settings(self): loader = test_base.Autoloader( [test_base.ARGS.build + "/osquery/example_extension.ext"]) daemon = self._run_daemon({ "disable_watchdog": True, "extensions_timeout": EXTENSION_TIMEOUT, "extensions_autoload": loader.path, }) self.assertTrue(daemon.isAlive()) # Get a python-based thrift client for the manager (core). client = test_base.EXClient(daemon.options["extensions_socket"]) self.assertTrue(client.open(timeout=EXTENSION_TIMEOUT)) em = client.getEM() # The waiting extension should have connected to the daemon. # This expect statement will block with a short timeout. result = test_base.expect(em.extensions, 1) self.assertEqual(len(result), 1) # The 'complex_example' table reports several columns. # Each is a 'test_type', check each expected value. result = em.query("select * from complex_example") if len(result.response) == 0: # There is a brief race between register and registry broadcast # That fast external client fight when querying tables. # Other config/logger plugins have wrappers to retry/wait. time.sleep(0.5) result = em.query("select * from complex_example") self.assertEqual(result.response[0]['flag_test'], 'false') self.assertEqual(result.response[0]['database_test'], '1') client.close() daemon.kill(True)
def test_10_extensions_settings(self): loader = test_base.Autoloader( [test_base.ARGS.build + "/osquery/example_extension.ext"]) daemon = self._run_daemon({ "disable_watchdog": True, "extensions_timeout": EXTENSION_TIMEOUT, "extensions_autoload": loader.path, }) self.assertTrue(daemon.isAlive()) # Get a python-based thrift client for the manager (core). client = test_base.EXClient(daemon.options["extensions_socket"]) self.assertTrue(client.open(timeout=EXTENSION_TIMEOUT)) em = client.getEM() # The waiting extension should have connected to the daemon. # This expect statement will block with a short timeout. result = test_base.expect(em.extensions, 1) self.assertEqual(len(result), 1) # The 'complex_example' table reports several columns. # Each is a 'test_type', check each expected value. result = em.query("select * from complex_example") self.assertEqual(result.response[0]['flag_test'], 'false') self.assertEqual(result.response[0]['database_test'], '1') client.close() daemon.kill(True)
def test_query_packs(self): query_pack_path = test_base.CONFIG_DIR + "/test_pack.conf" utils.write_config( { "queries": { "simple_test": { "query": "select * from time", "interval": 60, }, "simple_test2": { "query": "select * from time", "interval": 60, "platform": "does_not_exist", } } }, path=query_pack_path) # Get a daemon process, loaded with the default test configuration. # We'll add a config override (overwrite) for the "packs" key. # THis will point a single pack at the config written above. daemon = self._run_daemon({ "disable_watchdog": True, }, overwrite={ "packs": { "test_pack": query_pack_path }, }) self.assertTrue(daemon.isAlive()) # Introspect into the daemon's query packs. client = test_base.EXClient(daemon.options["extensions_socket"]) test_base.expectTrue(client.try_open) self.assertTrue(client.open()) em = client.getEM() # Every query from the pack(s) is added to the packs table. def get_packs(): result = em.query("select * from osquery_packs") return len(result.response) == 2 # Allow the daemon some lag to parse the pack content. test_base.expectTrue(get_packs) result = em.query("select * from osquery_packs") self.assertEqual(len(result.response), 2) # Only the applicable queries are added to the schedule. # There will be len(pack_queries) - 1 since "simple_test2" is bound # to an unknown/non-existing platform. result = em.query("select * from osquery_schedule") self.assertEqual(len(result.response), 1) daemon.kill()
def setUp(self): self.daemon = self._run_daemon({ # The set of queries will hammer the daemon process. "disable_watchdog": True, }) self.assertTrue(self.daemon.isAlive()) # The sets of example tests will use the extensions API.s self.client = test_base.EXClient(self.daemon.options["extensions_socket"]) test_base.expectTrue(self.client.open) self.assertTrue(self.client.open()) self.em = self.client.getEM()
def test_4_extension_dies(self): daemon = self._run_daemon({ "disable_watchdog": True, "extensions_interval": "0", "verbose": True, }) self.assertTrue(daemon.isAlive()) # Get a python-based thrift client client = test_base.EXClient(daemon.options["extensions_socket"]) self.assertTrue(client.open(timeout=EXTENSION_TIMEOUT)) em = client.getEM() # Make sure there are no extensions registered result = test_base.expect(em.extensions, 0) self.assertEqual(len(result), 0) # Make sure the extension process starts extension = self._run_extension( path=daemon.options["extensions_socket"], timeout=EXTENSION_TIMEOUT) self.assertTrue(extension.isAlive()) # Now that an extension has started, check extension list result = test_base.expect(em.extensions, 1) self.assertEqual(len(result), 1) # Kill the extension extension.kill() # Make sure the daemon detects the change result = test_base.expect(em.extensions, 0, timeout=EXTENSION_TIMEOUT) self.assertEqual(len(result), 0) # Make sure the extension restarts extension = self._run_extension( path=daemon.options["extensions_socket"], timeout=EXTENSION_TIMEOUT, ) self.assertTrue(extension.isAlive()) # With the reset there should be 1 extension again result = test_base.expect(em.extensions, 1) self.assertEqual(len(result), 1) print(em.query("select * from example")) # Now tear down the daemon client.close() daemon.kill() # The extension should tear down as well self.assertTrue(extension.isDead(extension.pid))
def test_1_daemon_without_extensions(self): # Start the daemon without thrift, prefer no watchdog because the tests # kill the daemon very quickly. daemon = self._run_daemon({ "disable_watchdog": True, "disable_extensions": True, }) self.assertTrue(daemon.isAlive()) # Now try to connect to the disabled API client = test_base.EXClient(daemon.options["extensions_socket"]) self.assertFalse(client.open()) daemon.kill()
def test_7_extensions_autoload_watchdog(self): loader = test_base.Autoloader( [test_base.ARGS.build + "/osquery/example_extension.ext"]) daemon = self._run_daemon({ "extensions_timeout": EXTENSION_TIMEOUT, "extensions_autoload": loader.path, }) self.assertTrue(daemon.isAlive()) # Get a python-based thrift client client = test_base.EXClient(daemon.options["extensions_socket"]) self.assertTrue(client.open(timeout=EXTENSION_TIMEOUT)) em = client.getEM() # The waiting extension should have connected to the daemon. result = test_base.expect(em.extensions, 1) self.assertEqual(len(result), 1) client.close() daemon.kill(True)
def test_8_external_config(self): loader = test_base.Autoloader( [test_base.ARGS.build + "/osquery/example_extension.ext"]) daemon = self._run_daemon({ "extensions_autoload": loader.path, "extensions_timeout": EXTENSION_TIMEOUT, "config_plugin": "example", "verbose": True, }) self.assertTrue(daemon.isAlive()) # Get a python-based thrift client client = test_base.EXClient(daemon.options["extensions_socket"]) self.assertTrue(client.open(timeout=EXTENSION_TIMEOUT)) em = client.getEM() # The waiting extension should have connected to the daemon. # If there are no extensions the daemon may have exited (in error). result = test_base.expect(em.extensions, 1) self.assertEqual(len(result), 1) client.close() daemon.kill(True)
def test_3_example_extension(self): daemon = self._run_daemon({"disable_watchdog": True}) self.assertTrue(daemon.isAlive()) # Get a python-based thrift client client = test_base.EXClient(daemon.options["extensions_socket"]) self.assertTrue(client.open(timeout=EXTENSION_TIMEOUT)) em = client.getEM() # Make sure there are no extensions registered result = test_base.expect(em.extensions, 0) self.assertEqual(len(result), 0) # Make sure the extension process starts extension = self._run_extension( path=daemon.options["extensions_socket"], timeout=EXTENSION_TIMEOUT, ) self.assertTrue(extension.isAlive()) # Now that an extension has started, check extension list result = test_base.expect(em.extensions, 1) self.assertEqual(len(result), 1) ex_uuid = result.keys()[0] ex_data = result[ex_uuid] self.assertEqual(ex_data.name, "example") self.assertEqual(ex_data.version, "0.0.1") self.assertEqual(ex_data.min_sdk_version, "0.0.0") # Get a python-based thrift client to the extension's service client2 = test_base.EXClient(daemon.options["extensions_socket"], uuid=ex_uuid) self.assertTrue(client2.open(timeout=EXTENSION_TIMEOUT)) ex = client2.getEX() self.assertEqual(ex.ping().code, 0) # Make sure the extension can receive a call em_time = em.call("table", "time", {"action": "columns"}) ex_time = ex.call("table", "time", {"action": "columns"}) print(em_time) print(ex_time) self.assertEqual(ex_time.status.code, 0) self.assertTrue(len(ex_time.response) > 0) self.assertTrue("name" in ex_time.response[0]) self.assertEqual(ex_time.status.uuid, ex_uuid) # Make sure the extension includes a custom registry plugin result = ex.call("table", "example", {"action": "generate"}) print(result) self.assertEqual(result.status.code, 0) self.assertEqual(len(result.response), 1) self.assertTrue("example_text" in result.response[0]) self.assertTrue("example_integer" in result.response[0]) self.assertEqual(result.response[0]["example_text"], "example") # Make sure the core can route to the extension result = em.call("table", "example", {"action": "generate"}) print(result) client2.close() client.close() extension.kill() daemon.kill()