WSL cron 에서 git push 가 멈출 때 — GCM 은 GUI 인증기다
터미널에서는 되는 git push 가 cron 에서만 실패한다. 전역 credential helper 가 Windows GCM 이라 인증창을 띄울 수 없어서다. repo 단위로 gh 토큰 helper 를 붙여 해결한다.
WSL 에 cron 을 걸어 저장소를 자동으로 git push 하게 만들었다. 터미널에서 손으로 실행하면 잘 된다. cron 이 돌리면 실패하거나 그대로 멈춰 있다.
로그도 별 말이 없다. 인증 실패라는 힌트조차 잘 안 나온다. 원인을 찾으려면 credential helper 부터 봐야 한다.
원인 — helper 가 GUI 프로그램이다
$ git config --get credential.helper
/mnt/c/Program\ Files/Git/mingw64/bin/git-credential-manager.exe
전역 helper 가 Windows GCM(Git Credential Manager) 으로 잡혀 있었다. WSL 에서 Windows Git 을 같이 설치했다면 흔한 구성이다.
GCM 은 GUI 인증 매니저다. 자격 증명이 필요하면 창을 띄운다. cron 은 데몬 컨텍스트라 세션도 데스크톱도 없다. 창을 띄울 수 없으니 인증이 진행되지 않고, 그대로 실패하거나 응답을 기다리며 멈춘다.
~/.git-credentials 파일이라도 있으면 폴백이 되겠지만 GCM 을 쓰는 구성에서는 그것도 없다.
터미널에서 잘 되는 이유는 명확하다. 그때는 GUI 가 있고, 대개 이전에 인증한 캐시가 살아 있다.
해결 — 그 저장소만 gh 토큰으로
전역 GCM 은 그대로 두는 게 낫다. 손으로 작업할 때는 GCM 이 편하고, 다른 저장소에 영향을 주고 싶지 않다.
gh 가 로그인돼 있다면(gh auth status 로 확인) 그 토큰을 repo-local helper 로 붙일 수 있다.
cd <repo>
git config --local credential.helper "" # 상속된 GCM 리셋
git config --local --add credential.helper '!gh auth git-credential' # gh 토큰 helper 추가
두 줄인 이유가 있다. credential helper 설정은 누적된다. 빈 문자열을 먼저 넣지 않으면 전역 GCM 이 목록에 남아 있어서 여전히 먼저 호출된다. 빈 값이 목록을 초기화하고, 그다음 줄이 gh helper 하나만 남긴다.
gh auth git-credential 은 비인터랙티브다. 토큰을 ~/.config/gh/hosts.yml 에서 읽으므로 GUI 없이 인증이 끝난다.
cron 의 PATH 를 잊지 말 것
여기서 한 번 더 걸린다. cron 의 기본 PATH 는 대개 /usr/bin:/bin 뿐이다. gh 는 보통 ~/.local/bin/gh 에 있어서 cron 은 못 찾는다.
helper 를 못 찾으면 증상이 원점으로 돌아간 것처럼 보인다. 스크립트나 crontab 줄에서 PATH 를 보강한다.
export PATH="$HOME/.local/bin:/usr/local/bin:$PATH"
검증 — cron 환경을 흉내 내서 실제로 push 해본다
“이제 되겠지” 하고 cron 을 기다리면 다음 실행까지 확인이 늦어진다. env -i 로 환경변수를 비워 cron 과 같은 조건을 만들면 즉시 확인할 수 있다.
인증 핸드셰이크만 보려면 read 로 충분하다.
env -i HOME="$HOME" PATH="$HOME/.local/bin:/usr/bin:/bin" \
git -C <repo> ls-remote origin -h >/dev/null && echo AUTH_OK
실제 push 까지 확인하려면 커밋을 하나 만들고 다음을 실행한다. PATH 보강이 스크립트 안에서 이뤄지는 상황까지 그대로 재현한 형태다.
env -i HOME="$HOME" PATH="/usr/bin:/bin" \
bash -c 'export PATH="$HOME/.local/bin:$PATH"; git -C <repo> push'
여기서 성공하면 cron 에서도 성공한다. 반대로 여기서 멈춘다면 아직 GUI 를 부르고 있는 것이다.
env -i 없이 테스트하면 현재 셸의 PATH, SSH_AUTH_SOCK, GCM 캐시 같은 것들이 조용히 도와주기 때문에 통과해버린다. 이 검증의 가치는 도움을 전부 걷어내는 데 있다.
실제 적용
개인 설정 파일을 역동기화하는 저장소에 이 방식을 붙였다. 평일 16:30 에 도는 cron 이 변경분을 커밋하고 push 하는데, GCM 을 쓰던 시절에는 실행 기록만 남고 원격에는 아무것도 안 올라갔다. repo-local helper 로 바꾼 뒤로는 그냥 돈다.
정리
이 문제의 본질은 git 이 아니라 실행 컨텍스트다. 대화형 세션에서 통하던 인증 방법이 데몬 컨텍스트에서 통하지 않는다는 것. 같은 이유로 SSH 에이전트에 의존하는 설정도 cron 에서 같은 방식으로 무너진다.
전역 설정은 손으로 쓰기 편한 쪽으로 두고, 자동화가 도는 저장소에만 비인터랙티브 경로를 따로 깔아주는 게 충돌 없이 사는 방법이었다.