Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,7 @@
**Root cause:** The protected implementation added canonical names to the exclusion set but did not compare each observed directory entry through a locale-stable normalized key.
**Prevention:** Build one `Locale.ROOT` lowercase set from the canonical sensitive names, compare every observed name against it, and add the original spelling to the exclusion set so downstream exact membership remains correct.
**Evidence:** `testProcessIgnoreFileTreatsSensitiveNamesCaseInsensitively` failed on test-only commit `472b916cd40f70693c4e1eb48956042a25353feb` (CI run `31469596932`) and passed with the source fix at `bb113d858ccfc42ddaecf6729749b238e5ade2d0` (CI run `31469921661`).
## 2024-05-24 - μž„μ‹œ 파일 생성 μ‹œ μ•ˆμ „ν•œ κΆŒν•œ(0644) λͺ…μ‹œμ  μ„€μ •
**Vulnerability:** JVM의 κΈ°λ³Έ `Files.createTempFile()`은 `0600` κΆŒν•œμœΌλ‘œ νŒŒμΌμ„ μƒμ„±ν•˜λ©°, 파일 이동 후에도 이 κΆŒν•œμ΄ μœ μ§€λ˜μ–΄ μ›Ή μ„œλ²„κ°€ νŒŒμΌμ„ 읽지 λͺ»ν•΄ `403 Forbidden` 였λ₯˜(κ°€μš©μ„± μΉ¨ν•΄)κ°€ λ°œμƒν•  수 μžˆμŠ΅λ‹ˆλ‹€.
**Learning:** μ›Ή μ„œλΉ„μŠ€μ—μ„œ 제곡될 μž„μ‹œ νŒŒμΌμ„ 생성할 λ•ŒλŠ” κΈ°λ³Έ κΆŒν•œμ— μ˜μ‘΄ν•˜μ§€ μ•Šκ³ , λͺ…μ‹œμ μœΌλ‘œ POSIX κΆŒν•œ(예: `rw-r--r--`)을 λΆ€μ—¬ν•΄μ•Ό ν•©λ‹ˆλ‹€.
**Prevention:** ν”Œλž«νΌ 독립적인 100% ν…ŒμŠ€νŠΈ 컀버리지λ₯Ό λ‹¬μ„±ν•˜κΈ° μœ„ν•΄ OS 의쑴적인 μ½”λ“œλŠ” `supportsPosix`와 같은 Boolean νŒŒλΌλ―Έν„°λ‘œ μΆ”μƒν™”ν•˜κ³  λŒ€μ²΄ κ²½λ‘œμ— λŒ€ν•œ ν…ŒμŠ€νŠΈλ₯Ό μž‘μ„±ν•΄μ•Ό ν•©λ‹ˆλ‹€.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,4 @@ All notable changes to this project are documented in this file.
and current W3C Working Draft reference in `docs/doctoring`.
- Record the generated-index readability decision, WCAG 2.2 engineering basis,
contrast calculations, scope boundaries, and verification contract.
- λ³΄μ•ˆ μˆ˜μ •: μž„μ‹œ 파일 생성 μ‹œ 403 Forbidden 였λ₯˜λ₯Ό λ°©μ§€ν•˜κΈ° μœ„ν•΄ 파일 κΆŒν•œμ„ 0644둜 μ„€μ •ν•˜λ„λ‘ λ³€κ²½
15 changes: 14 additions & 1 deletion src/main/kotlin/html4tree/main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import java.nio.file.Files
import java.nio.file.LinkOption
import java.nio.file.StandardCopyOption
import java.nio.file.attribute.BasicFileAttributes
import java.nio.file.attribute.PosixFilePermissions
import java.util.Base64
import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.parameters.options.option
Expand Down Expand Up @@ -370,6 +371,7 @@ fun process_ignore_file(curr_dir: File, dirFilesNames: Array<String>? = null): S
fun write_index_file(
curr_dir: File,
content: String,
supportsPosix: Boolean = java.nio.file.FileSystems.getDefault().supportedFileAttributeViews().contains("posix"),
moveFile: (
java.nio.file.Path,
java.nio.file.Path,
Expand All @@ -380,7 +382,18 @@ fun write_index_file(
}
) {
val indexPath = curr_dir.toPath().resolve("index.html")
val tempPath = Files.createTempFile(curr_dir.toPath(), ".index-", ".html")
// λ³΄μ•ˆ ν–₯상: μž„μ‹œ 파일이 μ›Ή μ„œλ²„μ— μ˜ν•΄ 제곡될 λ•Œ 403 Forbidden 였λ₯˜κ°€ λ°œμƒν•˜λŠ” 것을 λ°©μ§€ν•˜κΈ° μœ„ν•΄,
// JVM κΈ°λ³Έ μž„μ‹œ 파일 κΆŒν•œ(0600) λŒ€μ‹  μ „μ—­ 읽기 κ°€λŠ₯ κΆŒν•œ(0644)을 λͺ…μ‹œμ μœΌλ‘œ μ„€μ •ν•©λ‹ˆλ‹€.
val tempPath = if (supportsPosix) {
Files.createTempFile(
curr_dir.toPath(),
".index-",
".html",
PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rw-r--r--"))
)
} else {
Files.createTempFile(curr_dir.toPath(), ".index-", ".html")
}
try {
Files.write(tempPath, content.toByteArray(Charsets.UTF_8))
try {
Expand Down
8 changes: 8 additions & 0 deletions src/test/kotlin/html4tree/MainTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,14 @@ class MainTest {
)
}

@Test
fun testWriteIndexFileWithoutPosixSupport() {
val indexFile = File(tempDir, "index.html")
write_index_file(tempDir, "content without posix", supportsPosix = false)
assertTrue(indexFile.exists())
assertEquals("content without posix", indexFile.readText())
}

@Test
fun testWriteIndexFileCleansUpTempFileOnFailure() {
// Files.move cannot replace a non-empty directory, so this drives the
Expand Down
Loading