Skip to content

Improve security, accessibility, performance, and test coverage#4

Open
seonghobae wants to merge 76 commits into
yencarnacion:masterfrom
ContextualWisdomLab:master
Open

Improve security, accessibility, performance, and test coverage#4
seonghobae wants to merge 76 commits into
yencarnacion:masterfrom
ContextualWisdomLab:master

Conversation

@seonghobae

@seonghobae seonghobae commented Jul 7, 2026

Copy link
Copy Markdown

Overview

This PR improves html4tree so generated directory indexes are safer, more accessible, easier to validate, and more robust for real-world filenames.

What changed

  • Hardened traversal against symlink-based path traversal by using NOFOLLOW_LINKS checks for the top directory and child directory traversal.
  • Prevented index.html symlink overwrite issues by writing to a temporary file and then replacing the generated index atomically.
  • Escaped directory and file names before inserting them into generated HTML to reduce XSS risk.
  • Reworked escapeHtml() from chained replace() calls to a single-pass, lazily allocated StringBuilder implementation to reduce intermediate string allocations.
  • URL-encoded generated href paths so spaces, slashes, and non-ASCII filenames are handled more reliably.
  • Improved .html4ignore handling by compiling valid regex patterns once, ignoring empty lines, and skipping invalid regexes without aborting the whole directory render.
  • Improved generated HTML accessibility and UX with lang, charset, viewport, main, nav, aria-label, empty-directory feedback, and focus/hover styles.
  • Added Kotlin/JUnit tests and JaCoCo verification for traversal behavior, ignore-file handling, HTML escaping, URL encoding, max-depth behavior, and symlink protections.

CodeGraph review

I used colbymchenry/codegraph to index the current code and confirm the main impact paths:

  • go() -> process_dir() -> process_ignore_file()
  • process_dir() -> escapeHtml() / urlEncodePath() / write_index_file()
  • Regression coverage is concentrated in MainTest.kt and UtilTest.kt.

Validation

JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 ./gradlew test

Result: BUILD SUCCESSFUL

Related fork PRs

The ContextualWisdomLab fork first merged the currently valid, mergeable improvements that had already passed review and required checks:

seonghobae and others added 23 commits June 21, 2026 15:36
…vement-17389468144540365696

🎨 Palette: [모바일 대응 및 접근성 개선] 생성되는 HTML의 UX 향상
Merged after central .github required workflows completed and OpenCode approved the current head.
Merged after resolving conflicts, addressing Strix findings, passing Gradle tests, and receiving central OpenCode approval.
Merged after resolving conflicts with current accessibility structure, passing Gradle tests, and receiving central OpenCode approval.
Merged after updating against current master, passing Gradle tests, and receiving central OpenCode approval.
Merged after combining symlink traversal protections with current safe-write behavior, passing Gradle tests, and receiving central OpenCode approval.
Merged after resolving conflicts with current master, preserving prior symlink traversal protections and adding the maxLevel enqueue guard from PR #28.

Verified with JDK 11 Gradle tests and required current-head OpenCode approval.
Merged after refreshing against current master and combining decorative-icon aria-hidden spans with the existing semantic landmark, aria-label, and symlink-safe generator changes.

Verified with JDK 11 Gradle tests and required current-head OpenCode approval.
Merged after refreshing against current master and preserving the existing accessibility, performance, and symlink protections. Adds a CSP meta tag for generated HTML as defense-in-depth.

Verified with JDK 11 Gradle tests and required current-head OpenCode approval.
Merged after resolving conflicts with current master and removing a brittle internal coverage test. Adds a helpful empty-directory message to generated listings.

Verified with JDK 11 Gradle tests and required current-head OpenCode approval.
canonicalFile로 인해 심볼릭 링크 제한 검사가 무력화되는 문제를 absoluteFile.toPath().normalize().toFile()로 교체하여 정상화했습니다.

Co-authored-by: seonghobae <8172694+seonghobae@users.noreply.github.com>
* ⚡ Bolt: escapeHtml 성능 최적화 (단일 루프 및 StringBuilder 사용)

* ⚡ Bolt: escapeHtml 성능 최적화 (단일 루프 및 StringBuilder 사용)

기존의 연쇄적인 `.replace()` 호출은 각 치환 단계마다 새로운 중간 문자열을 메모리에 할당하여 쓰레기 수집(Garbage Collection) 및 CPU 부하를 발생시키는 주요 성능 병목이었습니다. 단일 루프 방식은 한 번의 순회만으로 치환을 수행하며, 문자열 수정이 필요할 때만 `StringBuilder`를 초기화하여 메모리 할당을 최소화합니다.

---------

Co-authored-by: seonghobae <8172694+seonghobae@users.noreply.github.com>
@seonghobae seonghobae changed the title 보안, 접근성, 성능 및 테스트 커버리지 개선 Improve security, accessibility, performance, and test coverage Jul 7, 2026
seonghobae and others added 6 commits July 7, 2026 20:57
루프 내에서 `byte.toString(16).padStart(2, '0').toUpperCase()`를 사용할 때 발생하는 불필요한 다중 중간 문자열 객체 할당을 방지하기 위해, 비트 연산 및 미리 정의된 16진수 문자 배열을 사용하여 `urlEncodePath()`의 인코딩 성능을 개선했습니다. 또한 인코딩이 필요 없는 문자열에 대해서는 `StringBuilder`를 초기화하지 않도록 지연 할당을 적용했습니다.
루프 내에서 `byte.toString(16).padStart(2, '0').toUpperCase()`를 사용할 때 발생하는 불필요한 다중 중간 문자열 객체 할당을 방지하기 위해, 비트 연산 및 미리 정의된 16진수 문자 배열을 사용하여 `urlEncodePath()`의 인코딩 성능을 개선했습니다. 또한 인코딩이 필요 없는 문자열에 대해서는 `StringBuilder`를 초기화하지 않도록 지연 할당을 적용했습니다.
루프 내에서 `byte.toString(16).padStart(2, '0').toUpperCase()`를 사용할 때 발생하는 불필요한 다중 중간 문자열 객체 할당을 방지하기 위해, 비트 연산 및 미리 정의된 16진수 문자 배열을 사용하여 `urlEncodePath()`의 인코딩 성능을 개선했습니다. 또한 인코딩이 필요 없는 문자열에 대해서는 `StringBuilder`를 초기화하지 않도록 지연 할당을 적용했습니다.
seonghobae and others added 30 commits July 11, 2026 13:58
Add a cross-agent "Agent guidance (CWL governance)" section covering the
central Security Scan gate (osv-scan, dependency-review, trivy-fs) and
CodeGraph-first code exploration, tailored to this Kotlin/Gradle repo.


Claude-Session: https://claude.ai/code/session_01RTAMs4bpSZS77Xe3RQjv9P

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: seonghobae <8172694+seonghobae@users.noreply.github.com>
- `process_ignore_file`에서 디렉토리 목록을 처리할 때 필터링 후 Set에 추가하는 목적이므로 순서가 중요하지 않음.
- 불필요한 `.sorted()` 호출을 제거하여 파일이 많은 디렉토리에서 발생하는 O(N log N) 시간 복잡도 오버헤드를 방지함.
- `bolt.md`의 기존 영문 로그들을 한국어로 번역하고, 해당 내용에 대한 새로운 학습 로그 추가.

Co-authored-by: seonghobae <8172694+seonghobae@users.noreply.github.com>
)

Co-authored-by: seonghobae <8172694+seonghobae@users.noreply.github.com>
Co-authored-by: seonghobae <8172694+seonghobae@users.noreply.github.com>
…e files (#156)

Co-authored-by: seonghobae <8172694+seonghobae@users.noreply.github.com>
불필요한 O(N * M) 정규식 매칭을 방지하기 위해 `process_ignore_file` 내부의 `ignored_matchers.forEach` 루프를 일반 `for` 루프와 `break`로 교체하여 조기 종료(Short-circuit)를 구현했습니다.

Co-authored-by: seonghobae <8172694+seonghobae@users.noreply.github.com>
…189919388320279490

🛡️ Sentinel: [보안] 정적 HTML CSP 강화 및 인라인 스타일 제거 (Nonce 기반 적용)
# Conflicts:
#	.jules/sentinel.md
#	src/main/kotlin/html4tree/main.kt
- `go` 함수의 디렉토리 탐색 루프에서 `listFiles()`를 한 번만 호출하고, 그 결과를 `process_dir` 및 `process_ignore_file`에 전달하도록 최적화.
- 불필요한 OS 레벨 파일 시스템 I/O를 제거하여 파일 트리가 깊거나 디렉토리가 클 때 성능 향상.
- 관련 테스트 업데이트 및 100% JaCoCo 커버리지 보장.
- `.jules/bolt.md`에 관련된 I/O 캐싱 학습 내용을 한국어로 기록함.

Co-authored-by: seonghobae <8172694+seonghobae@users.noreply.github.com>
- 디렉토리 및 파일 링크에 Flexbox 레이아웃을 적용하여 아이콘과 텍스트 영역 분리
- 긴 파일 이름이 아이콘 아래로 파고들어 자동 줄바꿈되는 현상(UX/UI 깨짐) 방지
- overflow-wrap: anywhere 속성을 적용하여 좁은 화면(모바일)에서도 가독성 유지

Co-authored-by: seonghobae <8172694+seonghobae@users.noreply.github.com>
- 디렉토리 인덱싱 시 제외되는 기본 민감한 파일 목록(defaultSensitiveFiles)에 클라우드 자격 증명 및 설정 파일(.aws, .kube, .npmrc, .gnupg, config.json, credentials.json 등) 추가
- HTTP Referer 헤더를 통한 로컬 디렉토리 경로 노출을 방지하기 위해 생성되는 HTML의 <head>에 <meta name="referrer" content="no-referrer"> 태그 추가
- 변경 사항에 맞춰 testProcessIgnoreFileNoIgnore 테스트 업데이트

Co-authored-by: seonghobae <8172694+seonghobae@users.noreply.github.com>
# Conflicts:
#	.jules/sentinel.md
#	src/main/kotlin/html4tree/main.kt
#	src/test/kotlin/html4tree/MainTest.kt
…files-exposure-10966133501192312716

🛡️ Sentinel: [HIGH] 숨겨진 파일 노출(Sensitive Data Exposure) 취약점 수정
이 커밋은 사용자가 일반 파일을 디렉토리나 메뉴 등으로 혼동하지 않도록 일반 파일의 아이콘을 화살표(우측 삼각형)에서 파일 아이콘(`&#128196;`)으로 교체하여 시각적 메타포를 개선합니다. 또한 프로젝트 요구 사항에 따라 모든 `.jules/palette.md`의 기존 내용을 한글로 번역하고 새로운 UX 개선 사항에 대한 로그를 추가했습니다.

Co-authored-by: seonghobae <8172694+seonghobae@users.noreply.github.com>
전환 효과와 모션 감소 미디어 쿼리 CSS는 PR #128로 이미 master에
반영되어, 본 PR은 해당 스타일이 회귀하지 않도록 검증하는 테스트만
master 기준으로 재구성했습니다.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…code-11250359961745319240

⚡ Bolt: urlEncodePath() 성능 최적화 (문자열 할당 오버헤드 제거)
시스템 폰트·행간·패딩은 PR #143으로 이미 master에 반영되어,
남은 개선분(넓은 화면에서의 가독성을 위한 main 요소 max-width
중앙 정렬, 라이트 모드 본문 색상 명시)만 master 기준으로
재구성했습니다. 다크 모드 색상은 기존 prefers-color-scheme
오버라이드가 그대로 우선합니다.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Git tracked both .Jules/palette.md and .jules/palette.md as separate
paths. On case-insensitive filesystems (Windows, default macOS) both
map to the same directory, so checkouts cross-contaminate the two
files and the worktree is perpetually dirty — git clone itself warns
about the colliding paths.

Merge the two entries unique to .Jules/palette.md (2024-05-24 CSS
transitions / prefers-reduced-motion, 2024-07-10 dark mode / nav
label localization) into .jules/palette.md, and remove the uppercase
path so only the lowercase .jules/ directory remains tracked.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* 🛡️ Sentinel: [MEDIUM] Fix Information Disclosure (Hidden files)

디렉토리 목록 생성 시 민감한 정보(예: .env, .git)가 포함된 숨김 파일이 노출되는 취약점을 방지하기 위해 파일 제외 로직을 수정했습니다.

* 🛡️ Sentinel: [MEDIUM] Fix Information Disclosure (Hidden files)

디렉토리 목록 생성 시 민감한 정보(예: .env, .git)가 포함된 숨김 파일이 노출되는 취약점을 방지하기 위해 파일 제외 로직을 수정했습니다.

* Restore master merge state (2840486); undo stale agent workspace replay

The previous commit replayed the pre-merge workspace tree, discarding the
origin/master merge (including CI workflows and the combined hidden-file
exclusion). The hidden-file security fix and its regression test are already
present in the merged tree.

* 🛡️ Sentinel: [MEDIUM] Fix Information Disclosure (Hidden files)

디렉토리 목록 생성 시 민감한 정보(예: .env, .git)가 포함된 숨김 파일이 노출되는 취약점을 방지하기 위해 파일 제외 로직을 수정했습니다.

* Restore dynamic hidden-file exclusion and its regression test

The prior commit removed the dynamic dotfile exclusion from
process_ignore_file, leaving only the static sensitive-name list. That
re-opens the vulnerability this PR fixes: hidden files not on the static
list (e.g. .netrc, .git-credentials, arbitrary .secret files) would be
listed again. Also restores testProcessIgnoreFileHiddenFiles using
.myhidden/.hiddendir, which are not on the static list, so the test fails
if the dynamic exclusion is removed; the replacement test used .env/.git,
which the static list already covers, so it could not catch the removal.

---------

Co-authored-by: seonghobae <8172694+seonghobae@users.noreply.github.com>
* 🎨 Palette: 링크 툴팁 추가

디렉토리 탐색기 인터페이스의 파일 및 디렉토리 아이콘 옆 링크와, `..` 상위 디렉토리 링크에 명시적인 `title` 속성을 추가하였습니다.

* 🎨 Palette: 링크 툴팁 추가

디렉토리 탐색기 인터페이스의 파일 및 디렉토리 아이콘 옆 링크와, `..` 상위 디렉토리 링크에 명시적인 `title` 속성을 추가하였습니다. 변경된 HTML 속성에 대한 테스트 코드(MainTest.kt) 단언문(assert)도 함께 추가하여 100% 테스트 커버리지를 유지하도록 개선했습니다.

* 🎨 Palette: 링크 툴팁 추가

디렉토리 탐색기 인터페이스의 파일 및 디렉토리 아이콘 옆 링크와, `..` 상위 디렉토리 링크에 명시적인 `title` 속성을 추가하였습니다. 변경된 HTML 속성에 대한 테스트 코드(MainTest.kt) 단언문(assert)도 함께 추가하여 100% 테스트 커버리지를 유지하도록 개선했습니다.

---------

Co-authored-by: seonghobae <8172694+seonghobae@users.noreply.github.com>
Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com>
`crawl_directories` 함수에서 파일의 제외 여부(`it.name !in exclude`)를 먼저 검사하도록 조건문 순서를 변경하여,
불필요한 OS 레벨의 파일 속성 확인(`Files.isDirectory` 및 `Files.isSymbolicLink`)을 최소화했습니다.

Co-authored-by: seonghobae <8172694+seonghobae@users.noreply.github.com>
* src/main/kotlin/html4tree/main.kt 파일의 HTML 헤더에 `<meta name="color-scheme" content="light dark">` 추가
* 생성된 HTML에서 시스템 테마에 맞는 네이티브 UI(스크롤바 등)가 일관되게 렌더링되도록 개선
* 관련 UX 개선 사항을 .jules/palette.md 파일에 한국어로 기록
* 테스트 커버리지 100% 유지 (MainTest.kt에 메타 태그 존재 여부 검증 추가)

Co-authored-by: seonghobae <8172694+seonghobae@users.noreply.github.com>
디렉토리 순회 시 파일의 종류(디렉토리 여부, 심볼릭 링크 여부)를 확인하기 위해
3번의 개별적인 OS 시스템 콜(`Files.isDirectory`, `it.isDirectory`, `Files.isSymbolicLink`)을
호출하던 것을 `Files.readAttributes` 단일 호출로 결합하여 I/O 비용을 줄였습니다.

예외 상황을 위한 단위 테스트도 추가하여 테스트 커버리지를 100%로 유지했습니다.

Co-authored-by: seonghobae <8172694+seonghobae@users.noreply.github.com>
Co-authored-by: seonghobae <8172694+seonghobae@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants