diff --git a/.jules/palette.md b/.jules/palette.md index 7b223901..9a12c9de 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -48,7 +48,3 @@ ## 2024-08-01 - 네이티브 브라우저 UI의 다크 모드 지원 강제 **학습:** CSS 미디어 쿼리(`@media (prefers-color-scheme: dark)`)를 통해 다크 모드를 지원하더라도, 브라우저의 네이티브 UI 요소(스크롤바, 기본 폼 컨트롤, 기본 백그라운드 등)는 테마 변경을 인식하지 못해 어두운 테마 환경에서 밝은 스크롤바가 표시되는 등 시각적 불일치를 초래합니다. **조치:** 항상 HTML 문서의 `` 영역에 `` 메타 태그를 명시적으로 추가하여 브라우저 수준에서 사용자의 시스템 테마(다크 모드 등)를 완전히 상속받아 일관성 있는 네이티브 UI를 렌더링하도록 보장하십시오. - -## 2024-07-13 - 빈 디렉토리 상태의 접근성(Accessibility) 개선 -**Learning:** 정적 파일 서버의 빈 디렉토리 상태는 스크린 리더 사용자에게 컨텐츠 누락으로 오해받을 수 있으며, 시각적으로도 일반 리스트 아이템과 정렬이 맞지 않는 문제가 있었습니다. -**Action:** 빈 상태를 나타내는 요소에 `role="status"`를 추가하여 스크린 리더가 명확하게 인지할 수 있도록 하고, 아이콘과 flex 레이아웃을 통해 다른 리스트 아이템과 일관된 시각적 흐름을 제공하도록 합니다. diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 6ecf72f1..ed55c325 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -83,3 +83,8 @@ **Vulnerability:** 정적 HTML 생성 도구에서 매번 다른 Nonce를 동적으로 생성하여 CSP에 적용하는 것은, 캐싱 효율을 저하시킬 뿐만 아니라 정적 배포 환경(예: GitHub Pages 등)에서 올바른 보안 정책 수립을 방해할 수 있는 안티 패턴입니다. **Learning:** 정적으로 고정된 인라인 스타일이나 스크립트에는 난수화된 Nonce보다 콘텐츠 자체의 해시(SHA-256 등)를 사용하는 것이 안전하고 일관된 방식임을 배웠습니다. **Prevention:** 자동 생성되는 정적 HTML의 콘텐츠 보안 정책(CSP)에는 `style-src 'sha256-'` 방식을 적용하고, ` } if(l.isEmpty()){ - l.append("""
  • 이 디렉토리는 비어 있습니다.
  • """) + l.append("""
  • 이 디렉토리는 비어 있습니다.
  • """) l.append('\n') } diff --git a/src/test/kotlin/html4tree/MainTest.kt b/src/test/kotlin/html4tree/MainTest.kt index 83739c9c..4bf28e94 100644 --- a/src/test/kotlin/html4tree/MainTest.kt +++ b/src/test/kotlin/html4tree/MainTest.kt @@ -7,7 +7,9 @@ import org.junit.Test import java.io.ByteArrayOutputStream import java.io.File import java.io.PrintStream +import java.nio.file.AtomicMoveNotSupportedException import java.nio.file.Files +import java.nio.file.StandardCopyOption import kotlin.test.assertEquals import kotlin.test.assertFailsWith import kotlin.test.assertFalse @@ -94,7 +96,6 @@ class MainTest { val htmlContent = indexFile.readText() assertTrue(htmlContent.contains("")) assertTrue(htmlContent.contains("이 디렉토리는 비어 있습니다.")) - assertTrue(htmlContent.contains("role=\"status\"")) assertTrue(htmlContent.contains("role=\"list\"")) } @@ -429,6 +430,22 @@ class MainTest { assertFalse(File(subsubdir, "index.html").exists()) } + @Test + fun testWriteIndexFileAtomicMoveNotSupported() { + val content = "test content" + var fallbackCalled = false + write_index_file(tempDir, content) { src, dest, options -> + if (options.contains(StandardCopyOption.ATOMIC_MOVE)) { + throw AtomicMoveNotSupportedException(src.toString(), dest.toString(), "Mocked exception") + } else { + fallbackCalled = true + Files.move(src, dest, *options) + } + } + assertTrue(fallbackCalled, "Fallback to REPLACE_EXISTING should have been called") + assertEquals(content, File(tempDir, "index.html").readText()) + } + @Test fun testGoIndexesNormalChildButSkipsSensitiveTraversal() { val subdir = File(tempDir, "subdir")