Skip to main content

Enterprise Server 3.21 은(는) 현재 릴리스 후보로 제공됩니다.

CodeQL CLI에서 증분 분석 사용

변경된 내용만 분석하여 끌어오기 요청에서 더 빠른 CodeQL 결과를 얻을 수 있습니다. 증분 분석은 CodeQL CLI를 자체 CI/CD 시스템에서 실행할 때 스캔 시간을 최대 10배까지 줄일 수 있습니다.

누가 이 기능을 사용할 수 있나요?

CodeQL은(는) 다음 리포지토리 유형에 사용할 수 있습니다.

증분 분석 정보

특히 큰 코드베이스에서 모든 끌어오기 요청에 대한 전체 CodeQL 검사는 느려질 수 있습니다. 고유한 CI/CD 시스템에서 실행하는 CodeQL CLI 경우 증분 분석을 통해 속도를 높일 수 있는 두 가지 방법이 제공됩니다.

  • Diff 정보 분석은 추가하거나 변경한 줄의 경고만 보고하므로 쿼리가 더 빠르게 실행되고 결과가 더 관련성이 높습니다.
  • 오버레이 분석은 처음부터 새로 빌드하는 대신 기본 분기에서 캐시된 데이터베이스를 재사용하여 데이터베이스 만들기 및 쿼리 평가 시간을 크게 단축합니다.

이러한 기능을 독립적으로 또는 함께 사용할 수 있습니다. 기존 코드베이스에서 풀 리퀘스트를 분석하는 대부분의 팀에는 두 가지를 모두 사용하는 것을 권장합니다. 즉, 빠른 데이터베이스 생성과 쿼리 평가를 위한 오버레이 분석과, 더 집중적이고 관련성 높은 결과를 위한 차이 정보 기반 분석입니다.

기본 설정code scanning을 사용하거나 GitHub에서 codeql-action을 사용하는 경우, 증분 분석은 이미 자동으로 수행됩니다. 이 문서는 자체 CI/CD 인프라에서 직접 실행하는 CodeQL CLI 팀을 위한 것입니다.

사전 요구 사항

증분 분석을 설정하기 전에 다음 요구 사항을 충족하는지 확인합니다.

  • CodeQL CLI 번들 버전: diff 정보 분석을 위한 2.21.0 이상, 오버레이 분석을 위한 2.23.8 이상(언어별 최소값, 최소 CLI 번들 버전 참조)
  • 원본 루트 는 Git 리포지토리 내에 있어야 합니다.
  • Git 버전 2.38.0 이상(오버레이 분석에 필요하며, 구체적으로는 git ls-files에서 사용하는 --format 옵션에 필요)
  • 관심 있는 모든 파일은 Git에서 추적해야 합니다(없음 .gitignore).
  • Git 인덱스가 분석 중인 원본 트리를 정확하게 반영해야 합니다.
  • 빌드 모드: 오버레이 분석만 build-mode: none 지원합니다(추적된 빌드는 지원되지 않음). Go는 이 모드를 명시적으로 지원하지는 않았음에도 불구하고 오버레이 분석에서 작동합니다.

접근 방식 선택

Scenario변경 사항 기반Overlay
기본 브랜치 푸시아니요(PR 아님)오버레이 기본 모드
PR 분석(처음, 캐시 없음)Yes아니요(전체 분석 실행)
PR 분석(캐시된 기준 포함)Yes오버레이 모드
PR이 아니고 기본 브랜치도 아닌 브랜치NoNo

다양한 CI 시스템의 전체 작업 예제는 샘플 CodeQL 파이프라인 구성 리포지토리를 참조하세요.

Diff 정보 분석

Diff 정보를 활용한 분석은 풀 리퀘스트 분석에 대한 최적화 기능입니다. 코드베이스에서 발견된 모든 경고를 보고하는 대신, 풀 리퀘스트 diff에서 추가되거나 수정된 줄의 경고만 보고합니다.

1단계: 차이 범위 식별

풀 리퀘스트 diff에서 추가되거나 수정된 줄 범위가 필요합니다. 입력은 모든 원본(git diffCI 플랫폼의 API 또는 다른 메커니즘)에서 올 수 있습니다.

변경된 각 파일에 대해 다음 구조의 범위 목록을 생성합니다.

  • path: 절대 파일 경로(항상 슬래시 사용)
  • startLine: 1부터 시작하는 포괄 시작선
  • endLine: 1부터 시작하며 종료 줄을 포함함

예를 들어, git diff로 생성된 다음과 같은 unified diff가 있다고 가정해 보겠습니다:

--- a/src/utils.ts
+++ b/src/utils.ts
@@ -2,7 +2,6 @@ import { helper } from './helper';
 
 function existing() {
   const x = 1;
-  const unused = 2;
   return x;
 }
 
@@ -14,6 +13,8 @@ function validate(input: string) {
 function process(input: string) {
   // validate
   if (!input) return;
+  const sanitized = input.trim();
+  console.log(sanitized);
   return input;
 }
 
@@ -23,5 +24,5 @@ function format(value: number) {
 
 function render(data: object) {
   const output = JSON.stringify(data);
-  return output;
+  return `<div>${output}</div>`;
 }

결과 차이 범위는 다음과 같습니다.src/utils.ts

  • ["/path/to/repo/src/utils.ts", 16, 17] (두 번째 헝크에 삽입된 두 줄)
  • ["/path/to/repo/src/utils.ts", 27, 27] (세 번째 청크의 수정된 줄)

첫 번째 덩어리는 삭제만 포함하므로 범위를 생성하지 않습니다. 범위에는 "from"(이전 파일) 번호가 아니라 "to"(새 파일) 줄 번호가 사용된다는 점에 유의하세요.

특수 사례:

  • 이진 파일 또는 매우 큰 변경 사항 (사용 가능한 패치 콘텐츠 없음): {path, startLine: 0, endLine: 0} 센티널 범위를 사용하여 "전체 파일"을 나타내세요.
  • 콘텐츠 변경 없이 파일 이름이 변경됨: 빈 배열(범위 없음)을 반환합니다.
  • 잘린 diff: 큰 풀 리퀘스트(예: 변경된 파일 수를 제한하는 API)에서 diff 소스가 불완전한 경우, diff 기반 분석을 건너뛰고 해당 실행에서는 전체 분석을 수행해야 합니다.

diff 구문 분석의 참조 구현은 소스 코드를 참조 getDiffRanges()codeql-action 하세요.

2단계: 데이터 확장 팩 만들기

두 개의 파일이 포함된 임시 디렉터리를 만듭니다. 이 확장 팩은 CodeQL 표준 라이브러리에 정의된 restrictAlertsTo 확장 가능한 조건자에 연결됩니다.

** qlpack.yml:**

name: my-ci/pr-diff-range
version: 0.0.0
library: true
extensionTargets:
  codeql/util: '*'  # Target the codeql/util pack where restrictAlertsTo is defined
dataExtensions:
  - pr-diff-range.yml

** pr-diff-range.yml:**

extensions:
  - addsTo:
      pack: codeql/util
      extensible: restrictAlertsTo
      checkPresence: false  # Don't error if the predicate doesn't exist in older CLI versions
    data:
      # Each row: [filePath, startLine, endLine]
      - ["/path/to/repo/src/utils.ts", 16, 17]
      - ["/path/to/repo/src/utils.ts", 27, 27]

각 데이터 행은 [filePath, lineStart, lineEnd]입니다. 줄 번호는 1부터 사용합니다. 특수 사례 lineStart = 0, lineEnd = 0 는 전체 파일 일치를 표시합니다.

중요

diff에 추가되거나 수정된 줄이 0개인 경우(예: 삭제만) 여전히 비어있지 않은 데이터 확장에 sentinel 항목을 ["", 0, 0]제공해야 합니다. 빈 data 섹션은 조건자를 restrictAlertsTo 비활성 상태로 둡니다. 즉, 원하는 동작과 반대되는 모든 경고가 생성됩니다.

3단계: 확장 팩을 CodeQL CLI에 전달합니다

쿼리를 실행할 때 다음 플래그를 추가합니다 codeql database run-queries.

codeql database run-queries \
  --additional-packs=PATH_TO_EXTENSION_PACK \
  --extension-packs=my-ci/pr-diff-range \
  PATH_TO_DATABASE \
  QUERIES
  • --additional-packs 는 CodeQL 디스크에서 팩을 찾을 위치를 알려줍니다. 자세한 내용은 데이터베이스 실행 쿼리을(를) 참조하세요.
  • --extension-packs 는 명명된 확장 팩을 로드하도록 지시합니다 CodeQL .

4단계: 진단 쿼리 제외

diff 정보 분석을 사용하는 경우 태그 exclude-from-incremental가 지정된 쿼리를 제외해야 합니다. 이러한 진단 쿼리는 경고(예: 메트릭 또는 코드 검사)를 생성하지 않으므로 증분 컨텍스트에서 값을 제공하지 않지만 여전히 리소스를 사용합니다.

코드 검색 구성 파일에 다음을 추가할 수 있습니다.

query-filters:
  - exclude:
      tags: exclude-from-incremental

또는 해당 쿼리를 제외하는 쿼리 도구 모음 파일(.qls)을 만듭니다.

- description: Pull request queries for Java
- import: codeql-suites/java-code-scanning.qls
  from: codeql/java-queries
- exclude:
    tags contain: exclude-from-incremental

자세한 내용은 코드 검색을 위한 워크플로 구성 옵션을(를) 참조하세요.

5단계: SARIF 출력 필터링

SARIF 파일을 생성한 후 CodeQL CI 쪽에서 출력을 필터링하여 위치가 diff 범위를 벗어난 결과를 제거해야 합니다.

SARIF의 각 결과에 대해, 해당 결과의 locations 또는 relatedLocations 중 어느 하나라도 그 파일의 diff 범위와 교차하는지 확인합니다. 위치가 범위와 교차하는 것은 range.startLine <= location.endLinelocation.startLine <= range.endLine일 때입니다. 특수 사례 range.startLine == range.endLine == 0 는 파일의 모든 위치와 일치합니다. 비교하기 전에 SARIF 아티팩트 위치가 diff 범위에서 사용되는 것과 동일한 절대 경로 형식으로 확인되었는지 확인합니다.

조건자는 restrictAlertsTo 쿼리가 범위를 벗어난 경고를 생략하는 것을 허용하지만 보장하지는 않으므로 안정적인 결과를 위해서는 CI 쪽 필터링이 필요합니다.

SARIF 필터링의 참조 구현은 소스 코드를 참조 filterAlertsByDiffRange()codeql-action 하세요.

diff 기반 분석을 위한 CLI 플래그 요약

CLI 명령Flag목적
codeql database init--codescanning-config=FILE코드 검색 구성 파일(쿼리 필터용)
codeql database run-queries--additional-packs=DIR확장 팩의 위치
codeql database run-queries--extension-packs=my-ci/pr-diff-range로드할 확장 팩의 이름
codeql database interpret-results--sarif-run-property=incrementalMode=diff-informed(선택 사항) diff 정보 메타데이터를 사용하여 SARIF 태그 지정

오버레이 분석

오버레이 분석은 기존 "기본" 데이터베이스를 기반으로 빌드하여 끌어오기 요청에 대한 데이터베이스 생성 및 쿼리 평가 속도를 향상 CodeQL 합니다.

  1. 기본 분기에서: "오버레이 기반" 데이터베이스(캐시된 중간 결과가 있는 전체 데이터베이스)를 빌드합니다. 이는 풀 리퀘스트의 대상이 되는 장기간 유지되는 브랜치일 수 있습니다.
  2. 끌어오기 요청의 경우: 캐시된 오버레이 기반 데이터베이스를 다운로드한 다음 변경된 파일만 처리하는 간단한 "오버레이" 데이터베이스를 만듭니다.

오버레이 기반 모드(기본 브랜치)

각 병합 후 기본 또는 수명이 긴 대상 분기에서 오버레이 기본 모드를 실행하여 기본 데이터베이스를 만들고 캐시합니다.

1. 다음을 사용하여 데이터베이스 초기화 --overlay-base

codeql database init \
  --overlay-base \
  --db-cluster \
  PATH_TO_DATABASE \
  --source-root=PATH_TO_SOURCE \
  --language=LANGUAGE

플래그는 --overlay-base 향후 오버레이 분석을 위한 기반으로 사용할 수 있는 데이터베이스를 빌드하도록 지시 CodeQL 합니다.

2. 정상적으로 빌드 및 추출

프로젝트와 마찬가지로 빌드 단계 및 추출을 실행합니다.

3. 파일 OID 기록

추출이 완료되면 원본 루트 아래에 추적된 모든 파일의 Git 개체 ID(OID)를 기록합니다. 원본 루트 디렉터리(PATH_TO_SOURCE)에서 이 명령을 실행합니다. 이 스냅샷은 나중에 변경된 파일을 결정하는 데 사용됩니다.

cd PATH_TO_SOURCE && git ls-files --recurse-submodules --format='%(objectname)_%(path)'

이 출력을 JSON 맵 { "relative/path": "git-oid" } 으로 구문 분석하고 데이터베이스와 함께 저장합니다. 출력에는 Git 하위 모듈의 파일이 포함되며, 오버레이 분석은 베이스와 오버레이 간의 모든 파일 변경 내용을 정확하게 추적해야 합니다.

4. 쿼리 실행 및 캐시 유지

오버레이 기반 데이터베이스에서 쿼리를 실행할 때는 전달****--expect-discarded-cache 마세요. 캐시된 중간 결과는 끌어오기 요청 빌드를 빠르게 만드는 것입니다. 이를 삭제하면 모든 PR에서 전체 재평가가 강제로 적용됩니다.

5. 데이터베이스 정리 및 캐시

분석 후 overlay 정리 수준을 사용하여 데이터베이스를 정리합니다:

codeql database cleanup PATH_TO_DATABASE --cache-cleanup=overlay

overlay 정리 수준은 기본 clear 수준보다 더 많은 캐시된 데이터를 유지합니다. 오버레이 모드는 끌어오기 요청에서 효율적인 쿼리 평가를 위해 캐시된 데이터를 다시 사용하므로 삭제하면 성능 이점이 없어집니다.

그런 다음 끌어오기 요청 빌드를 통해 나중에 검색할 수 있는 데이터베이스(OID 파일 포함)를 캐싱 시스템에 저장합니다.

오버레이 모드(끌어오기 요청)

끌어오기 요청 빌드에서 오버레이 모드를 실행하여 캐시된 베이스 위에 경량 데이터베이스를 만듭니다. 캐시에 호환되는 오버레이-베이스 데이터베이스가 없는 경우(예: 첫 실행 시 또는 CodeQL CLI 버전 업그레이드 후)에는 --overlay-changes 을(를) 건너뛰고 대신 일반적인 전체 분석을 실행합니다. 캐시 키는 호환되지 않는 기본 데이터베이스를 CodeQL CLI 방지하기 위해 버전 및 언어 집합 이상을 포함해야 합니다.

1. 캐시된 오버레이 기반 데이터베이스 다운로드

캐시에서 가장 최근의 오버레이 기반 데이터베이스를 검색합니다. 데이터베이스에는 오버레이 기본 모드 중에 기록된 OID 파일이 포함되어야 합니다.

2. 변경된 파일 컴퓨팅

기본 데이터베이스에 기록된 OID를 현재 Git 상태와 비교합니다. 오버레이 기반 모드에서 사용되는 동일한 원본 루트 디렉터리(PATH_TO_SOURCE)에서 다음 명령을 실행합니다.

cd PATH_TO_SOURCE && git ls-files --recurse-submodules --format='%(objectname)_%(path)'

두 맵을 비교하여 추가, 제거 또는 수정된 파일(다른 OID)을 찾습니다. 결과를 JSON 파일로 작성합니다.

{
  "changes": ["src/modified-file.ts", "src/new-file.ts", "src/deleted-file.ts"]
}

파일 경로는 원본 루트를 기준으로 해야 합니다.

3. 다음을 사용하여 데이터베이스 초기화 --overlay-changes

복원된 오버레이 기반 데이터베이스 디렉터리에 대해 실행 codeql database init 합니다. PATH_TO_DATABASE 새 빈 디렉터리가 아니라 복원된 캐시된 오버레이 기반 데이터베이스를 가리킵니다. 이 명령은 끌어오기 요청 분석을 위해 기존 기반을 확장합니다.

codeql database init \
  --overlay-changes=PATH_TO_OVERLAY_CHANGES_JSON \
  --db-cluster \
  PATH_TO_DATABASE \
  --source-root=PATH_TO_SOURCE \
  --language=LANGUAGE

중요

오버레이 모드에서는 --overwrite 또는 --force-overwrite를 전달하지 마세요. 기존 캐시된 기본 데이터베이스를 기반으로 구축하며 대체하지 않습니다.

4. 정상적으로 쿼리 빌드, 추출 및 실행

정상적으로 빌드, 추출 및 쿼리 실행을 진행합니다. 기존 --sarif-run-property 명령에 플래그를 codeql database interpret-results 추가하여 오버레이 메타데이터를 사용하여 SARIF 출력에 태그를 지정할 수 있습니다.

codeql database interpret-results \
  --format=sarif-latest \
  --output=results.sarif \
  --sarif-run-property=incrementalMode=overlay \
  PATH_TO_DATABASE \
  QUERIES_OR_SUITES

오버레이 및 차이 정보에 입각한 분석이 모두 활성 상태이면 .를 사용합니다 incrementalMode=overlay,diff-informed.

증분 분석의 경고는 전체 검사의 경고와 동일한 방식으로 끌어오기 요청의 코드 검색 결과에 표시됩니다. 모든 오버레이 기반 데이터베이스는 연령에 관계없이 작동하지만 최신 기반은 더 빠르고 정확한 결과를 생성합니다.

diff 기반 분석과 마찬가지로, 오버레이 모드를 사용할 때는 exclude-from-incremental 태그가 지정된 쿼리를 제외합니다. 자세한 내용은 4단계: 진단 쿼리 제외를 참조하세요.

오버레이 분석을 위한 CLI 플래그 요약

CLI 명령Flag모드목적
codeql database init--codescanning-config=FILE오버레이코드 검색 구성 파일(쿼리 필터용)
codeql database init--overlay-base오버레이 베이스향후 오버레이 사용을 위한 기본 데이터베이스 빌드
codeql database init--overlay-changes=FILE오버레이변경된 파일만 사용하여 오버레이 데이터베이스 빌드
codeql database init
(아니요 --overwrite)오버레이캐시된 기본 데이터베이스를 덮어쓰지 마세요.
codeql database run-queries
(아니요 --expect-discarded-cache)오버레이 베이스캐시된 중간 결과 유지
codeql database cleanup--cache-cleanup=overlay오버레이 베이스오버레이별 정리 수준 사용
codeql database interpret-results--sarif-run-property=incrementalMode=overlay오버레이오버레이 메타데이터를 사용하여 SARIF 태그

최소 CLI 번들 버전

오버레이 분석을 위한 기본 최소 버전은 2.23.8입니다. 일부 언어에는 더 높은 최소 버전이 필요합니다.

언어최소 CodeQL CLI 번들 버전
C/C++2.25.0
C#2.24.1
Go2.24.2
Java2.23.8
자바 스크립트2.23.9
Python2.23.9
Ruby2.23.9