모든 글
Silent Failures · 2분 읽기

조용히 실패하는 것들 7 — 검사가 초록인 것과 옳은 것은 다릅니다

출시 직전의 빌드에 구글 견본 광고 ID가 실려 있었습니다. 개발 중엔 광고가 멀쩡히 떠서 아무도 몰랐어요. 잡아 준 건 검사 스크립트였는데 — 그 검사도 절반만 세고 있었습니다.

#admob#광고#검사#자동화#출시

Pocket PDF에 구독을 붙이던 날, 보상형 광고 자리가 하나 새로 생겼습니다. 그리고 출시 빌드 직전에 발견했어요 — 그 자리가 이고 있던 광고 단위 ID가 구글이 문서에 적어 둔 견본 ID였다는 걸요.

ca-app-pub-3940256099942544/...   ← 구글의 테스트용 견본

견본 ID로 광고를 부르면 개발 중에는 멀쩡히 뜹니다. 그러라고 있는 ID니까요. 화면도 정상, 로그도 정상, 보상 지급도 정상. 그래서 조용합니다.

이대로 출시되면 어떻게 되냐면 — 수익이 0인 걸로 끝나지 않습니다. 실제 사용자에게 테스트 광고를 내보내는 건 AdMob 정책 위반이에요. 계정 경고나 정지로 이어질 수 있는 사고입니다. 광고가 안 뜨는 버그보다 광고가 잘 뜨는 이 상태가 훨씬 위험한 거죠.

잡은 건 검사였습니다 — 그런데

이걸 잡아 준 건 사람 눈이 아니라 admob-ids.sh라는 검사 스크립트였습니다. 저장소의 광고 ID들이 견본이 아닌지 세는 검사예요.

그런데 이 사건에서 제일 남는 건 그다음입니다. 그 검사도 절반만 세고 있었어요.

admob-ids.sh는 두 가지를 봅니다 — ‘견본인가’와 ‘비었는가’. 견본 검사에는 보상형 자리가 걸렸는데, 빈 값 검사의 목록에는 보상형이 없었습니다. 광고 자리를 새로 만들면서 검사 목록에는 더하지 않은 거예요.

검사가 초록이었다는 사실이 말해 주는 건 ‘검사한 것들이 통과했다’까지입니다. ‘검사 안 한 것이 없다’는 아무도 보증하지 않아요. 그리고 안 세고 있다는 사실 자체가 조용합니다 — 목록에 없는 자리는 실패조차 못 하니까요.

같은 병을 며칠 뒤에 한 번 더 봤습니다. 언어 파일의 열쇠 개수를 세는 strings-parity.sh는 내내 초록이었는데, 스페인어 자리에 영어 문장이 들어 있었어요. 열쇠만 세는 검사에게 값의 언어는 보이지 않습니다. 검사는 겨눈 것만 셉니다.

견본과 빈 값은 다릅니다

발견한 뒤의 처치도 적어 둘 만합니다. 실제 광고 단위는 아직 AdMob 콘솔에서 발급 전이었어요. 그럼 그 자리에 뭘 넣어 둘까요?

견본을 도로 넣는 건 답이 아닙니다. 방금 그게 사고였으니까요. 빈 값을 넣습니다.

  • 견본이 나가면: 정책 위반 사고
  • 빈 값이 나가면: 광고가 안 뜰 뿐

검사는 둘 다 빨갛게 잡습니다. 하지만 빨강이 하는 말이 달라져요. ‘견본을 들고 있다’(나가면 사고)에서 ‘아직 발급받지 못했다’(나가기 전에 채울 것)로요. 같은 빨강이라도 하나는 지뢰고 하나는 할 일 목록입니다.

준비 상태도 자리마다 따로 셌습니다. isRewardedReady를 배너의 isReady와 분리했어요 — 하나로 뭉치면 보상형이 비었다는 이유로, 실제 값을 멀쩡히 든 배너까지 함께 죽습니다.

같은 날, 같은 병 하나 더

같은 커밋에서 하나가 더 나왔는데, 결이 같아서 같이 적습니다.

PRO 기능을 여는 프로모션 코드에는 sha256 지문 검사가 붙어 있었습니다. 읽으면 단단해 보여요. 그런데 그 옆에 개발 중에 쓰던 평문 비교 넷이 ||로 나란히 서 있었습니다. 그중 하나가 "pro"였어요.

‘pro’ 한 단어로 PRO가 열렸습니다.

방어는 가장 약한 가지의 높이만큼만 섭니다 — ||로 이어진 조건에서는 특히요. 지문을 두고 그 옆에 평문을 적으면 지문이 하는 일이 없습니다. 자물쇠를 달아 놓고 열쇠를 문에 테이프로 붙여 둔 꼴인데, 코드만 보면 자물쇠가 먼저 보여요. 이것도 깨진 것처럼 보이지 않는다는 점이 견본 ID와 똑같습니다.

이번에 확인한 것

  • 잘 도는 것이 옳은 것은 아닙니다. 견본 광고는 멀쩡히 뜨고, 평문 코드는 잘 열립니다. 개발 중의 ‘된다’가 출시 후의 ‘맞다’를 보증하지 않아요.
  • 자리를 더하면 검사에도 더해야 합니다. 광고 자리, 언어 파일, 어떤 목록이든 — 검사 목록의 바깥은 실패조차 못 하는 사각지대입니다.
  • 검사가 초록인 것과 옳은 것은 다릅니다. 초록은 ‘겨눈 것이 통과했다’는 뜻이고, 무엇을 겨누고 있는지는 주기적으로 다시 물어야 합니다.
  • 자리 표시자는 ‘안전한 실패’를 고릅니다. 없는 값의 자리에는 그럴듯한 견본이 아니라 빈 값을 — 나가면 사고인 것과 나가면 그저 아쉬운 것은 다른 물건입니다.