def test_file_not_found(self, monkeypatch): monkeypatch.setattr( "anchore_engine.utils.subprocess.Popen", lambda a, **kw: _raise(FileNotFoundError), ) with pytest.raises(CommandException) as error: run_check(["foobar", "-vvv"]) assert "unable to run command. Executable does not exist" in str(error) assert error.value.code == 1 assert error.value.cmd == "foobar -vvv"
def get_vulnerabilities_for_sbom_file(self, grype_sbom_file: str) -> json: """ Use grype to scan the provided sbom for vulnerabilites. """ # Get the read lock with self.read_lock_access(): # Get env variables to run the grype scan with env_variables = self._get_env_variables() # Format and run the command cmd = "{grype_sub_command} sbom:{sbom}".format( grype_sub_command=self.GRYPE_SUB_COMMAND, sbom=grype_sbom_file) logger.debug("Running grype with command: %s", cmd) stdout = None err = None try: stdout, _ = run_check(shlex.split(cmd), log_level="spew", env=env_variables) except CommandException as exc: logger.error( "Exception running command: %s, stderr: %s", cmd, exc.stderr, ) raise exc # Return the output as json return json.loads(stdout)
def get_vulnerabilities_for_sbom(self, grype_sbom: str) -> json: """ Use grype to scan the provided sbom for vulnerabilites. """ # Get the read lock with self.read_lock_access(): # Get env variables to run the grype scan with env_variables = self._get_env_variables() # Format and run the command. Grype supports piping in an sbom string cmd = "{}".format(self.GRYPE_SUB_COMMAND) logger.spew("Running grype with command: {} | {}".format( grype_sbom, self.GRYPE_SUB_COMMAND)) try: stdout, _ = run_check( shlex.split(cmd), input_data=grype_sbom, log_level="spew", env=env_variables, ) except CommandException as exc: logger.error( "Exception running command: %s, stderr: %s", cmd, exc.stderr, ) raise exc # Return the output as json return json.loads(stdout)
def get_grype_version(self) -> json: """ Return version information for grype """ with self.read_lock_access(): env_variables = self._get_env_variables(include_grype_db=False) logger.debug("Getting grype version with command: %s", self.GRYPE_VERSION_COMMAND) stdout = None err = None try: stdout, _ = run_check(shlex.split(self.GRYPE_VERSION_COMMAND), env=env_variables) except CommandException as exc: logger.error( "Exception running command: %s, stderr: %s", self.GRYPE_VERSION_COMMAND, exc.stderr, ) raise exc # Return the output as json return json.loads(stdout)
def test_capture_bytes_std(self, monkeypatch): monkeypatch.setattr( "anchore_engine.utils.subprocess.Popen", FakePopen(0, b"stdout\nline", b"stderr\nline"), ) stdout, stderr = run_check(["ls"]) assert stdout == "stdout\nline" assert stderr == "stderr\nline"
def test_log_stderr_does_not_log(self, monkeypatch): # a 0 exit status doesn't log stderr monkeypatch.setattr( "anchore_engine.utils.subprocess.Popen", FakePopen(0, "stdout\nline", "stderr\nline"), ) error_log = Capture() monkeypatch.setattr("anchore_engine.utils.logger.error", error_log) stdout, stderr = run_check(["ls"]) assert error_log.calls == []
def test_raises_on_non_zero(self, monkeypatch): # a 0 exit status doesn't log stderr monkeypatch.setattr( "anchore_engine.utils.subprocess.Popen", FakePopen(100, "gathering info", "error! bad input"), ) error_log = Capture() monkeypatch.setattr("anchore_engine.utils.logger.error", error_log) with pytest.raises(CommandException) as error: stdout, stderr = run_check(["ls"]) assert error.value.msg == "Non-zero exit status code when running subprocess"
def test_run_check_with_input(cmd_list, input_data, expected_stdout, expected_stderr): # Function under test stdout, stderr = run_check(cmd_list, input_data) # Binary string returned in different environments can be padded with different amounts of whitespace # So convert it to utf-8 and trim it so we get a clean, reliable comparison if stdout is not None: stdout = stdout.strip() # Validate input assert stdout == expected_stdout assert stderr == expected_stderr
def test_log_stdout(self, monkeypatch): monkeypatch.setattr( "anchore_engine.utils.subprocess.Popen", FakePopen(0, "stdout\nline", b"stderr\nline"), ) debug_log = Capture() monkeypatch.setattr("anchore_engine.utils.logger.debug", debug_log) stdout, stderr = run_check(["ls"]) assert debug_log.calls[0]["args"] == ("running cmd: %s", "ls") assert debug_log.calls[1]["args"] == ("stdout: %s", "stdout") assert debug_log.calls[2]["args"] == ( "stdout: %s", "line", )
def run_syft(image): proc_env = os.environ.copy() syft_env = { "SYFT_CHECK_FOR_APP_UPDATE": "0", "SYFT_LOG_STRUCTURED": "1", } proc_env.update(syft_env) cmd = "syft -vv -o json oci-dir:{image}".format(image=image) stdout, _ = run_check(shlex.split(cmd), env=proc_env) return json.loads(stdout)
def test_non_zero_logs_error(self, monkeypatch): # set the log level to 2 (WARNING) monkeypatch.setattr("anchore_engine.utils.logger.log_level", 2) monkeypatch.setattr( "anchore_engine.utils.subprocess.Popen", FakePopen(100, "gathering info", "error! bad input"), ) error_log = Capture() debug_log = Capture() monkeypatch.setattr("anchore_engine.utils.logger.error", error_log) monkeypatch.setattr("anchore_engine.utils.logger.debug", debug_log) with pytest.raises(CommandException): stdout, stderr = run_check(["ls"]) assert len(error_log.calls) == 1
def test_non_zero_doesnt_log_error(self, monkeypatch): # at debug levels the stderr output is already logged # set the log level to 4 (DEBUG) monkeypatch.setattr("anchore_engine.utils.logger.log_level", 4) monkeypatch.setattr( "anchore_engine.utils.subprocess.Popen", FakePopen(100, "gathering info", "error! bad input"), ) error_log = Capture() debug_log = Capture() monkeypatch.setattr("anchore_engine.utils.logger.error", error_log) monkeypatch.setattr("anchore_engine.utils.logger.debug", debug_log) with pytest.raises(CommandException): stdout, stderr = run_check(["ls"]) assert len(error_log.calls) == 0 assert len(debug_log.calls) == 3
def test_run_check_invalid_cmd_list(cmd_list): with pytest.raises(Exception) as error: # Function under test run_check(cmd_list)