Skip to content

fix(dashboard): make scan states and detail focus perceivable - #930

Draft
seonghobae wants to merge 60 commits into
developfrom
palette/ux-visual-parity-aria-states-9123751085749638130
Draft

fix(dashboard): make scan states and detail focus perceivable#930
seonghobae wants to merge 60 commits into
developfrom
palette/ux-visual-parity-aria-states-9123751085749638130

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Buyer-visible gap

The dashboard exposed asynchronous and disabled state through attributes, but some states had weak visual parity and the scan-detail flow could leave keyboard focus on a non-focusable container. External references also opened a new tab without announcing that behavior. The browser console also accepted elevated organization API keys even though its product surface is read-only, unnecessarily exposing owner/member credentials to a browser session.

Current bounded change

  • give enabled buttons visible hover feedback while disabled controls remain visually unavailable;
  • style busy scan rows and expose a visible wait state while detail is loading;
  • replace the inline Clear filters style with a reusable class and return focus to the search field;
  • make external-reference URLs fail closed, normalize accepted HTTP(S) targets, preserve `rel="noopener", and announce that the link opens in a new tab;
  • keep stale detail responses from replacing the latest selected scan;
  • wire the close control in both successful and failed detail responses;
  • move keyboard focus to the newly rendered close button in both paths and restore the initiating row on close;
  • preserve reduced-motion behavior when scrolling details into view;
  • require a dedicated viewer API key for the read-only browser console;
  • keep the credential only in memory for the current page lifetime and purge legacy sessionStorage key names;
  • reject member/owner credentials before loading scan history by using the control plane's side-effect-free bodyless scan-creation authorization boundary;
  • escape scan identifiers before placing them in HTML attributes;
  • cover these contracts with focused Python regressions, including proof that the role probe does not create a scan.

Current-head regression repair

A later Palette commit 7a46834dde5d3ea2334af7e55aea4cf9075120de added the viewer-key authorization contract but silently removed two already-reviewed visual-parity details from the preceding head. The repair was test-first:

  • RED 06c48b06f47c3403c4ca0eb94e5ea7a70325a538 requires enabled-only hover feedback and a visible/pointer-disabled busy-row state;
  • GREEN e5dec61b415b5141fa5ba74437372998624b6c1f restores the missing CSS while preserving the viewer-key, focus, stale-response, escaping, reduced-motion, and memory-only credential contracts.

The production close-button flow focuses the actionable close control in both success and error paths and closeDetail() restores the initiating scan row. The viewer-key probe remains side-effect-free under the dedicated control-plane regression: viewer returns 403 before body handling, while elevated keys reach malformed-body validation and are rejected by the browser console before scan history loads.

Exact predecessor candidate

  • base: develop@a68b57d4ccad4f895d7a3d9f909fffbc4653b17e
  • head: e5dec61b415b5141fa5ba74437372998624b6c1f
  • changed paths: .jules/palette.md, scanner/dashboard/console.html, scanner/dashboard/index.html, tests/test_console_dashboard_security.py, tests/test_console_viewer_key_contract.py, tests/test_dashboard_external_link_contract.py, and tests/test_console_visual_state_contract.py.

Active design successor / writer boundary

Cursor-owned PR #977 is now the active design-system successor on the same scanner/dashboard/console.html interaction surface. It adds the reusable --busy-opacity token, separates aria-busy visual state from explicit aria-disabled unavailability, and records the dashboard Storybook inventory/ADR. That design work is valuable, but its current head 8759efb721020c99dd171fe43ce3f6bb398df95e is based on an older console tree and currently lacks several stricter contracts already present here: dedicated viewer-only authorization, memory-only credential handling, escaped scan IDs, stale-detail request identity, and focusing the rendered close button rather than the detail container.

This branch is therefore a verified predecessor/security-accessibility contract, not a competing delivery branch. Do not source-edit or merge #930 independently while #977 is the active Cursor writer. #977 must reconcile the exact #930 behavior above while preserving its unique busy/unavailable token and Storybook work, then acquire fresh exact-head evidence. A handoff with these exact requirements has been posted on #977.

The earlier #978 external-link-only Palette PR was closed as a proven duplicate because #930 already preserves its unique buyer behavior with stronger URL validation and tests.

Security and accessibility boundary

This change tightens API-key handling rather than weakening it: owner/member keys are rejected for browser-console use, the accepted viewer credential is memory-only, authentication remains same-origin Bearer authorization, and output escaping remains in place. title="Close (Esc)" is supplementary pointer help; the close button retains an accessible name, receives programmatic focus, supports click activation, and the existing Escape handler remains available. This PR improves component-level keyboard, state, link, and least-privilege feedback. It does not claim whole-product WCAG conformance or replace rendered assistive-technology testing.

Integration boundary

Keep Draft. Preserve e5dec61b415b5141fa5ba74437372998624b6c1f as the predecessor contract for #977 reconciliation. After the active successor incorporates these security/accessibility requirements, require new exact-head repository/organization CI, security, coverage, review-thread, and qualifying independent approval evidence on that successor. No predecessor-head check, model verdict, status, or author evidence transfers.

💡 What
- `scanner/dashboard/console.html`의 버튼에 `:hover` 및 `:disabled` 시각적 피드백 추가
- `.close-btn` 요소에 `title="Close (Esc)"` 툴팁 추가
- `tr.scan`의 로딩 상태(`aria-busy="true"`)에 대한 시각적 피드백(opacity, pointer-events) 추가
- `scanner/dashboard/index.html`의 "Clear filters" 버튼 스타일을 CSS 클래스(`.clear-btn`)로 분리하고 hover 효과 추가

🎯 Why
- 스크린 리더 사용자뿐만 아니라 시각 장애가 없는 일반 사용자도 ARIA 상태(`aria-busy`)나 비활성화(`disabled`) 상태를 명확히 인지할 수 있도록 시각적 피드백을 제공하여 사용성을 향상시키기 위함입니다.
- 인라인 스타일을 클래스로 분리하여 코드 유지보수성을 높였습니다.

📸 Before/After
(비주얼 변경 사항으로, PR 리뷰어 확인용 스크린샷이 첨부됩니다.)

♿ Accessibility
- ARIA 상태(`aria-busy="true"`)와 시각적 UI 간의 동기화(parity) 달성
- 닫기 버튼에 마우스 호버 시 툴팁(`title`)을 제공하여 명확한 컨텍스트 전달
@google-labs-jules

Copy link
Copy Markdown

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c0a09860-066e-46e3-9a16-41e3cd0f0cd1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c7070dd5-c860-41b1-b3e9-73c99f3c205a

📥 Commits

Reviewing files that changed from the base of the PR and between c879de8 and 2269c8b.

📒 Files selected for processing (3)
  • .jules/palette.md
  • scanner/dashboard/console.html
  • scanner/dashboard/index.html

📝 Walkthrough

Walkthrough

대시보드의 필터 초기화 버튼을 CSS 클래스로 변경하고 외부 링크에 접근성 레이블을 추가했습니다. 콘솔에는 비활성·처리 중 상태 스타일과 상세 닫기 버튼 툴팁을 추가했습니다. 접근성 적용 지침도 기록했습니다.

Changes

대시보드 및 콘솔 접근성 개선

Layer / File(s) Summary
대시보드 컨트롤 및 링크
.jules/palette.md, scanner/dashboard/index.html
필터 초기화 버튼이 clear-btn 클래스를 사용합니다. 외부 링크에는 새 탭 열림을 설명하는 aria-label을 추가했습니다. 관련 접근성 지침을 기록했습니다.
콘솔 상태 및 닫기 컨트롤
scanner/dashboard/console.html
비활성 버튼과 처리 중인 스캔 행의 시각적 상태를 추가했습니다. 상세 보기와 상세 로딩 오류의 닫기 버튼에 title="Close (Esc)"를 추가했습니다.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 2269c

The dashboard changes improve accessible state feedback, detail-panel focus handling, external-link announcements, and least-privilege credential use. No actionable merge-blocking risk remains at the current head beyond normal checks.

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 제목은 대시보드의 스캔 상태 피드백과 상세 보기 포커스 개선이라는 변경의 핵심을 명확하게 요약합니다.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch palette/ux-visual-parity-aria-states-9123751085749638130

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.

@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: 1

🤖 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 `@scanner/dashboard/console.html`:
- Around line 170-172: Update the error path in the detail-loading catch handler
to attach the same closeDetail click listener to the newly rendered .close-btn,
matching the successful path; alternatively reuse a shared helper for creating
and wiring the close button.
🪄 Autofix

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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 60e8c6c9-d334-4fa3-b3be-962cb757d62d

📥 Commits

Reviewing files that changed from the base of the PR and between a68b57d and 144b823.

📒 Files selected for processing (3)
  • .jules/palette.md
  • scanner/dashboard/console.html
  • scanner/dashboard/index.html

Comment thread scanner/dashboard/console.html
화면 판독기 사용자가 외부 링크를 클릭할 때 새 탭이 열린다는 사실을 인지할 수 있도록 `target="_blank"` 속성이 있는 링크에 `aria-label="... (opens in a new tab)"` 속성을 추가했습니다. 이를 통해 예기치 않은 컨텍스트 전환으로 인한 혼란을 방지하고 접근성을 개선했습니다.

* `scanner/dashboard/index.html` 의 참조 링크 렌더링 로직 업데이트
* `tests/test_dashboard_core.py` 에 관련 접근성 검증 테스트 추가
@seonghobae
seonghobae enabled auto-merge (squash) August 14, 2026 08:04

Copy link
Copy Markdown
Contributor Author

@opencode-agent Please run a fresh current-head review for 144b823be3a49208e60a06cb8dfd4dd8385ea143. The exact head has successful Tests, Security Process, Security Scan, SAST, CodeQL, dependency review, coverage, and appguardrail-scan; the sole inline finding was rechecked against the exact file, where the error-path close button already has the closeDetail listener, and the thread is resolved.

💡 What
- `scanner/dashboard/console.html`의 버튼에 `:hover` 및 `:disabled` 시각적 피드백 추가
- `.close-btn` 요소에 `title="Close (Esc)"` 툴팁 추가
- `tr.scan`의 로딩 상태(`aria-busy="true"`)에 대한 시각적 피드백(opacity, pointer-events) 추가
- `scanner/dashboard/index.html`의 "Clear filters" 버튼 스타일을 CSS 클래스(`.clear-btn`)로 분리하고 hover 효과 추가

🎯 Why
- 스크린 리더 사용자뿐만 아니라 시각 장애가 없는 일반 사용자도 ARIA 상태(`aria-busy`)나 비활성화(`disabled`) 상태를 명확히 인지할 수 있도록 시각적 피드백을 제공하여 사용성을 향상시키기 위함입니다.
- 인라인 스타일을 클래스로 분리하여 코드 유지보수성을 높였습니다.

📸 Before/After
(비주얼 변경 사항으로, 테스트 스크립트를 통해 검증 완료되었습니다.)

♿ Accessibility
- ARIA 상태(`aria-busy="true"`)와 시각적 UI 간의 동기화(parity) 달성
- 닫기 버튼에 마우스 호버 시 툴팁(`title`)을 제공하여 명확한 컨텍스트 전달
@seonghobae
seonghobae marked this pull request as draft August 14, 2026 08:14
auto-merge was automatically disabled August 14, 2026 08:14

Pull request was converted to draft

@seonghobae
seonghobae marked this pull request as ready for review August 14, 2026 08:14
@seonghobae
seonghobae enabled auto-merge (squash) August 14, 2026 08:14
💡 What
- `scanner/dashboard/console.html`의 버튼에 `:hover` 및 `:disabled` 시각적 피드백 추가
- `.close-btn` 요소에 `title="Close (Esc)"` 툴팁 추가
- `tr.scan`의 로딩 상태(`aria-busy="true"`)에 대한 시각적 피드백(opacity, pointer-events) 추가
- `scanner/dashboard/index.html`의 "Clear filters" 버튼 스타일을 CSS 클래스(`.clear-btn`)로 분리하고 hover 효과 추가
- Strix CI 스캔 실패 수정: `console.html`의 `data-id` 속성에 `s.id` 렌더링 시 XSS 방지를 위한 `esc()` 적용

🎯 Why
- 스크린 리더 사용자뿐만 아니라 시각 장애가 없는 일반 사용자도 ARIA 상태(`aria-busy`)나 비활성화(`disabled`) 상태를 명확히 인지할 수 있도록 시각적 피드백을 제공하여 사용성을 향상시키기 위함입니다.
- 인라인 스타일을 클래스로 분리하여 코드 유지보수성을 높였습니다.
- HTML Attribute Injection 취약점을 제거하여 보안을 강화했습니다.

📸 Before/After
(비주얼 변경 사항 및 XSS 방지 처리, 테스트 스크립트를 통해 검증 완료되었습니다.)

♿ Accessibility
- ARIA 상태(`aria-busy="true"`)와 시각적 UI 간의 동기화(parity) 달성
- 닫기 버튼에 마우스 호버 시 툴팁(`title`)을 제공하여 명확한 컨텍스트 전달
@seonghobae
seonghobae marked this pull request as draft August 14, 2026 09:32
auto-merge was automatically disabled August 14, 2026 09:32

Pull request was converted to draft

@seonghobae
seonghobae marked this pull request as ready for review August 14, 2026 09:32
@seonghobae
seonghobae enabled auto-merge (squash) August 14, 2026 09:32

Copy link
Copy Markdown
Contributor Author

@opencode-agent Please perform a fresh independent formal review of exact current head 570d0736a2c23fbe1ea9b210066c2c0af79c4c62 against live base a68b57d4ccad4f895d7a3d9f909fffbc4653b17e. All repository-owned exact-head Tests, Security Process/Scan, SAST, dependency review, coverage and required appguardrail-scan are successful; the only CodeRabbit inline finding is resolved. The organization ruleset requires one approval and last-push approval, so please return a head-bound APPROVE review if clean or actionable source findings if not. Treat workflow-dispatch success/status-only evidence as non-approval.

@google-labs-jules

Copy link
Copy Markdown

@opencode-agent Please perform a fresh independent formal review of exact current head 570d0736a2c23fbe1ea9b210066c2c0af79c4c62 against live base a68b57d4ccad4f895d7a3d9f909fffbc4653b17e. All repository-owned exact-head Tests, Security Process/Scan, SAST, dependency review, coverage and required appguardrail-scan are successful; the only CodeRabbit inline finding is resolved. The organization ruleset requires one approval and last-push approval, so please return a head-bound APPROVE review if clean or actionable source findings if not. Treat workflow-dispatch success/status-only evidence as non-approval.

Acknowledged.

seonghobae and others added 5 commits August 14, 2026 13:07
💡 What
- `scanner/dashboard/console.html`의 버튼에 `:hover` 및 `:disabled` 시각적 피드백 추가
- `.close-btn` 요소에 `title="Close (Esc)"` 툴팁 추가
- `tr.scan`의 로딩 상태(`aria-busy="true"`)에 대한 시각적 피드백(opacity, pointer-events) 추가
- `scanner/dashboard/index.html`의 "Clear filters" 버튼 스타일을 CSS 클래스(`.clear-btn`)로 분리하고 hover 효과 추가
- Strix CI 스캔 실패 수정: `console.html`의 `data-id` 속성에 `s.id` 렌더링 시 XSS 방지를 위한 `esc()` 적용

🎯 Why
- 스크린 리더 사용자뿐만 아니라 시각 장애가 없는 일반 사용자도 ARIA 상태(`aria-busy`)나 비활성화(`disabled`) 상태를 명확히 인지할 수 있도록 시각적 피드백을 제공하여 사용성을 향상시키기 위함입니다.
- 인라인 스타일을 클래스로 분리하여 코드 유지보수성을 높였습니다.
- HTML Attribute Injection 취약점을 제거하여 보안을 강화했습니다.

📸 Before/After
(비주얼 변경 사항 및 XSS 방지 처리, 테스트 스크립트를 통해 검증 완료되었습니다.)

♿ Accessibility
- ARIA 상태(`aria-busy="true"`)와 시각적 UI 간의 동기화(parity) 달성
- 닫기 버튼에 마우스 호버 시 툴팁(`title`)을 제공하여 명확한 컨텍스트 전달
- #connect 버튼과 tr.scan 요소의 :disabled 및 [aria-busy="true"] 상태에 대한 CSS 스타일 추가 (투명도 감소, 커서 변경)
- #key 입력값이 없을 때 #connect 버튼을 비활성화하도록 이벤트 리스너 추가 및 로딩 종료 후 비활성화 상태 동기화 처리

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

OpenCode cannot approve yet because required coverage evidence did not pass.

Review outcome

1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence

  • Problem: The required coverage-evidence job result was failure, so OpenCode cannot establish approval sufficiency for this head.

  • Root cause: Automated approval is only valid when the same-head coverage-evidence job proves supported repository test suites passed and configured docstring gates passed or were advisory, or reports not applicable because no supported source files or package manifests exist. Missing, failed, skipped, unavailable, or unsupported-tooling test evidence is a blocker.

  • Fix: Install or configure the repository test/docstring evidence tooling when source files or package manifests exist, rerun the current-head coverage-evidence job, and approve only after it reports success with required evidence or explicit no-source not-applicable evidence.

  • Regression test: Keep the approval branch checking needs.coverage-evidence.result == success before posting APPROVE, and publish REQUEST_CHANGES when coverage-evidence blocker states such as cancelled, skipped, failed, unsupported-tooling, or below-100 evidence are present.

  • Result: REQUEST_CHANGES

  • Reason: coverage-evidence result was failure, so required test/docstring evidence was not proven for current head 8964b5c352835399da707cd5ace688897808e283.

  • Head SHA: 8964b5c352835399da707cd5ace688897808e283

  • Workflow run: 31819007646

  • Workflow attempt: 1

Coverage evidence

Coverage evidence job did not run or did not publish coverage evidence.

Changed-File Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Changed file (4 files)"]
  S1 --> I1["repository behavior"]
  I1 --> R1["Review risk: Changed file (4 files)"]
  R1 --> V1["required checks"]
Loading

Copy link
Copy Markdown
Contributor Author

Exact-current-head read-only review request for 0604821c8ba25d4b0796ec611d649d461b82a0fa over protected develop@a68b57d4ccad4f895d7a3d9f909fffbc4653b17e.

All eight repository-owned exact-head workflows are terminal-success and every returned inline thread is resolved/outdated. Review the bounded dashboard state/focus/link contracts and the memory-only viewer-key boundary; predecessor verdicts are historical.

@opencode-agent review
@cwl-noema-review review
@coderabbitai review
@strix review

Read-only review. Do not update the branch, widen browser credential authority, synthesize author approval, weaken checks, or merge.

@seonghobae
seonghobae enabled auto-merge (squash) August 16, 2026 10:06
@coderabbitai

coderabbitai Bot commented Aug 16, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='a68b57d4ccad4f895d7a3d9f909fffbc4653b17e'
head='0604821c8ba25d4b0796ec611d649d461b82a0fa'

git cat-file -e "${base}^{commit}"
git cat-file -e "${head}^{commit}"
git merge-base --is-ancestor "$base" "$head"

printf '%s\n' '== exact commits =='
git show -s --format='commit=%H%nparents=%P%nsubject=%s' "$base" "$head"

printf '%s\n' '== changed files =='
git diff --name-status "$base...$head"

printf '%s\n' '== dashboard and test diff =='
git diff --find-renames --unified=35 "$base...$head" -- \
  scanner/dashboard/index.html \
  scanner/dashboard/console.html \
  tests

printf '%s\n' '== current console structure =='
ast-grep outline scanner/dashboard/console.html --items all

printf '%s\n' '== current dashboard structure =='
ast-grep outline scanner/dashboard/index.html --items all

printf '%s\n' '== console security and detail implementation =='
nl -ba scanner/dashboard/console.html | sed -n '65,250p'

printf '%s\n' '== dashboard links and focus implementation =='
nl -ba scanner/dashboard/index.html | sed -n '100,340p'

printf '%s\n' '== focused regression test definitions =='
for f in \
  tests/test_console_dashboard_security.py \
  tests/test_console_detail_loading_contract.py \
  tests/test_console_accessibility_contract.py \
  tests/test_dashboard_focus_live_region_contract.py \
  tests/test_dashboard_core.py
do
  if [ -f "$f" ]; then
    printf '\n-- %s --\n' "$f"
    ast-grep outline "$f" --items all
    rg -n -i -C 3 \
      'closeDetail|preventScroll|currentDetailRequest|lastDetailFocus|sessionStorage|localStorage|viewer|member|owner|Authorization|safeUrl|noopener|new tab|aria-label' \
      "$f"
  fi
done

printf '%s\n' '== endpoint authorization definitions =='
rg -n -C 8 --glob '*.py' \
  '(/api/v1/scans|def .*scan|async def .*scan|Authorization|Bearer|viewer|member|owner|role)' \
  scanner

Length of output: 39922


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== console implementation, current head =='
sed -n '65,250p' scanner/dashboard/console.html

printf '%s\n' '== dashboard implementation, current head =='
sed -n '100,340p' scanner/dashboard/index.html

printf '%s\n' '== authorization and scan endpoint definitions =='
rg -n -i -C 10 --glob '*.py' \
  '(/api/v1/scans|require.*role|role.*require|viewer|member|owner|api.?key|bearer|authorization)' \
  scanner

printf '%s\n' '== all console role-probe and credential contract references =='
rg -n -i -C 5 \
  '(viewer|member|owner|role.?probe|sessionStorage|localStorage|Authorization|/api/v1/scans)' \
  scanner/dashboard/console.html tests

printf '%s\n' '== remaining focused test source =='
for f in \
  tests/test_console_dashboard_security.py \
  tests/test_console_detail_loading_contract.py \
  tests/test_dashboard_external_link_contract.py
do
  if [ -f "$f" ]; then
    printf '\n-- %s --\n' "$f"
    sed -n '1,260p' "$f"
  fi
done

printf '%s\n' '== current console history after prior viewer-boundary implementation =='
git log --oneline --decorate \
  5ffdc21..0604821c8ba25d4b0796ec611d649d461b82a0fa -- \
  scanner/dashboard/console.html

Length of output: 177765


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== control-plane module candidates =='
fd -HI -t f 'controlplane\.py$' .

printf '%s\n' '== role hierarchy and HTTP route definitions =='
rg -n -C 12 --glob 'controlplane.py' \
  '(def has_role|def role_for_key|def require|def do_GET|def do_POST|/api/v1/scans|viewer|member|owner)' \
  .

printf '%s\n' '== exact console authorization flow =='
sed -n '100,215p' scanner/dashboard/console.html

printf '%s\n' '== role-specific endpoint test section =='
sed -n '277,321p' tests/test_controlplane.py

printf '%s\n' '== viewer-boundary commits and their console diffs =='
for commit in 7a807c5 df28e7e0c9472e47487c7c0da704781a0955292f; do
  printf '\n-- %s --\n' "$commit"
  git show --format='commit=%H%nsubject=%s' --unified=12 "$commit" -- scanner/dashboard/console.html
done

Length of output: 44140


@seonghobae I found one blocking issue in exact head 0604821c8ba25d4b0796ec611d649d461b82a0fa. I cannot approve this head.

  • P1 — Restore viewer-only key enforcement in scanner/dashboard/console.html.
    The console accepts a submitted key after GET /api/v1/scans succeeds in load() at Line 122. The server accepts every authenticated role for that route. appguardrail_core/controlplane.py defines the hierarchy as viewer < member < owner at Lines 327-333. Its GET /api/v1/scans route checks only that the key is valid at Lines 577-581. Therefore, member and owner keys can connect to the browser console.

    The console keeps KEY in memory, but it does not enforce the viewer-only boundary. Restore the side-effect-free role probe before load(): a viewer key must receive 403 from POST /api/v1/scans, while member and owner keys must be rejected. Also restore removal of the legacy ag_key and ag_viewer_key storage entries, as required by the stated credential contract.

I verified the other requested contracts. Both detail-result paths wire closeDetail and focus the rendered close control with preventScroll. The code invalidates stale detail responses, restores the initiating row on close or Escape, respects reduced-motion scrolling, escapes scan identifiers, validates external HTTP(S) links, preserves rel="noopener", and announces new-tab behavior.

You are interacting with an AI system.

@google-labs-jules

Copy link
Copy Markdown

Exact-current-head read-only review request for 0604821c8ba25d4b0796ec611d649d461b82a0fa over protected develop@a68b57d4ccad4f895d7a3d9f909fffbc4653b17e.

All eight repository-owned exact-head workflows are terminal-success and every returned inline thread is resolved/outdated. Review the bounded dashboard state/focus/link contracts and the memory-only viewer-key boundary; predecessor verdicts are historical.

@opencode-agent review
@cwl-noema-review review
@coderabbitai review
@strix review

Read-only review. Do not update the branch, widen browser credential authority, synthesize author approval, weaken checks, or merge.

Acknowledged.

@opencode-agent
opencode-agent Bot disabled auto-merge August 16, 2026 10:44
💡 What
- `console.html` 닫기 버튼에 `title="Close (Esc)"` 툴팁 추가
- `console.html` `button:disabled` 및 `tr.scan[aria-busy="true"]` 상태에 대한 시각적 피드백(opacity, cursor 등) 추가
- `console.html` 스캔 식별자 XSS 렌더링 방지 이스케이프 적용 및 뷰어 키 보안 정책 적용
- `index.html` 필터 지우기 버튼의 인라인 스타일을 `.clear-btn` 클래스로 추출하고 `:hover` 상태 추가
- `index.html` 외부 참조 링크에 `aria-label="... (opens in a new tab)"` 접근성 정보 추가

🎯 Why
- 비활성화된 버튼과 로딩 중인 목록이 시각적으로 구분되지 않아 사용자가 혼란을 겪을 수 있습니다.
- 닫기 버튼의 단축키가 명시되지 않아 키보드 사용자의 편의성이 떨어졌습니다.
- 필터 지우기 버튼에 시각적 피드백(hover)이 없어 상호작용 여부를 인지하기 어려웠습니다.
- 스크린 리더 사용자가 외부 링크를 클릭할 때 새 탭으로 열리는 것을 미리 알 수 없어 컨텍스트 전환에 혼란이 발생할 수 있습니다.
- 보안 리뷰어의 조언에 따라 최근 발견된 XSS 취약점을 해결하고 세션스토리지에 인증 정보를 보관하지 않도록 강화했습니다.

📸 Before/After
- 시각적 변화: hover 시 배경색 변경, disabled 시 투명도 조절, 로딩 상태 시 흐려짐
- 접근성 변화: 단축키 힌트 툴팁, 외부 링크 경고 ARIA 라벨 추가

♿ Accessibility
- 버튼의 aria-label 및 title 속성 추가를 통해 스크린 리더 및 키보드 사용자 지원 강화
- 새 탭에서 열리는 링크에 대한 스크린 리더 안내(aria-label) 추가
- 비활성화 및 로딩 상태를 명시적으로 나타내는 aria-busy 스타일 추가

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

OpenCode cannot approve yet because required coverage evidence did not pass.

Review outcome

1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence

  • Problem: The required coverage-evidence job result was failure, so OpenCode cannot establish approval sufficiency for this head.

  • Root cause: Automated approval is only valid when the same-head coverage-evidence job proves supported repository test suites passed and configured docstring gates passed or were advisory, or reports not applicable because no supported source files or package manifests exist. Missing, failed, skipped, unavailable, or unsupported-tooling test evidence is a blocker.

  • Fix: Install or configure the repository test/docstring evidence tooling when source files or package manifests exist, rerun the current-head coverage-evidence job, and approve only after it reports success with required evidence or explicit no-source not-applicable evidence.

  • Regression test: Keep the approval branch checking needs.coverage-evidence.result == success before posting APPROVE, and publish REQUEST_CHANGES when coverage-evidence blocker states such as cancelled, skipped, failed, unsupported-tooling, or below-100 evidence are present.

  • Result: REQUEST_CHANGES

  • Reason: coverage-evidence result was failure, so required test/docstring evidence was not proven for current head 7a46834dde5d3ea2334af7e55aea4cf9075120de.

  • Head SHA: 7a46834dde5d3ea2334af7e55aea4cf9075120de

  • Workflow run: 31950618149

  • Workflow attempt: 1

Coverage evidence

Coverage evidence job did not run or did not publish coverage evidence.

Changed-File Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Changed file (3 files)"]
  S1 --> I1["repository behavior"]
  I1 --> R1["Review risk: Changed file (3 files)"]
  R1 --> V1["required checks"]
  Evidence --> S2["Test (3 files)"]
  S2 --> I2["regression suite"]
  I2 --> R2["Review risk: Test (3 files)"]
  R2 --> V2["targeted test run"]
Loading

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

OpenCode cannot approve yet because required coverage evidence did not pass.

Review outcome

1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence

  • Problem: The required coverage-evidence job result was failure, so OpenCode cannot establish approval sufficiency for this head.

  • Root cause: Automated approval is only valid when the same-head coverage-evidence job proves supported repository test suites passed and configured docstring gates passed or were advisory, or reports not applicable because no supported source files or package manifests exist. Missing, failed, skipped, unavailable, or unsupported-tooling test evidence is a blocker.

  • Fix: Install or configure the repository test/docstring evidence tooling when source files or package manifests exist, rerun the current-head coverage-evidence job, and approve only after it reports success with required evidence or explicit no-source not-applicable evidence.

  • Regression test: Keep the approval branch checking needs.coverage-evidence.result == success before posting APPROVE, and publish REQUEST_CHANGES when coverage-evidence blocker states such as cancelled, skipped, failed, unsupported-tooling, or below-100 evidence are present.

  • Result: REQUEST_CHANGES

  • Reason: coverage-evidence result was failure, so required test/docstring evidence was not proven for current head 7a46834dde5d3ea2334af7e55aea4cf9075120de.

  • Head SHA: 7a46834dde5d3ea2334af7e55aea4cf9075120de

  • Workflow run: 31952563982

  • Workflow attempt: 1

Coverage evidence

Coverage evidence job did not run or did not publish coverage evidence.

Changed-File Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Changed file (3 files)"]
  S1 --> I1["repository behavior"]
  I1 --> R1["Review risk: Changed file (3 files)"]
  R1 --> V1["required checks"]
  Evidence --> S2["Test (3 files)"]
  S2 --> I2["regression suite"]
  I2 --> R2["Review risk: Test (3 files)"]
  R2 --> V2["targeted test run"]
Loading

@cursor

cursor Bot commented Aug 17, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

💡 What
- 외부 링크에 새 탭 열림 안내(`aria-label`) 추가
- 상세 창 닫기 버튼 포커스 복원 동작 분리 (접근성 향상)
- 검색 필터 취소 버튼 시각적 분리 (.clear-btn)
- 비동기 로딩 스캔 행(`aria-busy`)의 커서 상태(`wait`, `pointer-events: none`) 추가
- 버튼 호버 시 밝기 변화 효과 추가

🎯 Why
- 링크 열림 시 시각장애인 사용자의 문맥 손실을 방지합니다.
- 키보드 네비게이션 사용자가 닫기 버튼에 쉽게 접근하고 원래 위치로 되돌아올 수 있도록 돕습니다.
- 활성/비활성 컴포넌트의 상태를 명확히 하여 상호작용 피드백을 향상시킵니다.

📸 Before/After
- 이전: 호버 피드백 및 로딩 피드백 부재. 스크린 리더 안내 부족
- 이후: 동적 인터랙션 및 스크린 리더 접근성 완비

♿ Accessibility
- 링크 열림 문맥 제공 (`aria-label`)
- 키보드 포커스 흐름 보완
- Loading/Wait 상태 시각화
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: ui-ux Frontend, interaction, design, or user experience bug Something isn't working priority: critical Immediate blocker, P0, urgent deadlock, or critical incident priority: medium Normal-priority or P2 work scope: product-gap Customer-visible product gap status: draft Draft pull request type: bug Defect or incorrect behavior

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

1 participant