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")