← 아티클 목록

개발일지WhoAmI — 공부 기록을 발행 가능한 형태로 좁힌 파이프라인 →

커밋 39개에서 시작한 저장소 감사는 61개에서 끝났다

39번째 커밋에서 기준선을 잡아 61번째 병합 커밋까지 진행한 저장소 감사 기록. 미실행 검사와 기존 실패도 기준선에서 분리하고, 보류한 의존성이 Worker 추가 뒤에도 배포 런타임에 도달하는지 다시 확인했다.

목차 3

2026-08-09 업데이트 — 감사의 시작·종료 커밋 수와 시간축을 바로잡고, 미실행 검사와 기존 실패를 기준선에 반영했다. Worker 추가 뒤 undici가 배포 런타임에 도달하는지도 다시 평가했다.

감사를 시작한 2026년 8월 4일의 main HEAD는 77d089d였고, git rev-list --count 77d089d의 결과는 39다. 감사 보고서를 먼저 남긴 08cf337이 40번째였고, 수정과 문서화를 마쳐 main에 병합한 8cc632c가 61번째다. 62번째 a5d1c13은 감사 뒤에 용어를 바꾼 별도 커밋이므로 감사 시점을 나타내지 않는다.

저장소 안에는 「지금은 잘 돌아가는데 왜 그렇게 됐는지 기억나지 않는 것」이 쌓여 있었다. 쓰지 않는 스크립트, 같은 일을 하는 파서 세 벌, 서로 어긋난 문서와 실제 명령. 하나씩은 사소한데 어느 것이 사소한지 알려면 전부 봐야 했다.

그래서 한 번 통째로 훑기로 하고, 시작하기 전에 규칙 두 개를 먼저 정했다.

기준선을 먼저 잰다. 리팩터링 전에 실행하기로 한 유한한 검사를 돌려 결과를 기록해 둔다. 그러지 않으면 나중에 무언가 실패했을 때 그게 내가 만든 것인지 원래 그랬던 것인지 알 수 없다. 다만 당시 기준선은 「모든 명령 통과」가 아니었다. npm ci는 기존 설치 트리를 바꾸지 않으려고 실행하지 않았고, 장기 실행인 npm run write·dev·admin과 실제 배포도 제외했다. npm run check·build·check:exposure 등은 0으로 끝났지만 npm audit은 취약점 5건 때문에 1, npm outdated도 갱신 가능한 패키지 4개 때문에 1로 끝났다. 이 둘을 기존 상태로 기록해 이후 변경이 새로 만든 실패와 구분했다.

추측을 적지 않는다. 실행한 결과만 기록한다. 코드를 읽고 「이건 안 쓰일 것 같다」고 판단한 것과 실제로 호출자를 찾아 0건인 것을 확인한 것은 다르다.

확인하지 못한 것을 지우지 않고 보류로 남겼다

감사를 하다 보면 지우고 싶은 것이 계속 나온다. 여기서 건 규칙이 이 작업에서 가장 크게 작용했다. 내가 확인할 수 없는 조건에 걸린 것은 지우지 않고 보류 항목으로 적어 둔다.

옛 배포 스크립트가 그 경우였다. 코드 주석과 문서 두 곳이 「첫 배포가 끝나면 지운다」고 조건을 걸어 두었는데, 그 배포가 실제로 끝났는지는 저장소를 봐서는 알 수 없다. 그래서 그 자리에서 지우지 않고 보류로 기록했고, 배포가 끝났다는 것을 확인한 다음에 지웠다.

보류로 남긴 항목은 나중에 재검토 조건이 실제로 발동했다. 감사 당시 undici 계열 취약점은 Wrangler·Miniflare의 개발 도구 경로에만 있고 배포 런타임이 없어 수용했다. 8월 6일 공유 링크 기능 때문에 wrangler.jsonc에 main: "worker/index.js"가 생기면서 「Worker 진입점이 추가되면 다시 본다」는 조건이 충족됐다.

재평가 결과 결론은 유지됐지만 근거는 바뀌었다. wrangler deploy --dry-run --outdir 산출물은 5.25 KiB의 worker/index.js 한 파일이었고 node_modules 참조가 없었다. Worker 코드도 npm 패키지를 import하지 않으며 workerd의 fetch를 쓴다. 따라서 배포 런타임은 생겼지만 undici는 여전히 Wrangler CLI와 Miniflare의 빌드·로컬 개발 경로에만 있고 Worker 번들에는 도달하지 않았다. 「Worker를 추가하면 곧 취약점이 도달 가능해진다」는 이전 문장은 조건을 너무 앞서 결론 낸 것이었다. 다음 재검토 조건은 Worker가 npm 의존성을 import하기 시작하거나 패치 릴리스가 나오는 때다.

「지금 잘 돌아가니까」를 근거로 쓰지 않는 것도 같은 규칙의 다른 얼굴이다. 잘 돌아간다는 것은 아직 그 조건을 안 밟았다는 뜻일 수 있다.

나온 것은 대부분 중복이었다

정리한 것을 놓고 보면 성격이 비슷했다. 카테고리를 읽는 파서가 세 벌 있었고, 자격증명 탐지 규칙 정의가 여러 곳에 흩어져 있었으며, 부수적인 중복이 다섯 건 더 나왔다. 저장소의 첫 커밋은 7월 17일이고 감사 시작은 8월 4일이므로 그 사이는 18일이다. 한 달이 아니라 3주도 안 되는 동안 중복이 이만큼 쌓였다.

의존성 쪽에서는 버전을 고정하지 않고 매번 최신을 받아 쓰던 것이 나왔다. 출력 형식이 바뀌면 수집한 숫자가 조용히 달라지는 자리라 버전을 고정했다.

가장 실질적인 것은 배포 명령이 검증받은 산출물을 배포하지 않을 수 있다는 지적이었다. 빌드와 배포가 각각의 명령이면 그 사이에 다른 모드로 빌드한 결과물이 끼어들 수 있다. 지금은 배포 명령이 항상 검증과 빌드를 먼저 돌린다.

감사가 끝났다고 저장소가 깨끗해진 것은 아니다

감사 문서는 여섯 편으로 남겼고, 각 항목에 근거가 되는 파일과 줄 번호를 붙였다. 고친 것보다 고치지 않기로 하고 이유를 적은 것이 이 문서의 쓸모라고 생각한다. 다음에 같은 자리를 보게 될 때 처음부터 다시 판단하지 않아도 된다.

남은 것도 그대로 적혀 있다. 관리자를 다른 기기에서 여는 --host 경로는 접속 방식을 바꾸는 수정 대신 경고만 두기로 했고, undici 계열은 위의 도달 가능성 근거로 수용 위험에 남겼다. 검증·시크릿 검사는 release와 CI에 연결했지만 npm audit 자체는 아직 CI 게이트가 아니다. 감사는 모든 문제를 없앤 작업이 아니라 적용·수용·기각의 근거를 남긴 작업이었다.

한 가지는 이 감사로도 확인되지 않았다. 이 저장소는 혼자 만들고 혼자 감사했다. 기준선과 실행 결과로 판정을 묶어 두려고 한 것도 결국 그 조건 때문인데, 같은 사람이 만든 것을 같은 사람이 보면 애초에 의심하지 않는 자리는 그대로 남는다. 그건 규칙으로 메울 수 있는 종류가 아니다.

함께 보면 좋은 글

이 기록과 태그가 겹치는 아티클입니다.