fix(core,cli): 원자적 쓰기 공용 경계로 통합해 skill 심볼릭 링크 관통 차단 - #82
Merged
Merged
Conversation
init은 PR #80에서 임시 파일+rename 교체로 심볼릭 링크 대상 오염을 막았지만 skill --install은 writeAsString이 링크를 따라가 신뢰할 수 없는 디렉터리의 링크 대상 파일(체크아웃 밖 경로 포함)을 그대로 덮어썼다. baseline 임시 이름도 PID만으로 예측 가능해 미리 심어둔 링크를 절단·관통할 수 있었다. - core/atomic_write.dart 신설: PID+무작위 접미사 임시 이름, 배타적 생성 (이미 존재하면 실패 — 심어둔 링크 관통 불가), rename 교체(대상 자리 링크는 링크 자체를 교체), 실패 시 임시 파일 정리 - init·skill·BaselineStore.write를 공용 경계로 이관해 정책 일원화 - skill 매달린 링크(--force 불필요 케이스)와 살아 있는 링크(--force)에 대한 CLI 회귀, init 링크 교체 회귀, AtomicWrite 단위 테스트 추가
This was referenced Sep 13, 2026
This was referenced Sep 13, 2026
Merged
ictechgy
pushed a commit
that referenced
this pull request
Sep 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
배경
전체 개선 검토(보안·성능·구조·기능·사용성)에서 확인된 최상위 보안 지적이다.
skill --install은File.writeAsString으로 대상에 직접 썼다. writeAsString은 심볼릭 링크를 따라가므로, 신뢰할 수 없는 체크아웃이<dir>/dartograph/SKILL.md를 git 심볼릭 링크로 심어둔 경우 링크 대상(체크아웃 밖 경로 포함)이 그대로 덮여썼진다. 링크 대상이 없으면--force없이도 발생했다.init과BaselineStore.write의 임시 파일 이름은.tmp.$pid로 예측 가능하고, 기존 내용물(심어둔 링크 포함)을 절단·관통했다. init만 PR #80의 rename 교체 정책이 있었고 baseline은finally정리, skill은 정책 자체가 없는 3박자였다.변경
lib/src/core/atomic_write.dart신설: PID+무작위 접미사(16 hex) 임시 이름,createSync(exclusive: true)로 배타적 생성(그 자리에 무엇이 있으면 실패 — 심어둔 링크 절단·관통 불가), rename 교체(대상 자리의 링크는 링크 자체를 교체), 실패 시 임시 정리는 best-effort로 원래 예외를 보존. 보장 경계(POSIX 전용 속성, 적극적 race 범위 밖, 부모 디렉터리 미생성)를 클래스 문서로 명시.Link(...).exists()를 추가해 매달린 링크도--force없이는 조용히 교체되지 않게 한다(init은 이미Link.existsSync()로 이를 검사).리뷰 반영 (GLM packet-review, 차단 0건)
검증
dart formatclean,dart analyzeclean, 전체 테스트 304개 통과(신규 6개 포함)tool/verify-false-positive-corpus.sh통과,tool/verify-cli-contract.sh통과dart pub publish --dry-run경고 0(clean git)