엔지니어링 문서

클라우드 Mac에서 Xcode 정적 분석 기준선 운영하기

클라우드 Mac에서 Xcode 정적 분석 기준선 운영하기

팀이 클라우드 Mac에 xcodebuild analyze를 연동하면 가장 흔히 마주하는 결과는 결함이 즉시 0건이 되는 것이 아니라, 기존에 누적된 진단이 한꺼번에 수십 건 나타나는 것입니다. 경고 총개수를 그대로 실패 조건으로 설정하면 파이프라인은 계속 실패 상태로 남게 됩니다. 반대로 로그만 첨부 파일로 보관하면 아무도 꾸준히 확인하지 않습니다. 더 실용적인 방법은 검토를 거친 기준선을 먼저 만든 다음, 각 병합이 새로 추가한 문제에 대해서만 책임지도록 하는 것입니다.

분석 작업의 입력부터 고정하기

정적 분석 결과는 프로젝트 설정, 컴파일 조건, 실제 컴파일에 포함되는 소스 파일에 따라 달라집니다. 분석을 시작하기 전에 Xcode 선택, 워크스페이스, Scheme, 구성, 대상 플랫폼을 고정하고, CI가 아카이브 작업과 동일한 종속성 잠금 파일을 사용하도록 해야 합니다. 개발자 개인의 Scheme을 사용하거나 스크립트에서 “최신” 도구 체인을 자동으로 선택해서는 안 됩니다.

분석 작업에는 별도의 디렉터리를 사용해 빌드 및 테스트 작업과 DerivedData를 동시에 변경하지 않도록 합니다.

set -o pipefail

ROOT="$PWD"
OUT="$ROOT/ci-artifacts/analyze"
DERIVED="$ROOT/.derived/analyze"
RESULT="$OUT/AppAnalyze.xcresult"

rm -rf "$OUT" "$DERIVED"
mkdir -p "$OUT" "$DERIVED"

xcodebuild analyze \
  -workspace App.xcworkspace \
  -scheme App \
  -configuration Debug \
  -destination 'generic/platform=iOS' \
  -derivedDataPath "$DERIVED" \
  -resultBundlePath "$RESULT" \
  CODE_SIGNING_ALLOWED=NO \
  | tee "$OUT/xcodebuild.log"

CODE_SIGNING_ALLOWED=NO는 서명 없이도 분석을 완료할 수 있는 대상에만 적합합니다. 프로젝트 스크립트가 서명 관련 빌드 설정을 명시적으로 읽는다면 무작정 재정의 매개변수를 더 추가하지 말고, 먼저 스크립트의 입력 경계를 바로잡아야 합니다.

기준선은 “무시해도 되는 문제” 목록이 아니라 마이그레이션 기간에 이미 알려진 사실을 기록한 스냅샷입니다. 새 문제는 계속 즉시 실패 처리해야 하며, 기존 문제에는 담당자와 정리 계획이 필요합니다.

warning 개수만 세지 말고 전체 결과 보관하기

grep -c warning:을 직접 실행하는 방식은 편리하지만 장기적인 품질 게이트에는 적합하지 않습니다. 로그의 경로, 줄 번호, 형식은 달라질 수 있으며 같은 진단이 여러 번 출력될 수도 있습니다. CI는 .xcresult와 원본 로그를 모두 보관하고, 구조화된 결과에서 비교용 진단 목록을 생성해야 합니다.

Xcode 버전에 따라 xcresulttool의 하위 명령이 변경될 수 있으므로 먼저 도움말을 기록하고, 노드 이미지를 업데이트할 때 파싱 스크립트를 다시 검증합니다.

xcrun xcresulttool help > "$OUT/xcresulttool-help.txt"
xcrun xcresulttool get \
  --legacy \
  --path "$RESULT" \
  --format json > "$OUT/xcresult.json"

현재 도구 체인이 --legacy를 허용하지 않는다면 해당 버전의 도움말에 맞춰 명령을 조정하고, 파서 변경과 도구 체인 업그레이드를 같은 병합 요청에 포함해야 합니다. 스크립트가 실패했을 때 로그 개수 집계로 되돌아간 뒤 작업을 통과시키지 마십시오. 그렇게 하면 품질 게이트가 아무도 모르게 무력화됩니다.

각 진단에는 다음 필드를 보관하는 것이 좋습니다.

필드 용도
규칙 또는 문제 유형 널 포인터, 리소스 누수 등의 범주 구분
저장소 기준 상대 경로 노드의 작업 디렉터리가 기준선에 포함되는 것을 방지
함수 또는 심벌 이름 줄 번호가 바뀐 뒤에도 위치 파악 지원
정규화된 메시지 임시 디렉터리와 불안정한 숫자 제거
심각도 위험도에 따른 처리 정책 지원

안정적인 지문으로 검토 가능한 기준선 만들기

진단 지문에는 절대 경로, DerivedData 경로 또는 줄 번호만을 단독으로 포함해서는 안 됩니다. 비교적 안정적인 조합은 “문제 유형 + 저장소 기준 상대 경로 + 심벌 이름 + 정규화된 메시지”입니다. 줄 번호는 표시용으로 보관할 수 있지만 기본 키에는 포함하지 않아야 합니다. 그렇지 않으면 파일 맨 위에 한 줄만 추가해도 기존 문제가 모두 신규 문제로 인식됩니다.

정규화 과정에서 지나치게 통합하지 않기

작업 디렉터리 접두사, 임시 UUID, 연속된 공백은 제거할 수 있지만 변수 이름, 호출 이름, 리소스 유형까지 삭제해서는 안 됩니다. 같은 파일에서 발생한 서로 다른 결함 두 건이 하나의 지문으로 압축되면 나중에 발생한 문제가 기존 기준선에 가려질 수 있습니다.

기준선 파일은 정렬된 JSON Lines 형식을 사용해 한 줄에 레코드 하나씩 저장하고 버전 관리에 포함하는 것이 좋습니다.

{"fingerprint":"sha256:…","type":"AnalyzeWarning","path":"Sources/Cache.swift","symbol":"load()","message":"Potential leak of an object"}

최초로 기준선을 만들 때는 코드 소유자가 각 항목을 하나씩 확인해야 합니다. 최소한 진단이 현재 기본 브랜치에서 실제로 발생한 것인지, 당장 수정하기 어려운지, 추적 항목이 이미 등록되어 있는지, 파싱 실패나 중복 레코드가 기준선에 들어가지는 않았는지 확인해야 합니다.

병합 요청에서는 집합 차이만 비교하기

각 작업에서 current.jsonl을 생성한 뒤 지문 집합을 baseline.jsonl과 비교합니다. current - baseline은 새로 발생한 문제이므로 작업을 실패시켜야 합니다. baseline - current는 이미 사라진 문제이므로 무효한 레코드를 계속 유지하지 말고, 해당 기준선 항목을 삭제하라고 관리자에게 알려야 합니다.

품질 게이트의 출력은 짧고 실행 가능해야 합니다. 새 문제마다 유형, 상대 경로, 줄 번호, 심벌, 메시지를 출력하고 전체 xcresult 산출물의 위치를 함께 표시합니다. 콘솔 로그에는 요약만 보여 주어 수천 줄의 분석 추적 정보가 실제 차이를 가리지 않도록 합니다.

세 가지 실패 유형 구분하기

분석 스크립트는 최소한 다음 상태를 구분해야 합니다.

  1. 종속성 누락이나 사용할 수 없는 Scheme 등으로 xcodebuild analyze 자체가 실패한 경우
  2. 도구 체인 업그레이드 후 JSON 구조가 바뀌는 등 결과 파싱에 실패한 경우
  3. 분석은 성공했지만 기준선에 없는 새 진단이 발견된 경우

앞의 두 가지는 인프라 또는 구성 오류이므로 “신규 결함 0건”으로 표시해서는 안 됩니다. 분석과 파싱이 모두 성공하고 집합 차이가 비어 있을 때만 작업을 통과시킬 수 있습니다.

기준선을 지속적으로 줄이기

기준선이 오랫동안 변하지 않으면 결국 아무도 관리하지 않는 또 하나의 무시 목록이 됩니다. 모듈별 담당자를 지정해 관련 파일을 수정할 때 주변의 진단도 함께 해결하거나, 반복 주기마다 위험도가 높은 항목을 소량씩 정리할 수 있습니다. 문제를 수정한 뒤에는 기준선 레코드도 반드시 삭제해야 하며, 다음 실행에서 문제가 실제로 사라졌는지 검증하게 됩니다.

일상 점검은 다음 순서로 수행할 수 있습니다.

  • 도구 체인, Scheme, 구성, 대상 플랫폼이 달라지지 않았는지 확인합니다.
  • 분석 디렉터리가 다른 작업과 격리되어 있는지 확인합니다.
  • xcresult, 로그, 정규화된 목록이 모두 생성되었는지 확인합니다.
  • 지문에 절대 경로나 임시 식별자가 없는지 표본 검사합니다.
  • 새 진단은 병합을 차단하고, 사라진 진단은 기준선 축소를 안내하도록 합니다.
  • 도구 체인을 업그레이드할 때는 먼저 별도 브랜치에서 기준선을 다시 만들고 차이를 검토합니다.

OakVM에서 이러한 작업을 실행할 때 중요한 것은 더 공격적인 임계값을 선택하는 것이 아니라, 같은 물리 노드의 도구 체인, 스크립트, 결과 형식을 추적 가능한 상태로 유지하는 것입니다. 파싱 실패를 성공으로 처리하지 않고 기준선 변경을 반드시 검토한다면, 정적 분석은 쉽게 무시되는 긴 로그에서 안정적인 증분 품질 게이트로 바뀔 수 있습니다.

자주 묻는 질문

처음부터 정적 분석 경고를 모두 0으로 만들면 안 되나요?

가능하지만 기존 프로젝트에서는 대량의 과거 경고 때문에 게이트가 사실상 비활성화되기 쉽습니다. 현재 결과를 기준선으로 고정하고 새 결함부터 차단한 뒤 모듈별로 기준선을 줄이는 편이 현실적입니다.

CI 산출물로 무엇을 보관해야 하나요?

전체 xcresult, 빌드 로그, 정규화된 진단 목록, 비교에 사용한 기준선 파일을 함께 보관해야 합니다. 그래야 실패 원인과 분석 환경을 다시 확인할 수 있습니다.

OAKVM BUILD NODE

다음 빌드를 독립 물리 노드에서 실행하세요

OakVM M4 또는 OakVM M4 Pro를 선택하고, 가상화되지 않은 클라우드 Mac을 일·주·월·분기 단위로 대여하세요. 노드의 실제 이용 가능 여부는 콘솔에서 실시간으로 확인할 수 있습니다.

구성 선택 및 대여