etc

과거 실수들을 묻어버리자 - bfg repo cleaner

민사민서 2024. 8. 29. 14:01

https://github.com/rtyley/bfg-repo-cleaner

 

GitHub - rtyley/bfg-repo-cleaner: Removes large or troublesome blobs like git-filter-branch does, but faster. And written in Sca

Removes large or troublesome blobs like git-filter-branch does, but faster. And written in Scala - rtyley/bfg-repo-cleaner

github.com

https://rtyley.github.io/bfg-repo-cleaner/

 

BFG Repo-Cleaner by rtyley

$ bfg --strip-blobs-bigger-than 100M --replace-text banned.txt repo.git an alternative to git-filter-branch The BFG is a simpler, faster alternative to git-filter-branch for cleansing bad data out of your Git repository history: Removing Crazy Big Files Re

rtyley.github.io

 

실수로 github 나 gitlab 의 public 저장소에 큰 파일을 커밋했거나 암호나 SSH private key 같이 민감한 정보를 올린 경우 파일을 삭제하거나 commit history 를 정리해야 한다.
삭제하고 마스킹해서 새로운 커밋을 올려도 과거 커밋 (변경) 기록에는 남아있겠죠?

 

리포의 히스토리를 관리하는 툴에는 두 가지가 있다.

 

하나는 깃허브에서 공식적으로 제공하는 방법인 git filter-repo 이다.

다른 하나는 위의 툴을 대체하기 위한 bfg 이다.

⇒ 빠르고 사용하기 쉬운 장점, 그러나 강력하지는 않음 (번거롭지만 강력한 git-filter-branch 사용해도)

  • Removing Crazy Big Files
  • Removing PasswordsCredentials & other Private data

사용법

1. java jdk 설치

java -version

확인. 아무것도 안뜬다면 당신의 컴퓨터에는 자바가 없는 것입니다.

https://www.azul.com/downloads/?package=jdk#download-openjdk

위 사이트에서 jdk 다운로드. dmg 파일로 다운받으면 맥에서 쓰기 편리하더라고요

 

2. bfg.jar 다운로드

curl -o bfg.jar -L <https://repo1.maven.org/maven2/com/madgag/bfg/1.14.0/bfg-1.14.0.jar>

 

 

3. 레포를 --mirror 플래그로 클론해오기

git clone --mirror <my awesome repo.git>
  • normal file들은 보이지 않는 bare repo, full copy of Git DB of your repo
  • 로컬에 당연히 백업 만들어둬야 함

4. bfg 돌리기 (clean 하기)

java -jar bfg.jar --strip-blobs-bigger-than 100M haha.git
java -jar bfg.jar --delete-files id_{dsa, rsa} haha.git
java -jar bfg.jar --replace-text delete.txt haha.git
  • 크기가 큰 파일들을 커밋 히스토리에서 삭제할수도 있고
  • 특정 이름의 파일들을 히스토리에서 삭제할수도 있고
  • delete.txt 파일에 담긴 text들을 전부 ***REMOVED*** 로 마스킹할수도 있다 // ‘regex:’, ‘glob:’ prefix

아래처럼 delete.txt 를 구성하면 유출되면 안되는 url들을 커밋 히스토리에서 마스킹해버릴 수 있겠죠

regex:(rtsp:\\/\\/admin:[^@]+@) # delete.txt

어유 과거 커밋에서 얼마나 생각없이 url들을 사용했으면..

 

5. 남아있는 dirty data 삭제하기

cd haha.git
git reflog expire --expire=now --all && git gc --prune=now --aggressive
  • 4단계 진행하면 commit, branch, tag 등은 업데이트되었지만 실제 파일의 삭제나 변경은 아직 수행 안 됨
  • git-gc 이용해서 삭제

5. git push

git push
  • this push will update all refs on your remote server
  • repo의 old copy 가지고 있는 사람들은 fresh clone 수행하면 됨 (dirty history 남아있으므로)

이렇게 과거 커밋 히스토리를 봐도 지워져있네요!

 

트러블슈팅

1. repo의 branch rule 적용되어있을 때

당연하게 git push 가 막혀있습니다

잠깐 branch protection을 disable or delete 하고 진행하셔야 함

 

2. ! [remote rejected] (protected branch hook declined) 경고 메시지

push는 완료된거 같은데, 수많은 경고 메시지의 향연..

 

git for-each-ref --format="%(refname)" refs/pull/ | xargs -n 1 git update-ref -d

(편법) 위 커맨드를 사용해 refs/pull 참조들을 로컬 레포에서 전부 제거한 후 push하면 발생하지 않는다

 

쨌든 저 경고가 왜 발생하고 근본적인 원인은?

https://github.com/rtyley/bfg-repo-cleaner/issues/36

https://stackoverflow.com/questions/34265266/remote-rejected-errors-after-mirroring-a-git-repository

 

GitHub의 refs/pull/과 관련된 읽기 전용 참조들 때문이다.

이 참조들은 GitHub에서 자동으로 생성되며, Pull Request와 관련된 브랜치에 대한 참조를 포함한다

우리는 --mirror clone으로 전부 가져왔고 당연히 pull request 관련 참조들도 포함

⇒  refs/pull/ 참조들은 읽기 전용이기 때문에 사용자가 직접 수정하거나 삭제할 수 없음

       = GitHub에서 관리되며, 사용자 푸시 작업에서 수정이 거부됨

⇒ Pull Request와 관련된 참조들(refs/pull/)은 해당 Pull Request에서 사용된 커밋들을 가리킴

 

즉 BFG가 히스토리를 정리하여 민감한 정보를 제거하더라도, 해당 참조들에 의해 과거의 커밋 히스토리가 남아 있을 수 있다. 따라서, Pull Request 내에서 과거의 민감한 정보가 여전히 확인될 수 있다는 거 (!!!!!)

커밋 히스토리 보면 마스킹 잘 되어있어요
pull request 탭에 가서 file changed 탭을 확인해보면 고친 히스토리는 그대로 남아있음

 

 

그렇다면 pr history까지 없애려면 어케 하느냐

1. 레포를 새로 판다.. (거긴 pr 관련 read-only ref 가 없을테니)

 

2. contact github support and ask them to delete PRs

https://docs.github.com/ko/authentication/keeping-your-account-and-data-secure/removing-sensitive-data-from-a-repository

"해줘"

 

교훈: commit history는 흑역사 삭제 가능이지만 pr history는 쉽게 못지우니 .gitignore + 주요 정보 commit 전에 masking 꼭 하자..