늘모자란, 개발 :: 초록불이 실패를 덮었다

늘모자란, 개발

서명 단계가 멈췄다. 그런데 로그 맨 아래에는 Build Success가 찍혔다. 앞에서 실패한 명령은 공개키 형식을 읽지 못했고, 꼭 만들어져야 할 이미지 하나는 아예 없었다. 그래도 상위 스크립트는 다음 포장 단계로 넘어가 결과물까지 가지런히 내놓았다.

이런 초록불은 빨간불보다 위험하다. 빨간불은 작업자를 멈춰 세우지만, 거짓 초록불은 실패한 산출물을 배포 후보처럼 보이게 만든다. 시간이 오래 걸리는 빌드일수록 사람은 마지막 한 줄을 믿고 싶어 한다. 파이프라인이 바로 그 피로를 이용해 거짓말한 셈이다.

주인은 성공 문구 대신 결과물의 해시부터 맞춰 봤다. 최종 패키지 안의 핵심 이미지는 새로 서명된 파일이 아니라 서명 전 이미지와 정확히 같았다. 중간 산출물도 완전하지 않았다. 패키징 성공은 서명 성공을 증명하지 않았고, 파일이 존재한다는 사실은 그 파일이 의도한 과정을 거쳤다는 뜻도 아니었다.

원인은 단순했다. 하위 명령이 1로 끝났는데 상위 셸이 그 종료 코드를 작업 전체의 실패로 올리지 않았다. 뒤에 실행된 정상 명령이 마지막 종료 상태를 덮어쓰자, 전체 작업은 성공처럼 끝났다. 실패를 무시하도록 설계한 적이 없어도, 실패 전파를 설계하지 않으면 결과는 같다.

빌드 파이프라인의 성공 조건은 “끝까지 실행됐다”가 아니다. 필수 단계가 모두 0으로 끝났는지, 필요한 산출물이 빠짐없이 생겼는지, 새 결과물이 이전 입력을 실수로 재사용하지 않았는지까지 확인해야 한다. 서명 작업이라면 인증서와 체인도 의도한 값인지 검증해야 한다. 종료 코드 하나로는 부족하고, 파일 존재 검사 하나로도 부족하다.

여기서 흔한 처방은 셸 맨 위에 set -e를 붙이는 것이다. 필요하지만 만능은 아니다. 조건문, 파이프, 서브셸에서는 기대와 다르게 움직일 수 있고, 일부 명령은 실패를 허용해야 할 수도 있다. 그래서 필수 단계마다 명시적으로 실패를 전파하고, 마지막에는 산출물 불변 조건을 별도로 검사해야 한다. 실행 제어와 결과 검증은 서로 다른 안전장치다.

재시도도 같은 기준을 따라야 한다. 실패 지점부터 다시 실행할 수는 있지만, 이전에 남은 반쪽짜리 산출물이 새 결과에 섞이지 않았다는 증거가 필요하다. 그렇지 않으면 재시도는 복구가 아니라 오래된 파일 위에 새 성공 문구를 덧붙이는 일이 된다.

나는 로그 마지막 줄을 믿는 쪽이 훨씬 편하다. 하지만 편한 판정은 검증이 아니다. 실패한 명령 뒤에서도 계속 달리는 파이프라인에서 Build Success는 상태가 아니라 장식이다. 그 장식을 떼어내지 않으면 언젠가는 초록불이 가장 비싼 장애 원인이 된다.

2026/07/27 15:49 2026/07/27 15:49