From e9b27f6b440ff8d3fa8b277c23e67ef137a39281 Mon Sep 17 00:00:00 2001 From: Advait Patel Date: Thu, 2 Jul 2026 02:39:35 -0500 Subject: [PATCH] Route docker_scanner error/troubleshooting output through docksec.output --- docksec/docker_scanner.py | 46 +++++++++++++++++++-------------------- docs/CHANGELOG.md | 1 + 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/docksec/docker_scanner.py b/docksec/docker_scanner.py index 972fe34..ab9bda2 100644 --- a/docksec/docker_scanner.py +++ b/docksec/docker_scanner.py @@ -459,32 +459,32 @@ def scan_dockerfile(self) -> Tuple[bool, Optional[str]]: except subprocess.CalledProcessError as e: error_msg = f"Hadolint execution failed: {e}" logger.error(error_msg, exc_info=True) - print(f"\n[ERROR] Error: {error_msg}") - print("\nTroubleshooting steps:") - print(" 1. Verify Hadolint is installed: hadolint --version") - print(" 2. Check file permissions on the Dockerfile") - print(" 3. Ensure Dockerfile syntax is valid") + ui.error(error_msg) + ui.detail("Troubleshooting steps:") + ui.detail(" 1. Verify Hadolint is installed: hadolint --version") + ui.detail(" 2. Check file permissions on the Dockerfile") + ui.detail(" 3. Ensure Dockerfile syntax is valid") return False, str(e) except subprocess.TimeoutExpired: error_msg = "Hadolint scan timed out after 300 seconds" logger.error(f"{error_msg} for {self.dockerfile_path}") - print(f"\n[ERROR] Error: {error_msg}") - print("\nTroubleshooting steps:") - print(" 1. The Dockerfile may be extremely large") - print(" 2. Try splitting into smaller Dockerfiles") - print(" 3. Check for infinite loops or circular dependencies") + ui.error(error_msg) + ui.detail("Troubleshooting steps:") + ui.detail(" 1. The Dockerfile may be extremely large") + ui.detail(" 2. Try splitting into smaller Dockerfiles") + ui.detail(" 3. Check for infinite loops or circular dependencies") return False, "Scan timeout" except FileNotFoundError: error_msg = "Hadolint not found in PATH" logger.error(error_msg) - print(f"\n[ERROR] Error: {error_msg}") - print("\nInstallation instructions:") - print(self._get_tool_installation_instructions('hadolint')) + ui.error(error_msg) + ui.detail("Installation instructions:") + ui.detail(self._get_tool_installation_instructions('hadolint')) return False, error_msg except Exception as e: error_msg = f"Unexpected error during Hadolint scan: {e}" logger.error(error_msg, exc_info=True) - print(f"\n[ERROR] Error: {error_msg}") + ui.error(error_msg) return False, str(e) def _filter_scan_results(self, scan_results: Dict) -> List[Dict]: @@ -575,7 +575,7 @@ def scan_image_json(self, severity: str = "CRITICAL,HIGH") -> Tuple[bool, Option progress.update(scan_task, completed=True) if result.stderr and 'error' in result.stderr.lower() and not result.stdout: - print(f"[ERROR] Trivy scan failed: {result.stderr[:200]}") + ui.error(f"Trivy scan failed: {result.stderr[:200]}") return False, None if not result.stdout: @@ -592,17 +592,17 @@ def scan_image_json(self, severity: str = "CRITICAL,HIGH") -> Tuple[bool, Option except subprocess.TimeoutExpired: error_msg = "Trivy scan timed out after 600 seconds" logger.error(error_msg) - print(f"[ERROR] {error_msg}") + ui.error(error_msg) return False, None except json.JSONDecodeError as e: error_msg = f"Failed to parse Trivy output: {e}" logger.error(error_msg) - print(f"[ERROR] {error_msg}") + ui.error(error_msg) return False, None except (subprocess.CalledProcessError, Exception) as e: error_msg = f"Trivy scan failed: {e}" logger.error(error_msg, exc_info=True) - print(f"[ERROR] {error_msg}") + ui.error(error_msg) return False, None def scan_image(self, severity: str = "CRITICAL,HIGH") -> Tuple[bool, Optional[str]]: @@ -644,10 +644,10 @@ def scan_image(self, severity: str = "CRITICAL,HIGH") -> Tuple[bool, Optional[st return result.returncode == 0, result.stdout except subprocess.TimeoutExpired: - print("[ERROR] Trivy scan timed out after 600 seconds") + ui.error("Trivy scan timed out after 600 seconds") return False, "Scan timed out" except subprocess.CalledProcessError as e: - print(f"[ERROR] Error running Trivy scan: {e}") + ui.error(f"Error running Trivy scan: {e}") return False, str(e) def advanced_scan(self) -> Dict: @@ -678,13 +678,13 @@ def advanced_scan(self) -> Dict: if any(x in line for x in ['Target', 'Base image', 'Updated base image', 'vulnerabilities']): summary_lines.append(line.strip()) - print(f" [ADVANCED] Docker Scout Summary for {self.image_name}:") + ui.info(f"Docker Scout Summary for {self.image_name}:") if summary_lines: for line in summary_lines[:5]: # Show top 5 summary lines - print(f" {line}") + ui.detail(f" {line}") else: # Fallback to a very short version of output if parsing fails - print(f" {output.splitlines()[0] if output.splitlines() else 'Scan completed.'}") + ui.detail(f" {output.splitlines()[0] if output.splitlines() else 'Scan completed.'}") result_dict['success'] = True result_dict['output'] = result.stdout diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 5f45677..a476eba 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - **Cleaner terminal output**: internal logs now write to `stderr` instead of `stdout` and stay quiet in CLI mode, so raw location-tagged log lines no longer interleave with the tool's user-facing messages. Set `DOCKSEC_LOG_LEVEL` to restore verbose logging. +- `docker_scanner.py`'s Hadolint/Trivy/Docker Scout error and troubleshooting messages now route through `docksec.output` instead of raw `print()`, so they're consistently styled and honor `--quiet`/`--no-color`/`--json` like the rest of the tool's output. - The security score is now rendered once, in the result summary, instead of mid-scan. - Report generation runs silently and the CLI renders a single report summary from the result (removes the misleading progress bars). - **Honest exit codes**: a failed scan (for example, an image that is not found) now exits non-zero instead of ending with "Analysis complete!".