From 2ca81d1ee48adb4e2ed2bba99c480276ad6957cc Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 5 Jul 2026 04:54:17 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20CLI=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=20=EB=A9=94=EC=8B=9C=EC=A7=80=20=EC=8B=9C=EA=B0=81?= =?UTF-8?q?=EC=A0=81=20=EA=B0=80=EC=8B=9C=EC=84=B1=20=EB=B0=8F=20UX=20?= =?UTF-8?q?=ED=96=A5=EC=83=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CLI의 Error 및 Warning 메시지 출력 시 일관된 이모지와 키워드("❌ Error", "⚠️ Warning")가 포함되도록 수정하여 사용자가 문제 수준을 즉각 파악할 수 있도록 UX를 개선했습니다. - 오류 메시지에는 문제 해결을 돕는 "💡 Hint:" 안내 문구를 추가하여 접근성을 높였습니다. - 관련 테스트 코드(test_appguardrail.py)의 출력 문자열 검증 구문도 변경된 메시지 형식에 맞게 일치시켰습니다. --- .Jules/palette.md | 1 + scanner/cli/appguardrail.py | 25 +++++++++++++------------ tests/test_appguardrail.py | 4 ++-- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/.Jules/palette.md b/.Jules/palette.md index f8c1fbd..6ffbbda 100644 --- a/.Jules/palette.md +++ b/.Jules/palette.md @@ -5,3 +5,4 @@ ## 2026-06-30 - Added Emojis to CLI Output Messages **Learning:** Adding subtle emojis to informative CLI output headers (like "Created/updated files" and "Next steps") provides clearer visual cues for developers scanning long CLI output. **Action:** Always include relevant emojis in summary output text to make success and informational messages more visually distinguishable from routine command logs. +## 2026-07-05 - AppGuardrail CLI Emoji Formatting\n**Learning:** CLI output is significantly more scannable and accessible when Errors, Warnings, and file lists consistently use semantic prefixing combined with emojis (e.g. '❌ Error', '⚠️ Warning'). Adding '💡 Hint:' lines to errors reduces user friction.\n**Action:** Ensure all future CLI text changes or additions follow these exact structural and visual guidelines. diff --git a/scanner/cli/appguardrail.py b/scanner/cli/appguardrail.py index 9314ee4..37efa45 100644 --- a/scanner/cli/appguardrail.py +++ b/scanner/cli/appguardrail.py @@ -1422,7 +1422,7 @@ def cmd_scan(args): findings.extend(_run_bandit_scan(scan_path)) except RuntimeError as exc: if external_plan.bandit.auto_selected and not external_plan.bandit.forced: - print(f"⚠️ Skipping Bandit auto integration: {exc}\n") + print(f"⚠️ Warning: Skipping Bandit auto integration: {exc}\n") else: print(f"❌ Error: {exc}", file=sys.stderr) print( @@ -1437,7 +1437,7 @@ def cmd_scan(args): findings.extend(_run_ruff_security_scan(scan_path)) except RuntimeError as exc: if external_plan.ruff.auto_selected and not external_plan.ruff.forced: - print(f"⚠️ Skipping Ruff auto integration: {exc}\n") + print(f"⚠️ Warning: Skipping Ruff auto integration: {exc}\n") else: print(f"❌ Error: {exc}", file=sys.stderr) print( @@ -1455,7 +1455,7 @@ def cmd_scan(args): external_plan.semgrep.auto_selected and not external_plan.semgrep.forced ): - print(f"⚠️ Skipping Semgrep auto integration: {exc}\n") + print(f"⚠️ Warning: Skipping Semgrep auto integration: {exc}\n") else: print(f"❌ Error: {exc}", file=sys.stderr) print( @@ -1470,7 +1470,7 @@ def cmd_scan(args): findings.extend(_run_zap_baseline(zap_baseline_url)) except RuntimeError as exc: if external_plan.zap.auto_selected and not external_plan.zap.forced: - print(f"⚠️ Skipping ZAP auto integration: {exc}\n") + print(f"⚠️ Warning: Skipping ZAP auto integration: {exc}\n") else: print(f"❌ Error: {exc}", file=sys.stderr) print( @@ -1652,11 +1652,11 @@ def cmd_org_bundle(args): summary = manifest["summary"] print(f"\n✅ Buyer evidence bundle written: {bundle_dir}\n") - print("Files:") - print(" - org-readiness.md") - print(" - buyer-evidence.json") - print(" - manifest.json") - print(" - README.md") + print("📄 Files:") + print("📄 - org-readiness.md") + print("📄 - buyer-evidence.json") + print("📄 - manifest.json") + print("📄 - README.md") print() print(f"Open PRs analyzed: {summary['open_pull_requests']}") print(f"Buyer evidence status: {summary['buyer_evidence_status']}") @@ -2634,13 +2634,14 @@ def _print_scan_results(findings, files_scanned): ) if files_scanned == 0: - print("\n⚠️ No files were scanned. Are you in the right directory?") + print("\n⚠️ Warning: No files were scanned. Are you in the right directory?") elif counts["CRITICAL"] > 0: issue_word = "issue" if counts["CRITICAL"] == 1 else "issues" - print(f"\n❌ Critical {issue_word} found. Fix before deploying.") + print(f"\n❌ Error: Critical {issue_word} found. Fix before deploying.") + print("💡 Hint: Review the critical issues and apply fixes before deploying.") elif counts["HIGH"] > 0: issue_word = "issue" if counts["HIGH"] == 1 else "issues" - print(f"\n⚠️ High-severity {issue_word} found. Review before deploying.") + print(f"\n⚠️ Warning: High-severity {issue_word} found. Review before deploying.") elif not findings: print("\n✅ No issues found in this scan.") else: diff --git a/tests/test_appguardrail.py b/tests/test_appguardrail.py index 3d1a633..8a678d1 100644 --- a/tests/test_appguardrail.py +++ b/tests/test_appguardrail.py @@ -1300,7 +1300,7 @@ def test_print_scan_results_critical(capsys): assert "Found a critical issue" in captured.out assert "Code: const secret = 'abc';" in captured.out assert "🔴 1 critical issue" in captured.out - assert "❌ Critical issue found. Fix before deploying." in captured.out + assert "❌ Error: Critical issue found. Fix before deploying." in captured.out assert ( "💡 Run 'appguardrail review' to get an AI prompt for fixing this issue." in captured.out @@ -1323,7 +1323,7 @@ def test_print_scan_results_high(capsys): assert "[🟠 HIGH] app/api/route.ts:5" in captured.out assert "🟠 1 high issue" in captured.out - assert "⚠️ High-severity issue found. Review before deploying." in captured.out + assert "⚠️ Warning: High-severity issue found. Review before deploying." in captured.out def test_print_scan_results_warnings_only(capsys):