From aed94fa5442812ff3da843fa3d7abcdf5d346a89 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 27 Sep 2026 19:01:09 +0000 Subject: [PATCH 01/11] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EC=99=B8?= =?UTF-8?q?=EB=B6=80=20=EB=A7=81=ED=81=AC=20=EC=83=88=20=EC=B0=BD=20?= =?UTF-8?q?=EC=97=B4=EB=A6=BC(target=3D"=5Fblank")=20=EC=9B=B9=20=EC=A0=91?= =?UTF-8?q?=EA=B7=BC=EC=84=B1=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .jules/palette.md | 4 ++++ scanner/dashboard/index.html | 2 +- tests/test_dashboard_core.py | 6 ++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.jules/palette.md b/.jules/palette.md index ea004e2d2..be75988f2 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -81,3 +81,7 @@ ## 2026-08-12 - Skip to Content Accessibility **Learning:** Screen reader and keyboard-only users experience significant friction when forced to navigate through repetitive header controls on every page load. **Action:** Keep a visible-on-focus skip link as the first interactive element, target a programmatically focusable main container, and give the focused link a high-contrast outline. + +## 2026-09-02 - target=_blank external link accessibility +**Learning:** Links opening in a new tab without context are inaccessible. Users using screen readers may not realize they have opened a new tab and lose the navigation history. Using an English-only `aria-label` override breaks translations. +**Action:** When creating `target="_blank"` external links, add an assistive-technology warning via `.sr-only` text and a visible indicator (like an `aria-hidden` icon) inside the anchor tag to ensure WCAG compliance and preserve localization logic. diff --git a/scanner/dashboard/index.html b/scanner/dashboard/index.html index 132bc31b2..24cbdf36d 100644 --- a/scanner/dashboard/index.html +++ b/scanner/dashboard/index.html @@ -281,7 +281,7 @@

Dashboard

function openDetail(f){ lastFocus = document.activeElement; const s = String(f.severity||'INFO').toUpperCase(); - const refs = (f.references||[]).map(r=>`${esc(r)}`).join('
'); + const refs = (f.references||[]).map(r=>`${esc(r)} (opens in a new tab)`).join('
'); const owasp = (f.owasp||[]).join(', '); const cwe = (f.cwe||[]).join(', '); const d = document.getElementById('detail'); diff --git a/tests/test_dashboard_core.py b/tests/test_dashboard_core.py index 75a5809f8..597203ea1 100644 --- a/tests/test_dashboard_core.py +++ b/tests/test_dashboard_core.py @@ -302,3 +302,9 @@ def test_dashboard_search_escape_clears_input(): assert "e.key === 'Escape'" in html assert "query = '';" in html assert "render();" in html + +def test_dashboard_external_links_have_a11y_warnings(): + """External links with target=_blank must warn screen readers and visual users.""" + html = dashboard_index_path().read_text(encoding="utf-8") + assert '(opens in a new tab)' in html + assert '' in html From 3e95c23e00e63861d42784eed92334dd8cd743a9 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:23:28 +0000 Subject: [PATCH 02/11] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EC=99=B8?= =?UTF-8?q?=EB=B6=80=20=EB=A7=81=ED=81=AC=20=EC=83=88=20=EC=B0=BD=20?= =?UTF-8?q?=EC=97=B4=EB=A6=BC(target=3D"=5Fblank")=20=EC=9B=B9=20=EC=A0=91?= =?UTF-8?q?=EA=B7=BC=EC=84=B1=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From 7d15f73ea75f91cc77889486d41ce8185fcbd262 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 27 Sep 2026 23:31:50 +0000 Subject: [PATCH 03/11] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EC=99=B8?= =?UTF-8?q?=EB=B6=80=20=EB=A7=81=ED=81=AC=20=EC=83=88=20=EC=B0=BD=20?= =?UTF-8?q?=EC=97=B4=EB=A6=BC(target=3D"=5Fblank")=20=EC=9B=B9=20=EC=A0=91?= =?UTF-8?q?=EA=B7=BC=EC=84=B1=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From fc6f7e477ea9f5a24bb83b0307025b9f8b023c4d Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Mon, 28 Sep 2026 02:13:06 +0000 Subject: [PATCH 04/11] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EC=99=B8?= =?UTF-8?q?=EB=B6=80=20=EB=A7=81=ED=81=AC=20=EC=83=88=20=EC=B0=BD=20?= =?UTF-8?q?=EC=97=B4=EB=A6=BC(target=3D"=5Fblank")=20=EC=9B=B9=20=EC=A0=91?= =?UTF-8?q?=EA=B7=BC=EC=84=B1=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From be18d56f400da4b45c427c3bd45d1491a9832a2e Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Mon, 28 Sep 2026 13:27:12 +0000 Subject: [PATCH 05/11] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EC=99=B8?= =?UTF-8?q?=EB=B6=80=20=EB=A7=81=ED=81=AC=20=EC=83=88=20=EC=B0=BD=20?= =?UTF-8?q?=EC=97=B4=EB=A6=BC(target=3D"=5Fblank")=20=EC=9B=B9=20=EC=A0=91?= =?UTF-8?q?=EA=B7=BC=EC=84=B1=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From 07374318849eaa3b1be815af561b5ced346133de Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Mon, 28 Sep 2026 20:05:50 +0000 Subject: [PATCH 06/11] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EC=99=B8?= =?UTF-8?q?=EB=B6=80=20=EB=A7=81=ED=81=AC=20=EC=83=88=20=EC=B0=BD=20?= =?UTF-8?q?=EC=97=B4=EB=A6=BC(target=3D"=5Fblank")=20=EC=9B=B9=20=EC=A0=91?= =?UTF-8?q?=EA=B7=BC=EC=84=B1=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From 6c6c990be6bde459fc394745808965454afe1658 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Tue, 29 Sep 2026 04:22:58 +0000 Subject: [PATCH 07/11] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EC=99=B8?= =?UTF-8?q?=EB=B6=80=20=EB=A7=81=ED=81=AC=20=EC=83=88=20=EC=B0=BD=20?= =?UTF-8?q?=EC=97=B4=EB=A6=BC(target=3D"=5Fblank")=20=EC=9B=B9=20=EC=A0=91?= =?UTF-8?q?=EA=B7=BC=EC=84=B1=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From ab76202cbb00c913a3ae2e0b817b144ca193c432 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Wed, 30 Sep 2026 05:31:25 +0000 Subject: [PATCH 08/11] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EC=99=B8?= =?UTF-8?q?=EB=B6=80=20=EB=A7=81=ED=81=AC=20=EC=83=88=20=EC=B0=BD=20?= =?UTF-8?q?=EC=97=B4=EB=A6=BC(target=3D"=5Fblank")=20=EC=9B=B9=20=EC=A0=91?= =?UTF-8?q?=EA=B7=BC=EC=84=B1=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From b12542fb7381456fafeb6c9f1728c460a2035a28 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 3 Oct 2026 17:56:46 +0900 Subject: [PATCH 09/11] chore: retire duplicate .jules/palette.md delta in favor of #1361 --- .jules/palette.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.jules/palette.md b/.jules/palette.md index be75988f2..ea004e2d2 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -81,7 +81,3 @@ ## 2026-08-12 - Skip to Content Accessibility **Learning:** Screen reader and keyboard-only users experience significant friction when forced to navigate through repetitive header controls on every page load. **Action:** Keep a visible-on-focus skip link as the first interactive element, target a programmatically focusable main container, and give the focused link a high-contrast outline. - -## 2026-09-02 - target=_blank external link accessibility -**Learning:** Links opening in a new tab without context are inaccessible. Users using screen readers may not realize they have opened a new tab and lose the navigation history. Using an English-only `aria-label` override breaks translations. -**Action:** When creating `target="_blank"` external links, add an assistive-technology warning via `.sr-only` text and a visible indicator (like an `aria-hidden` icon) inside the anchor tag to ensure WCAG compliance and preserve localization logic. From 9b559723732cda77e71b43028dc22874ff6171fe Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 3 Oct 2026 17:56:48 +0900 Subject: [PATCH 10/11] chore: retire duplicate scanner/dashboard/index.html delta in favor of #1361 --- scanner/dashboard/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scanner/dashboard/index.html b/scanner/dashboard/index.html index 24cbdf36d..132bc31b2 100644 --- a/scanner/dashboard/index.html +++ b/scanner/dashboard/index.html @@ -281,7 +281,7 @@

Dashboard

function openDetail(f){ lastFocus = document.activeElement; const s = String(f.severity||'INFO').toUpperCase(); - const refs = (f.references||[]).map(r=>`${esc(r)} (opens in a new tab)`).join('
'); + const refs = (f.references||[]).map(r=>`${esc(r)}`).join('
'); const owasp = (f.owasp||[]).join(', '); const cwe = (f.cwe||[]).join(', '); const d = document.getElementById('detail'); From 63c4a40618a7bfa4ccead6d948de0c593e6fafd1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 3 Oct 2026 17:56:50 +0900 Subject: [PATCH 11/11] chore: retire duplicate tests/test_dashboard_core.py delta in favor of #1361 --- tests/test_dashboard_core.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/test_dashboard_core.py b/tests/test_dashboard_core.py index 597203ea1..75a5809f8 100644 --- a/tests/test_dashboard_core.py +++ b/tests/test_dashboard_core.py @@ -302,9 +302,3 @@ def test_dashboard_search_escape_clears_input(): assert "e.key === 'Escape'" in html assert "query = '';" in html assert "render();" in html - -def test_dashboard_external_links_have_a11y_warnings(): - """External links with target=_blank must warn screen readers and visual users.""" - html = dashboard_index_path().read_text(encoding="utf-8") - assert '(opens in a new tab)' in html - assert '' in html