Skip to content

fix(security): restore sandbox block reasons and wire security panel (#408, #409) - #426

Merged
F16shen merged 4 commits into
AI-Shell-Team:mainfrom
F16shen:fix/security-panel-message-408-409
Aug 3, 2026
Merged

fix(security): restore sandbox block reasons and wire security panel (#408, #409)#426
F16shen merged 4 commits into
AI-Shell-Team:mainfrom
F16shen:fix/security-panel-message-408-409

Conversation

@F16shen

@F16shen F16shen commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Summary

Change Type

  • Bug 修复
  • 功能增强 / UX

Scope

  • 安全模块
  • 技能 / 工具
  • Shell / TUI

User-visible Changes

  • Sandbox Block text now shows the matched rule reason (e.g. “System config changes can break the host”) plus rule id / paths instead of a generic HIGH sentence.
  • Confirm / Blocked security prompts use the rich panel: Tool, Command, Risk, Reason, Rule, Paths, Alternatives, and (when relevant) a degraded-sandbox Note even if Paths are also present.
  • Closed confirm box draws the bottom border before key input so the prompt is not clipped.

Compatibility

  • Backward compatible? Yes
  • Config changes? No

Testing

  • cargo test -p aish-security assess_sandbox_result_exposes_rule_reason_when_description_missing
  • cargo test -p aish-tools test_bash_tool_preflight_sandbox_hit_uses_rule_reason_without_description
  • cargo test -p aish-tools test_bash_tool_preflight_sandbox_hit_falls_back_to_rule_identity
  • cargo test -p aish-shell security_panel
  • Manual: run a sandbox-blocked rm /etc/... path and confirm Block text shows rule reason + H-001/paths instead of the generic HIGH sentence
  • Manual: trigger a Confirm decision and verify the closed panel shows Tool / Command / Risk / Reason / Rule / Paths / Alternatives with y/a/r/n still working
  • Manual: degraded-sandbox path with matched paths still shows both Paths and Note

🤖 AI-assisted · lightly tested (unit/integration); needs local UI confirmation screenshots before merge

Summary by CodeRabbit

  • New Features
    • Security prompts now show clearer explanations, matched rules, and affected file paths.
    • Security panels provide structured details including tool, target, risk, alternatives, and the selected verdict.
    • Non-interactive security checks now display a notice and automatically deny the action.
    • Security impact messages now use the most relevant available rule description or reason.
  • Localization
    • Added and updated security-panel labels for English, German, Spanish, French, Japanese, and Chinese.

F16shen added 2 commits July 31, 2026 10:14
Write human-facing rule.reason into sandbox assessment results and fall
back impact_description to reason, then annotate format_security_message
with rule id/paths so Block text no longer degrades to a generic HIGH
level sentence.

Fixes AI-Shell-Team#408
Connect confirmation/security_notice callbacks to the rich security
panel, separate Reason/Rule/Paths rows, and draw a complete confirm box
before reading input so bottom borders are not delayed until keypress.
Reserve viewport space via ScrollUp instead of inserting blank lines.

Fixes AI-Shell-Team#409
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Thanks for the pull request. A maintainer will review it when available.

Please keep the PR focused, explain the why in the description, and make sure local checks pass before requesting review.

Contribution guide: https://github.com/AI-Shell-Team/aish/blob/main/CONTRIBUTING.md

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Template check passed. Thanks for updating the pull request description.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The change propagates matched rule reasons, identities, and paths through sandbox assessment and Bash messages. It adds structured localized security-panel rows and routes interactive and non-interactive security flows through centralized shell rendering.

Changes

Security panel enrichment

Layer / File(s) Summary
Policy reason propagation and message fallback
crates/aish-security/src/sandbox/assess.rs, crates/aish-tools/src/bash/bash.rs
Sandbox assessment falls back from rule description to rule reason. Bash messages select primary explanations and append matched rule IDs and paths.
Structured panel rows and localized labels
crates/aish-shell/src/security_panel.rs, crates/aish-i18n/locales/*
The panel exposes separate localized rows for reason, rule, matched paths, risk, fallbacks, and alternatives.
Centralized panel rendering and approval flow
crates/aish-shell/src/app.rs
Interactive confirmations and non-interactive notices use the shared renderer. The renderer formats content, displays verdicts, and denies non-interactive notices.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SandboxAssessment
  participant BashPreflight
  participant SecurityPanel
  participant ShellApp
  participant Operator
  SandboxAssessment->>BashPreflight: provide rule reason and impact description
  BashPreflight->>SecurityPanel: provide primary message, rule IDs, and paths
  ShellApp->>SecurityPanel: render security context panel
  SecurityPanel->>Operator: display localized rows and approval choices
  Operator->>ShellApp: return approval verdict
Loading

Possibly related PRs

  • AI-Shell-Team/aish#416: Adds security-policy rule and reason metadata consumed by this change.
  • AI-Shell-Team/aish#425: Also updates sandbox assessment and Bash security-message handling for rule reasons, IDs, and paths.

Poem

A rabbit checks each rule and path,
Then shows the reason on its path.
Local labels line the gate,
Clear verdicts mark approve or wait.
The panel hops from fact to fate.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 41.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: restoring sandbox block reasons and integrating the security panel.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added size: L and removed size: XL labels Aug 3, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
crates/aish-shell/src/security_panel.rs (1)

343-395: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a case covering degraded sandbox together with matched paths.

The current tests only exercise a clean decision. The gap flagged at lines 76-101 (fallback hint suppressed when matched_paths is non-empty) is not covered. Add a context where analysis.sandbox.reason = Some("sandbox_ipc_unavailable"), analysis.sandbox.enabled = false, and matched_paths is non-empty, then assert both the paths row and the fallback-hint row are present.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/aish-shell/src/security_panel.rs` around lines 343 - 395, Add a test
context for degraded sandbox behavior with analysis.sandbox.reason set to
"sandbox_ipc_unavailable", analysis.sandbox.enabled false, and non-empty
matched_paths. Exercise security_panel_rows and assert that both the matched
paths row and the fallback-hint row are present, covering the path where the
hint must not be suppressed by matched paths.
crates/aish-tools/src/bash/bash.rs (1)

264-296: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider making the annotation format an explicit shared contract.

annotate_security_message encodes rule id and paths into the message string as " (H-001; paths: /etc)". crates/aish-shell/src/security_panel.rs::strip_message_annotation parses that same suffix back out with a heuristic (rfind(" (") plus a paths: / H/M/L prefix check). Today the strip path only runs when no SecurityDecision is attached, so the two never disagree in practice. If a future change routes an annotated message through the fallback path, the heuristic can strip a legitimate parenthetical or miss a real annotation.

Prefer keeping the structured fields (matched_rule, matched_paths) as the single source and letting the panel format them, instead of round-tripping through text.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/aish-tools/src/bash/bash.rs` around lines 264 - 296, The security
annotation is encoded in text and later heuristically parsed by
strip_message_annotation, creating an implicit format contract. Refactor
annotate_security_message and the related security-panel flow to preserve and
pass matched_rule and matched_paths as structured data, then format them in the
panel; remove the annotation round-trip and heuristic stripping while preserving
the current displayed rule-id and path information.
crates/aish-shell/src/app.rs (1)

10498-10515: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Clamp the wrap width before calling wrap_text.

width is accepted from COLUMNS without a lower bound, and width.saturating_sub(14) can be 0. wrap_text returns the source text unchanged when the width is 0, so no termination issue is present here. The main effect is that the estimate at line 10512 and the rendered lines at line 10592 can use a different wrapping width from inner_width, which changes approval-panel layout.

🛡️ Proposed fix
-    for (_, value) in rows {
+    let wrap_width = width.saturating_sub(14).max(20);
+    for (_, value) in rows {
         let safe_value = sanitize_for_display(value);
         if safe_value.is_empty() {
             lines += 1;
             continue;
         }
         for raw_line in safe_value.lines() {
-            let wrapped = wrap_text(raw_line, width.saturating_sub(14));
+            let wrapped = wrap_text(raw_line, wrap_width);
             lines += wrapped.lines().count().max(1);
         }
     }

Apply the matching change at line 10592 so the estimate and the render stay in sync.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/aish-shell/src/app.rs` around lines 10498 - 10515, Clamp the wrapping
width consistently in estimate_security_panel_lines and the corresponding render
path so both use the same bounded width derived from inner_width. Update the
wrap_text call near the rendering logic as well as the estimate, preserving
synchronized approval-panel layout for small terminal widths.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/aish-shell/src/security_panel.rs`:
- Around line 178-193: Update strip_message_annotation so annotation detection
validates an explicit rule-ID shape instead of accepting any suffix part
beginning with H, M, or L. Preserve paths: handling and stripping only when the
parenthetical contains the expected identifiers such as H-001, M-001, or L-001,
while leaving legitimate text like “Host unreachable” unchanged.
- Around line 76-101: Make the matched-paths and degraded-sandbox hint rows
independent in the security panel: change the fallback-hint branch following the
matched-paths handling so it can also run when paths are present. In that
branch, reuse the existing reason value computed earlier in the panel instead of
calling primary_panel_reason again, while preserving the existing note-empty and
duplicate checks.

---

Nitpick comments:
In `@crates/aish-shell/src/app.rs`:
- Around line 10498-10515: Clamp the wrapping width consistently in
estimate_security_panel_lines and the corresponding render path so both use the
same bounded width derived from inner_width. Update the wrap_text call near the
rendering logic as well as the estimate, preserving synchronized approval-panel
layout for small terminal widths.

In `@crates/aish-shell/src/security_panel.rs`:
- Around line 343-395: Add a test context for degraded sandbox behavior with
analysis.sandbox.reason set to "sandbox_ipc_unavailable",
analysis.sandbox.enabled false, and non-empty matched_paths. Exercise
security_panel_rows and assert that both the matched paths row and the
fallback-hint row are present, covering the path where the hint must not be
suppressed by matched paths.

In `@crates/aish-tools/src/bash/bash.rs`:
- Around line 264-296: The security annotation is encoded in text and later
heuristically parsed by strip_message_annotation, creating an implicit format
contract. Refactor annotate_security_message and the related security-panel flow
to preserve and pass matched_rule and matched_paths as structured data, then
format them in the panel; remove the annotation round-trip and heuristic
stripping while preserving the current displayed rule-id and path information.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8ae95c42-f5b2-4f83-a0f1-f80148680012

📥 Commits

Reviewing files that changed from the base of the PR and between af55deb and 6ac8bad.

📒 Files selected for processing (10)
  • crates/aish-i18n/locales/de-DE.yaml
  • crates/aish-i18n/locales/en-US.yaml
  • crates/aish-i18n/locales/es-ES.yaml
  • crates/aish-i18n/locales/fr-FR.yaml
  • crates/aish-i18n/locales/ja-JP.yaml
  • crates/aish-i18n/locales/zh-CN.yaml
  • crates/aish-security/src/sandbox/assess.rs
  • crates/aish-shell/src/app.rs
  • crates/aish-shell/src/security_panel.rs
  • crates/aish-tools/src/bash/bash.rs

Comment thread crates/aish-shell/src/security_panel.rs
Comment thread crates/aish-shell/src/security_panel.rs
Keep Paths and degraded-sandbox Note independent so users still see
when assessment fell back, tighten annotation stripping to H/M/L-###
ids, and clamp narrow-terminal wrap width for estimate/render parity.
@github-actions github-actions Bot added size: XL and removed size: L labels Aug 3, 2026
@F16shen
F16shen merged commit 64d6781 into AI-Shell-Team:main Aug 3, 2026
9 checks passed
@F16shen
F16shen deleted the fix/security-panel-message-408-409 branch August 3, 2026 08:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant