증상
100줄 넘는 파일을 cat > 파일 <<'EOF' 블록으로 채팅에 내보내고, 운영자가 SSH 세션에 붙여넣었다. 라이브가 문법이 깨진 파일로 덮여 그 경로를 지나는 호출이 통째로 죽는다. 01장의 heredoc 이모지 항목은 인코딩 층이고, 이건 붙여넣기 자체가 개행과 EOF를 깨는 층이다.
원인
붙여넣기는 파일 복사가 아니다.
해법 — 받아서, 검사하고, 원자 교체
cp app.php app.php.bak.$(date +%F-%H%M) # 1) 백업 선행
curl -fsSL -H "Authorization: token $TOKEN" \
-H "Accept: application/vnd.github.raw" \
"https://api.github.com/repos/<org>/<repo>/contents/<path>?ref=main" \
-o app.php.new # 2) raw+토큰으로 .new에 받기
php -l app.php.new # 3) 문법검사 통과해야만
mv app.php.new app.php # 4) mv = 원자 교체
.new에 받는 이유: 다운로드가 중간에 끊겨도 현행 파일이 멀쩡하다.mv인 이유: 같은 파일시스템에서 원자적이라 반쪽 파일이 서비스되는 순간이 없다. 롤백은 .bak을 mv로 되돌린다.같은 뿌리의 2차 사고 — 대체본이 비밀 로딩을 발명했다
heredoc 사고를 수습하며 올린 대체본이 또 죽였다. 이번엔 문법이 아니라 키다. 대체본은 키를 getenv()로 읽게 썼는데, 원본은 docroot 상위의 비밀 파일에서 읽고 있었다. 공유 호스팅 PHP는 셸 export를 보지 못한다 — SSH에서 넣은 환경변수는 웹 요청 프로세스에 없다.
"현행 파일을 못 봐서 프로토콜 계약대로 새로 썼다"가 사각이었다. 요청·응답 형태는 문서에 있었지만 비밀 로딩·경로·부수 로직은 계약 밖이라, 그 빈칸을 그럴듯하게 채워 넣었다. 그럴듯한 건 발명이다.
grep -n 'getenv\|secret' <파일> 한 줄을 요청한다. 실측이 불가능하면 그 부분은 비워 두고 명시한다.검증
php -l 통과 + 키 로딩 방식이 원본과 같은지 grep 대조 + 라이브 실호출 1회에서 인증까지 통과하는 응답을 본다.
★ 전달 수단도 설계의 일부다. 내용이 맞아도 옮기는 방법이 틀리면 라이브가 깨진다. "채팅에 전문 출력"은 사람이 읽으라는 뜻이지 기계가 받아 쓰라는 뜻이 아니다 — 기계가 받을 것은 링크와 검증 절차다. 백업 선행은 비용이 아니라 보험이다.