본문으로 건너뛰기
5분 AI.
GITHUB TRENDING GO WEEKLY #3 딥다이브 · 2026-10-23 분석

gitleaks 딥다이브
— 코드에 숨은 비밀을 찾는 탐지기의 설계

보안 CLI

빠른 판단

무엇
파일과 Git 이력의 API 키·비밀번호·토큰 노출 후보를 규칙·문맥으로 검사하는 Go CLI
이럴 때
커밋 전이나 CI에서 자격증명 노출을 점검하고 과거 커밋에 남은 민감 문자열을 조사할 때
입력
검사할 파일·Git 이력과 탐지·예외 규칙
결과
노출 의심 문자열의 위치·규칙·검사 보고서
API 키와 비밀번호를 Git에 올리는 실수는 작은 문자열 하나에서 시작됩니다. Gitleaks는 Git 이력·파일·표준입력을 검사하는 Go CLI입니다. 이 글에서는 입력 추상화, 단계별 탐지, 제한된 동시성, 설정 생성과 검증이 어떻게 하나의 도구로 이어지는지 살펴봅니다. Go 214개 파일 약 21,579줄, 기본 탐지 규칙 222개를 가진 저장소에서 초보자가 따라갈 수 있는 읽기 경로를 안내합니다. (gitleaks/gitleaks · ⭐30,253 · 포크 2,311 · MIT · 2026-10-23 GitHub 기준 · 코드 인용은 커밋 b58d3f1 기준)
목차
  1. 프로젝트 한줄 요약
  2. 왜 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석
  5. 디렉토리 구조 해부
  6. 학습 포인트 (기술별)
  7. 하드웨어 / 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한줄 요약

문자열을 찾아내는 작은 도구에서, 개발 흐름을 지키는 검사기로

Gitleaks는 소스 코드에 하드코딩한 비밀번호·API 키·토큰 등의 노출 후보를 찾아주는 프로그램입니다. 현재 파일과 과거 커밋을 따로 살피고, 의심스러운 문자열을 규칙과 문맥으로 걸러 보고서로 남깁니다. 사용자는 명령 하나를 실행하지만, 내부에서는 입력 읽기·규칙 선택·위치 계산·예외 처리·결과 출력이 각자의 역할을 합니다.

용어부터
시크릿과 자격 증명
시크릿은 공개하면 안 되는 값입니다. 그중 API 키·비밀번호·접근 토큰처럼 권한을 증명하는 값을 자격 증명이라고 부릅니다. 파일명이나 변수명이 비밀인 것이 아니라, 그 안에 들어 있는 접근 권한을 가진 값이 보호 대상입니다.
전체를 이해하는 비유

개발팀의 짐이 창고 밖으로 나가기 전에 검사하는 검색대

git 모드는 과거 출고 기록을, dir 모드는 지금 창고에 있는 상자를, stdin 모드는 컨베이어 벨트로 들어오는 내용을 검사합니다. 짐의 출처가 달라도 검사대에 올라오는 순간에는 같은 형태의 조각이 됩니다.

검사 기준은 모양이 알려진 출입증을 찾는 규칙과 비슷합니다. 발견한 출입증이 실제로 문을 여는지까지 이 검사대가 확인하는 것은 아닙니다. 경고는 검토해야 할 노출 후보이며, 유효한 권한의 증명과 구분해야 합니다.

1-1. 세 명령은 서로 다른 범위를 검사한다

명령입력 범위처음 기억할 점
gitleaks git .로컬 Git 이력의 패치과거에 추가했다가 지운 값도 이력에 남아 있으면 탐지 대상
gitleaks dir .현재 디렉터리 또는 파일아직 커밋하지 않은 파일도 볼 수 있음. 과거 이력을 복원하지는 않음
gitleaks stdin표준입력으로 들어온 내용파이프로 연결한 로그·텍스트도 같은 탐지기로 검사

명령의 시작점은 cmd/git.go:runGit, cmd/directory.go:runDirectory, cmd/stdin.go:runStdIn입니다. 셋 모두 Detector.DetectSource를 호출합니다. 이 공통 지점을 찾으면 처음부터 모든 패키지를 읽을 필요가 없습니다.

# 설치된 Gitleaks로 실행하는 사용 예시
# Git 이력을 검사하고, 결과의 비밀값을 가린다
gitleaks git . --redact --report-format json --report-path findings.json

# 현재 디렉터리만 검사한다
gitleaks dir . --redact

# 텍스트를 표준입력으로 연결한다
printf '%s\n' '설정 예시 텍스트' | gitleaks stdin --redact
배울 것
하나의 검사 엔진을 여러 사용 방식으로 연결하는 법

웹 서버나 데이터베이스를 갖추지 않아도 실용적인 제품을 만들 수 있습니다. 이 저장소는 작은 인터페이스와 명확한 데이터 구조가 어떻게 CLI·Git 훅·CI 보고서까지 이어지는지 보여줍니다.

2왜 주목받는가

트렌딩 순위와, 소스에서 설명할 수 있는 실용적 매력을 구분하기

2-1. 유출을 찾는 위치가 개발자와 가깝다

2026-10-23 GitHub Trending Go Weekly #3에 오른 저장소입니다. 다만 순위만으로 특정 사건이나 기능이 인기 상승의 원인이라고 단정할 수는 없습니다. 여기서 살펴볼 것은 소스에 드러난 도입 편의성과 학습 가치입니다.

.pre-commit-hooks.yaml의 실행 명령은 gitleaks git --pre-commit --redact --staged --verbose입니다. 커밋 전에 스테이징한 변경을 검사하도록 연결합니다. .github/workflows/gitleaks.yml은 자신의 저장소를 Gitleaks Action으로 검사하며, 체크아웃에 fetch-depth: 0을 지정합니다. 이력의 깊이가 검사 범위를 결정하기 때문입니다.

이 도구의 매력은 탐지 알고리즘 하나보다, 같은 검사를 로컬 커밋 전과 CI에 반복해서 넣을 수 있다는 데 있습니다. 이것은 트렌딩 원인에 대한 통계적 증명이 아니라, 구현과 배포 경로에서 읽어낸 장점입니다.

용어부터
커밋 전 훅과 CI
훅은 Git 작업 시점에 실행되는 검사이고, CI는 변경을 올렸을 때 자동으로 수행하는 빌드·검사 절차입니다. 훅은 빠른 피드백에, CI는 팀이 공유하는 검증에 유리합니다. 검사 범위와 예외 정책을 함께 맞춰야 결과를 비교할 수 있습니다.

2-2. 비슷한 도구와 비교하면 무엇이 보일까

도구중심 접근선택할 때 볼 차이
Gitleaks로컬 Git·파일·표준입력 + TOML 규칙단일 CLI와 규칙 파일로 검사 정책을 공유하기 좋음. 이 글의 탐지 경로는 서비스 API에 키를 보내 검증하지 않음
TruffleHog시크릿 탐지와 API 기반 유효성 검증공식 문서는 검증 성공·미검증·검증 오류를 구분. 실제 활성 키인지 확인하는 흐름을 함께 고려할 때 비교
detect-secrets탐지 플러그인·베이스라인·감사 절차기존 결과를 기준선으로 관리하고 사람이 분류하는 작업 흐름을 학습하기 좋음

경쟁 도구의 설명은 TruffleHog 공식 문서와 detect-secrets 공식 문서 기준입니다. 이 표는 속도나 정확도 순위가 아닙니다. 동일한 데이터·규칙·실행 조건으로 측정한 비교 수치는 없습니다.

2-3. 초보자가 읽기에도 구조가 알맞다

현재 개발 방향
새 기능 확장보다 보안 패치 중심의 유지 단계

README.md 첫머리는 기능 구현이 완료되어 새 기능을 병합하지 않으며, 향후 릴리스는 보안 패치 중심이고 개발자의 초점은 Betterleaks로 옮겨간다고 안내합니다. 이는 README의 유지 방침입니다. 트렌딩 순위를 활발한 신규 기능 개발의 증거로 해석하면 안 됩니다.

학습할 설계와 사용 가능한 기능은 풍부하지만, 새 기능 기여를 준비한다면 먼저 현재 기여 방침을 확인해야 합니다.

3기술 스택 전체 지도

탐지 엔진 · 사용자 접점 · 빌드와 배포를 나눠 읽기

3-1. 백엔드에 해당하는 핵심 처리부

상시 실행하는 애플리케이션 서버 대신 Go 프로세스가 입력을 읽고 결과를 만듭니다. go.mod의 모듈 경로는 현재 GitHub 조직명과 다른 github.com/zricethezav/gitleaks/v8이며, Go 지시문은 go 1.24.11입니다. 소스의 import를 따라갈 때는 이 모듈 경로를 기준으로 봐야 합니다.

영역실제 의존성과 버전소스에서 맡는 역할
명령 처리spf13/cobra v1.9.1cmd/의 하위 명령·플래그·실행 함수 연결
설정 해석spf13/viper v1.19.0TOML을 읽어 설정 구조체로 변환
키워드 검색BobuSumisu/aho-corasick v1.0.3여러 규칙의 키워드를 함께 찾아 정규식 후보 축소
동시성 제한fatih/semgroup v1.2.0Git 패치·파일 처리 작업의 동시 실행 수 제한
Git 패치 해석gitleaks/go-gitdiff v0.9.1외부 Git 명령의 출력을 파일·추가 행으로 분해
압축 파일mholt/archives v0.1.5압축 형식 식별·내부 파일 읽기
파일 유형h2non/filetype v1.1.3파일 앞부분의 바이트로 형식 판별 보조
로그rs/zerolog v1.33.0경로·커밋·규칙 ID를 붙인 로그 출력
대체 정규식wasilibs/go-re2 v1.9.0gore2regex 빌드 태그를 선택한 경우 사용
테스트 지원testify v1.10.0
google/go-cmp v0.7.0
검증문과 구조체 비교. 제품 실행 기능과 구분해서 읽기

모두 go.mod에 선언된 버전입니다. 선언 버전은 실행 측정값이나 최신 버전 추천을 뜻하지 않습니다. 데이터베이스에 탐지 결과를 쌓는 구조도 아니며, 기본 결과는 메모리의 []report.Finding에 모입니다.

3-2. 프론트엔드에 해당하는 사용자 접점

React·Vue 같은 SPA는 없습니다. 사용자 접점은 터미널이며, charmbracelet/lipgloss v0.5.0으로 발견 결과의 색과 강조를 표현합니다. 정적 보고서는 report/template.go의 Go text/template과 Masterminds/sprig/v3 v3.3.0을 사용합니다.

접점위치실제로 읽을 내용
터미널 표시detect/utils.goprintFinding이 규칙·파일·행·지문을 표시
정적 보고서report_templates/basic.tmpl 등 5개 템플릿. 별도 웹 서비스와 구분
자동화용 출력report/JSON·CSV·JUnit·SARIF 직렬화

NewTemplateReporter는 Sprig 함수 중 env, expandenv, getHostByName을 제거합니다. 한편 text/template은 HTML 자동 이스케이프를 제공하지 않습니다. 새 HTML 보고서를 설계할 때는 입력 문자열을 어떤 문맥에 출력하는지 별도로 검토해야 합니다.

3-3. 인프라·빌드: 파일마다 버전과 경로가 다르다

파일확인한 설정학습 포인트
Dockerfilegolang:1.24 → alpine:3.22
CGO_ENABLED=0
빌드 도구와 실행 환경을 분리하는 2단계 빌드. 실행 이미지에 Git·Bash·OpenSSH 클라이언트 설치
.goreleaser.ymlDarwin·Linux·Windows, 여러 CPU 아키텍처
tags: [gore2regex]
릴리스 빌드는 대체 정규식 엔진 선택. 버전 문자열은 링커 플래그로 주입
.github/workflows/test.ymlGo 1.25, Ubuntu·Windows
go test -json ./... --race
경쟁 상태 검사와 운영체제 차이를 CI에서 확인
.github/workflows/release.yml릴리스가 게시되면 컨테이너 빌드
linux/amd64,linux/arm64
QEMU·Buildx로 다중 아키텍처 이미지 배포
Makefile설정 생성·포맷·모듈 정리·빌드 연결make build는 단순 컴파일 이상의 작업. 버전 계산에는 태그 조회도 포함

의존성 파일의 Go 버전, CI의 Go 버전, 배포 이미지의 Go 버전은 각각 다른 약속이므로 따로 읽어야 합니다. Docker 빌드 명령은 gore2regex 태그를 지정하지 않습니다. 따라서 이 Dockerfile 경로는 regexp/stdlib_regex.go를, GoReleaser 설정은 regexp/wasilibs_regex.go를 선택합니다.

비유

Go 버전과 빌드 태그는 같은 요리를 만드는 조리 기구와 같습니다. 재료 목록이 같아도 조리 기구가 다르면 결과를 비교할 조건이 달라집니다. 성능을 논할 때는 실행 파일을 어떤 경로로 만들었는지까지 기록해야 합니다.

4아키텍처 심화 분석

한 조각이 발견 결과가 되기까지, 함수 호출로 따라가기

4-0. 시스템 구조도

아래 그림은 일반적인 텍스트 검사 경로입니다. 압축 파일은 별도의 내부 파일 읽기를 거친 뒤 같은 경로로 합류합니다. 화살표는 데이터 흐름이며, 각 상자가 모두 별도 프로세스라는 뜻은 아닙니다.

사용자 명령 | v main.go -> cmd.Execute() -> Cobra 하위 명령 | +-- cmd/git.go ---------> sources.Git | | | +-- 외부 git log / git diff | +-- go-gitdiff로 패치 해석 +-- cmd/directory.go ---> sources.Files -> sources.File +-- cmd/stdin.go -------> sources.File (os.Stdin) | v sources.Fragment 본문 + 경로 + 시작 행 + 커밋 정보 | v detect.Detector.DetectSource() | v DetectContext() +----------------+----------------+ | 전역 경로·커밋 허용 목록 확인 | | Aho-Corasick 키워드 사전 검색 | | 후보 규칙별 detectRule() | | 정규식 -> 위치 -> 캡처 그룹 | | 엔트로피 -> 허용 목록 | | 필요 시 디코딩 후 다음 검사 | +----------------+----------------+ | filter()로 중복 후보 조정·가림 | v AddFinding() 지문 계산 -> 무시 목록·베이스라인 -> 저장 | v []report.Finding | v findingSummaryAndExit() 안에서 Reporter.Write() JSON / CSV / JUnit / SARIF / 템플릿 / 종료 코드

4-1. 패턴 ① 입력 어댑터: 탐지기는 입력의 출신을 몰라도 된다

sources/source.go의 핵심 계약은 메서드 하나입니다. 구현체는 조각을 준비할 때마다 콜백인 yield를 부릅니다. 채널 전체를 탐지기 인터페이스로 노출하지 않고, 읽는 쪽의 차이를 이 계약 뒤에 둡니다.

// sources/source.go의 인터페이스
type FragmentsFunc func(fragment Fragment, err error) error

type Source interface {
    Fragments(ctx context.Context, yield FragmentsFunc) error
}

sources.Fragment에는 Raw, Bytes, FilePath, StartLine, CommitInfo 등이 있습니다. DetectSource는 이것을 받아 DetectContext에 넘깁니다. 새로운 입력원을 추가한다면 먼저 이 형식으로 바꾸는 방법을 생각하면 됩니다.

sources/git.go:Git.Fragments는 텍스트 패치에서 textFragment.Raw(gitdiff.OpAdd)로 추가된 행을 꺼냅니다. 기본 Git 명령은 git -C <저장소> log -p -U0 --full-history --all --diff-filter=tuxdb입니다. -U0은 변경 주변의 문맥 행을 0으로 설정합니다. 저장된 모든 커밋의 파일 전체를 매번 다시 여는 방식과 다릅니다.

sources/file.go:fileFragments는 기본 100 * 1_000바이트 버퍼로 읽고, readUntilSafeBoundary가 최대 25 * 1_000바이트를 더 읽어 빈 줄 경계(공백·탭·CR을 사이에 허용한 두 LF)를 찾습니다. sources/common.go의 주석에는 10KB라고 적혀 있지만 상수의 실제 값은 25,000입니다. 경계를 완벽하게 보장하는 알고리즘이 아니라, 문자열을 중간에서 자를 가능성을 줄이는 절충입니다.

비유

여러 나라의 전원 플러그를 하나의 콘센트 규격으로 바꾸는 어댑터와 같습니다. 탐지기를 Git 전용으로 만들지 않았기 때문에 파일·파이프 입력에도 같은 규칙을 적용할 수 있습니다.

4-2. 패턴 ② 단계별 필터: 비싼 검사 전에 후보를 줄인다

NewDetectorContext는 모든 규칙의 키워드로 Aho-Corasick 트라이를 만듭니다. DetectContext는 현재 검사 문자열을 소문자로 바꾸고 그 사전을 검색합니다. 키워드가 없는 규칙은 항상 검사하고, 키워드가 있는 규칙은 그중 하나라도 발견될 때 정규식을 실행합니다.

키워드는 정답을 판정하는 규칙이 아니라, 정규식을 실행할 대상을 줄이는 사전 필터입니다. 검사 조각에 없는 키워드만 규칙에 넣으면 정규식이 정확해도 검사를 건너뛸 수 있습니다.

// cmd/generate/config/rules/github.go:GitHubPat의 핵심 필드
// 설명 문자열과 예외 목록 등은 생략
RuleID:   "github-pat",
Regex:    regexp.MustCompile(`ghp_[0-9a-zA-Z]{36}`),
Entropy:  3,
Keywords: []string{"ghp_"},

detectRule는 정규식 일치 구간을 찾고 원문 위치를 계산한 뒤, SecretGroup이 지정되어 있으면 해당 캡처 그룹을 비밀값으로 선택합니다. 지정하지 않았는데 캡처 그룹이 있다면 첫 번째 비어 있지 않은 그룹을 사용합니다. 그래서 정규식 전체에 일치한 Match와 실제 비밀값인 Secret은 다를 수 있습니다.

그다음 detect/utils.go:shannonEntropy로 문자 분포를 계산합니다. 임계값이 0이 아니면 entropy <= r.Entropy인 후보를 버립니다. GitHubPat의 3은 확률이나 신뢰도 3점을 뜻하지 않습니다.

용어부터
엔트로피는 문자열 분포를 요약한 값
AAAAAAAAAAAA는 반복이 많아 낮고, A1B2C3D4E5F6는 문자가 다양해 더 높습니다. 높다고 반드시 시크릿이 아니며 낮다고 안전하지도 않습니다. 원래 의미는 평균 정보량이고, 여기서는 일부 규칙의 오탐을 줄이는 보조 조건으로 씁니다.

전역·규칙별 허용 목록과 gitleaks:allow 표시도 탐지 결과를 제외할 수 있습니다. processRequiredRules는 보조 규칙이 같은 조각에서 함께 발견되는지 확인하며, 설정된 행·열 거리 조건도 적용합니다. 이 복합 규칙은 같은 조각에서 문맥을 찾으므로, 파일이 나뉘거나 패치에서 문맥이 빠지면 결과도 달라집니다.

filter는 같은 행에서 더 구체적인 규칙이 찾은 비밀값에 포함되는 범용 규칙 결과를 줄입니다. 모든 중복을 전역적으로 제거하는 만능 집합 연산은 아닙니다. 또한 검사 문자열을 디코딩하면 codec.AdjustMatchIndex로 원문 좌표에 맞춥니다.

4-3. 패턴 ③ 제한된 동시성: 작업 수와 공유 상태를 따로 관리한다

detect/detect.go:NewDetectorContext의 초기화에는 semgroup.NewGroup(ctx, 40)이 있습니다. sources.Files.Fragments와 sources.Git.Fragments는 이 그룹에 작업을 넣고 sync.WaitGroup으로 완료를 기다립니다. 파일 수만큼 작업을 무제한으로 동시에 실행하는 설계가 아닙니다.

40은 CPU 코어 요구량이 아닙니다. 이 세마포어 그룹에서 동시에 실행하는 작업 수의 상한입니다. 규칙마다 고루틴을 하나씩 만드는 것도 아닙니다. DetectContext의 규칙 루프와, 입력 소스 쪽의 동시 실행 위치를 구분해 읽어야 합니다.

공유 자원구현왜 필요한가
발견 목록AddFinding의 findingMutex여러 작업이 같은 슬라이스에 동시에 추가하는 문제 방지
검사한 커밋 집합addCommit의 commitMutex여러 패치가 같은 커밋 정보를 다룰 수 있음
처리 바이트 수atomic.Uint64공유 카운터의 갱신 보호
중단 요청context.Context시간 제한·취소를 입력 읽기와 검사 루프에 전달

뮤텍스가 있다고 결과 순서까지 고정되지는 않습니다. 규칙은 map에 담기고 여러 입력 작업이 함께 진행됩니다. JSON 보고서의 행 순서보다 규칙 ID·파일·위치·개수로 결과를 비교하는 편이 적절합니다.

4-4. 패턴 ④ 검증을 거치는 설정 생성: 규칙도 제품의 일부다

config/gitleaks.toml은 생성된 기본 설정입니다. 원본 규칙은 cmd/generate/config/rules/의 Go 함수들입니다. cmd/generate/config/main.go가 이 함수들을 모으고, cmd/generate/config/rules/config.tmpl을 통해 TOML로 내보냅니다.

utils.Validate는 탐지되어야 하는 예제에서 결과가 나오는지, 오탐 예제에서는 결과가 나오지 않는지 실제 탐지기 호출로 확인하는 함수입니다. 생성기의 main은 규칙 검증과 ID 중복 검사도 수행합니다. CI는 go generate ./... && git diff --exit-code로 생성 결과가 저장된 파일과 같은지 확인합니다.

Go 규칙 함수 + 정상 탐지·오탐 예제 | v utils.Validate() | v 생성기 main: 규칙 유효성·ID 중복 검사 | v cmd/generate/config/rules/config.tmpl | v config/gitleaks.toml | v go:embed -> 실행 파일의 기본 설정

실행할 때는 cmd/root.go:initConfig가 설정 출처를 선택하고, config/config.go:ViperConfig.Translate가 문자열 정규식을 컴파일하며 키워드를 정규화합니다. 외부 설정 모양과 내부 실행 구조를 나눈 점도 배울 만합니다. maxExtendDepth = 2로 설정 확장의 깊이를 제한합니다.

마지막 출력은 report.Reporter 인터페이스의 Write로 연결됩니다. cmd/root.go:findingSummaryAndExit는 보고서 출력을 요청한 경우 보고서를 쓴 뒤, 발견 결과가 있으면 기본 종료 코드 1로 프로세스를 종료합니다. 검사 오류도 1이 될 수 있으므로, 자동화에서는 종료 코드와 로그를 함께 읽어야 합니다.

문서와 구현의 차이
복사한 사용 설명보다 실제 기본값을 먼저 확인하세요

README의 도움말·디코딩 설명은 --max-decode-depth 기본값을 0이라고 적지만, cmd/root.go는 5로 등록합니다. 반면 NewDetectorContext 자체는 이 필드를 설정하지 않으므로 라이브러리 생성 직후 값은 0입니다. CLI 초기화와 라이브러리 초기화를 같은 것으로 생각하면 안 됩니다.

README는 dir 별칭을 files·directory라고 설명하지만, cmd/directory.go에는 file·directory가 있습니다. detect/codec/encodings.go에는 README의 목록에 빠진 Unicode 디코더도 있습니다.

5디렉토리 구조 해부

파일 개수보다 책임 경계를 먼저 보고, 작은 경로부터 연결하기
gitleaks/ |-- main.go # 진입점과 인터럽트 처리 |-- go.mod / go.sum # 모듈 경로와 의존성 |-- cmd/ # CLI 명령과 공통 초기화 | |-- git.go # Git 입력 선택 | |-- directory.go # 파일·디렉터리 입력 선택 | |-- stdin.go # 표준입력 선택 | |-- root.go # 플래그·설정·보고서·종료 처리 | |-- scm/ # 저장소 호스팅 플랫폼 구분 | `-- generate/ # 기본 설정과 예제 시크릿 생성 | `-- config/rules/ # 서비스별 탐지 규칙의 원본 |-- sources/ # 입력을 Fragment로 바꾸는 계층 |-- detect/ # 탐지·위치·베이스라인·필터 | `-- codec/ # 인코딩 탐색과 디코딩·좌표 추적 |-- config/ # 설정 구조체·검증·기본 TOML |-- regexp/ # 빌드 태그에 따른 정규식 구현 선택 |-- report/ # 결과 구조와 출력 형식 |-- report_templates/ # 정적 보고서 템플릿 |-- logging/ # 로그 출력 도우미 |-- version/ # 빌드 시 주입하는 버전 |-- testdata/ # 설정·Git 저장소·압축 파일 등 예제 |-- scripts/ # 프로파일링 보조 스크립트 |-- .github/workflows/ # 테스트·자체 검사·이미지 배포 |-- .pre-commit-hooks.yaml # 커밋 전 검사 진입점 |-- Dockerfile # 컨테이너 빌드와 실행 환경 `-- .goreleaser.yml # 운영체제·CPU별 실행 파일 설정

5-1. 처음 읽을 파일 여섯 개

순서파일·함수읽고 답할 질문
1main.go:main프로그램은 어디서 시작하고 어떤 명령 계층으로 넘기는가?
2cmd/stdin.go:runStdIn가장 단순한 입력은 탐지기에 어떻게 연결되는가?
3sources/source.go모든 입력이 지켜야 하는 공통 계약은 무엇인가?
4sources/file.go:fileFragments입력은 어떤 크기와 위치 정보로 나뉘는가?
5detect/detect.go:DetectContext키워드와 규칙 루프, 디코딩의 순서는 무엇인가?
6report/json.go:JsonReporter.Write구조체가 파일로 바뀌는 경계는 어디인가?

첫 회독에는 범위가 넓은 cmd/root.go를 통째로 외우려 하지 않아도 됩니다. 표준입력 한 줄이 JSON 결과가 되는 흐름을 먼저 그린 뒤 Git 입력으로 넓히면 됩니다. detect/git.go 등에는 이전 API와의 호환 경로도 있으므로 현재 CLI가 실제로 호출하는 함수를 출발점으로 삼으세요.

5-2. 줄 수를 책임별로 나누면 읽기 부담이 달라진다

범위파일 수물리적 줄 수
전체 Go 파일21421,579
런타임 비테스트 Go486,469
생성기 영역 Go1399,418
테스트데이터 Go10215
_test.go195,915

전체는 Git이 추적하는 Go 파일이며 빈 줄·주석을 포함합니다. 런타임 비테스트는 cmd/generate/와 testdata/, _test.go를 제외한 수치입니다. 생성기 영역에는 테스트 파일도 들어 있어 일부 행은 서로 겹칩니다. 이 표를 단순 합산하면 안 되며, 테스트 줄 수가 곧 테스트 커버리지도 아닙니다.

읽기 전략
서비스별 규칙을 전부 읽기 전에 대표 규칙 두 개를 고르세요

cmd/generate/config/rules/github.go:GitHubPat은 고정 접두사가 있는 규칙을, cmd/generate/config/rules/generic.go:GenericCredential은 변수명과 문자열을 함께 보는 범용 규칙을 보여줍니다. 두 접근의 차이를 이해한 뒤 관심 있는 서비스 규칙으로 확장하면 됩니다.

6학습 포인트 (기술별)

기능을 따라 만드는 데서 한 걸음 더 나아가, 설계 판단을 설명하기

6-1. Go 인터페이스: 작고 구체적인 계약부터

Source와 Reporter는 각각 입력과 출력의 경계를 정합니다. 전자는 조각을 내보내고, 후자는 발견 목록을 기록합니다. Go는 명시적으로 구현을 선언하지 않아도 필요한 메서드가 있으면 인터페이스를 만족합니다.

// report/json.go의 컴파일 시 인터페이스 만족 검사
var _ Reporter = (*JsonReporter)(nil)

// report/report.go의 출력 계약
type Reporter interface {
    Write(w io.WriteCloser, findings []Finding) error
}

실습 아이디어: 파일을 열지 않는 가상의 입력 소스를 종이에 설계하세요. 문자열 배열을 순서대로 Fragment로 내보낼 때 어떤 필드를 채워야 할까요? 파일 위치가 없다는 사실을 결과에서 어떻게 표현할지도 함께 정합니다.

6-2. 정규식과 알고리즘: 최종 판정과 사전 필터를 분리하기

키워드 검색은 후보 규칙을 좁히고, 정규식은 모양을 확인하며, 엔트로피는 일부 단순한 값을 걸러냅니다. Go 정규식 공식 문서는 입력 크기에 선형인 실행 시간을 설명합니다. 그렇더라도 규칙 수·디코딩 횟수·매치 수가 늘면 전체 비용은 커집니다. 정규식 한 번의 성질과 프로그램 전체의 성능은 구분해야 합니다.

실습 아이디어: 규칙에 올바른 키워드, 엉뚱한 키워드, 빈 키워드 목록을 각각 넣었을 때를 비교하세요. 탐지 여부가 바뀌는 이유를 DetectContext의 분기와 연결하면 사전 필터의 책임이 분명해집니다.

계산을 읽는 법
Shannon 엔트로피
문자별 비율을 p라고 할 때 H = -Σ p × log2(p)입니다. 열두 문자가 모두 다르면 ASCII 예제의 값은 log2(12) ≈ 3.585입니다. 길이와 문자 종류에 영향을 받으므로 모든 토큰에 같은 임계값을 적용할 근거는 없습니다.

shannonEntropy는 문자 수를 map[rune]int로 세면서 분모는 len(data)를 씁니다. Go에서 문자열의 len은 바이트 수입니다. ASCII 시크릿과 다중 바이트 문자열에서 의미가 어떻게 달라질지 손으로 계산해 보세요. 변수명만 보고 “문자 수”라고 읽지 않는 연습이 됩니다.

6-3. Git과 스트리밍: 전체 파일 대신 변경 조각 다루기

NewGitLogCmdContext는 exec.CommandContext로 Git을 실행합니다. Git 저장 형식을 직접 구현하는 대신 Git의 패치 출력과 전용 파서를 조합한 것입니다. 반면 파일 입력은 io.Reader를 읽으므로 표준입력도 같은 타입으로 받을 수 있습니다.

실습 아이디어: 같은 가짜 토큰이 파일에 남은 경우, 커밋 후 파일에서 지운 경우, 이력까지 없는 얕은 저장소인 경우를 표로 비교하세요. “검사 결과가 0”이라는 숫자가 세 경우에서 같은 보장을 뜻하는지 설명해 봅니다.

6-4. 동시성과 오류: 성공·부분 검사·중단을 구분하기

컨텍스트는 종료 요청을 전파하고, 세마포어 그룹은 동시 작업량을 제한하며, 뮤텍스는 공유 상태를 보호합니다. 서로 다른 문제를 푸는 도구들입니다. DetectSource는 조각 콜백으로 받은 오류를 기록하고 다음 조각으로 진행하는 경로도 있습니다.

실습 아이디어: 실제 실행 없이 오류 경로를 색연필 세 색으로 표시해 보세요. 즉시 종료하는 곳, 오류를 반환하는 곳, 로그만 남기고 계속하는 곳을 구분합니다. 종료 코드만으로 검사 완전성을 판단하기 어려운 이유를 찾을 수 있습니다.

6-5. 테스트와 생성 코드: 오탐도 명세에 넣기

config/config_test.go:TestTranslate는 입력 설정·기대 결과·기대 오류를 묶은 표 형식 테스트입니다. sources/common_test.go:Test_readUntilSafeBoundary는 LF·CRLF·공백·안전 경계가 없는 경우를 다룹니다. detect/codec/decoder_test.go:TestDecode는 인코딩과 중첩 변환을 확인합니다.

실습 아이디어: 새 규칙을 만든다고 가정하고 탐지할 예제 3개와 제외할 예제 3개를 먼저 적으세요. 같은 값이 JSON·YAML·환경변수 문법에 들어갔을 때를 포함하면 문자열 하나보다 풍부한 명세가 됩니다. GenerateSampleSecrets가 여러 설정 문법의 예제를 만드는 이유도 여기에 있습니다.

6-6. 데이터 식별과 출력 규격: 지문은 해시가 아니다

AddFinding의 지문은 파일 경로·규칙 ID·시작 행을 연결한 문자열이며, 커밋이 있으면 앞에 커밋 ID도 붙입니다. 내용 자체를 암호학적 해시로 만든 값이 아닙니다. 줄이 이동하면 같은 비밀값이라도 식별 문자열이 달라질 수 있습니다.

# 파일 검사 지문 형태
fixtures/demo.txt:demo-token:1

# Git 검사 지문 형태 — COMMIT은 실제 커밋 ID 자리
COMMIT:demo.txt:demo-token:1

detect/baseline.go:IsNew는 지문 하나만 비교하지 않고 위치·메시지·엔트로피 등 여러 필드를 직접 비교합니다. report/sarif.go:SarifReporter.Write는 같은 발견 결과를 SARIF 2.1.0으로 표현합니다. 내부 식별 정책과 외부 교환 형식이 각각 필요하다는 예입니다.

좋은 학습 목표는 함수 이름을 외우는 것이 아니라, 입력 범위·판정 조건·예외·출력 사이의 계약을 설명하는 것입니다. 같은 설계는 로그 검사기, 코드 린터, 데이터 검증 CLI에도 응용할 수 있습니다.

7하드웨어 / 시스템 요구사항

공식 최저 사양과 학습용 권장 출발점을 혼동하지 않기

README와 빌드 설정에는 CPU·RAM의 공식 최소 수치가 없습니다. GPU·모델 가중치·데이터베이스 서버는 이 탐지 경로의 필수 구성요소가 아닙니다. 실제 자원 사용량은 검사하는 파일·패치·규칙·디코딩·압축 깊이·발견 개수에 따라 달라집니다.

항목확인 가능한 요구·지원초보자용 해석
운영체제GoReleaser 설정에 Linux·macOS·Windows배포 파일의 운영체제와 CPU 아키텍처를 맞춰야 함
Gitgit 모드는 외부 git 명령 호출Git 실행 파일과 읽을 수 있는 로컬 이력 필요
Go소스 빌드 기준 go 1.24.11
테스트 CI는 1.25
완성된 실행 파일을 사용할 때 Go 설치가 반드시 필요한 것은 아님
CPU·RAM공식 최소 수치 미기재작은 학습 저장소부터 검사하고, 입력 규모를 늘리며 자원 사용량 확인
디스크Git 객체·작업 파일·보고서·선택적 임시 파일전체 이력 확보와 압축 검사에서 여유 공간 고려
네트워크일반 탐지 경로는 로컬 내용을 검사설치·이미지 받기·이력 가져오기·CI 서비스 연결은 별도 작업

7-1. 제한 옵션은 속도와 검사 범위를 함께 바꾼다

설정커밋 b58d3f1의 CLI 기본값설정할 때 볼 점
--max-target-megabytes0크기 제한 없음. 양수면 큰 파일·조각을 건너뛸 수 있으므로 검사 범위 기록
--max-decode-depth5인코딩 해제의 재귀 깊이. 0이면 해제 없이 원문만 검사
--max-archive-depth0기본적으로 압축 내부 탐색 안 함. 디코딩 깊이와 별개의 기능
--timeout0초 단위 시간 제한 없음. 제한에 걸리면 완전한 검사 결과로 간주하지 않기
--follow-symlinksfalsedir 전용. 켜도 디렉터리를 가리키는 심볼릭 링크는 건너뜀

sources.Files는 파일 전체 크기를 바이트 단위로 확인하지만, detectRule의 크기 확인은 현재 문자열 길이를 1,000,000으로 나눈 값을 사용합니다. 서로 다른 계층의 검사이므로 모든 모드에 같은 정밀도의 전역 메모리 상한이 생기는 것은 아닙니다.

7-2. 큰 저장소에서는 처리량보다 측정 조건부터

sources/file.go:extractorFragments는 ZIP·7z 입력이 임의 위치 읽기를 지원하지 않으면 임시 파일에 복사하는 경로가 있습니다. 또 발견 결과는 보고서를 쓰기 전까지 슬라이스에 쌓입니다. 따라서 100KB 입력 버퍼 하나만 보고 전체 메모리가 고정이라고 판단하면 안 됩니다.

cmd/diagnostics.go는 CPU·메모리 프로파일과 실행 추적을 지원합니다. 먼저 같은 커밋·규칙·입력 범위·빌드 태그로 조건을 맞추고 한 항목씩 바꿔 측정하세요. 선택적 HTTP 진단 모드는 localhost:6060에 프로파일 서버를 엽니다. CLI 제품에 웹 프론트엔드가 있다는 뜻은 아닙니다.

보고서 취급
검사 결과 파일도 민감한 데이터가 될 수 있습니다

--redact를 생략하면 비밀값이 결과에 남을 수 있습니다. 여기의 실습은 값을 가리지만 파일명·작성자·커밋 메시지 같은 메타데이터까지 전부 없애지는 않습니다. 실습 보고서는 가짜 데이터로 만들고, 실제 보고서를 공개 저장소에 올리지 마세요.

8직접 해볼 수 있는 실습 과제

가짜 값으로 탐지기의 조건을 하나씩 바꾸고 예상과 비교하기

다음 명령은 Gitleaks 실행 파일이 준비된 독자를 위한 실습입니다. Bash·zsh 계열 셸을 기준으로 하며, 보조 파일 생성에는 Python 3을 사용합니다. 실제 계정의 키는 필요 없습니다. 새로 만든 gitleaks-lab 안에서 순서대로 진행하고, 모든 예제는 임의로 정한 가짜 형식 DEMO_를 검사합니다.

발견 결과가 있으면 기본 종료 코드는 1입니다. 자동 종료 옵션을 켠 셸에서는 예상된 탐지 때문에 다음 줄이 실행되지 않을 수 있으므로 명령별로 확인하세요. 아래의 예상 결과는 규칙과 소스 흐름에서 도출한 것이며, 배포 버전 차이는 먼저 gitleaks version으로 기록합니다.

과제 1

내 규칙 하나로 첫 발견 만들기 입문

목표: 기본 규칙과 섞이지 않는 작은 실험 환경을 만듭니다. demo.toml에는 기본 설정 확장을 넣지 않으므로 이 규칙 하나만 사용합니다.

mkdir -p gitleaks-lab/fixtures gitleaks-lab/reports
cd gitleaks-lab
gitleaks version

cat > demo.toml <<'EOF'
title = "학습용 가짜 토큰 검사"

[[rules]]
id = "demo-token"
description = "학습용 DEMO 토큰"
regex = '''DEMO_([A-Z0-9]{12})'''
secretGroup = 1
keywords = ["DEMO_"]
EOF

printf '%s\n' 'DEMO_A1B2C3D4E5F6' > fixtures/demo.txt
gitleaks dir fixtures --config demo.toml --redact \
  --max-decode-depth 0 --report-format json --report-path reports/first.json

# 바로 직전 검사의 종료 코드를 확인한다. 예상: 1
printf '종료 코드: %s\n' "$?"

# 동일한 가짜 값을 표준입력으로 검사한다
printf '%s\n' 'DEMO_A1B2C3D4E5F6' | \
  gitleaks stdin --config demo.toml --redact --max-decode-depth 0

완료 기준: 파일 검사에서 RuleID가 demo-token인 결과 1개, StartLine 1, 가려진 Secret을 확인합니다. 표준입력도 결과가 나오지만 파일·커밋 메타데이터는 같은 방식으로 기대하지 않습니다.

생각할 질문: 정규식 전체는 접두사를 포함하는데 비밀값은 왜 열두 글자일까요? detectRule의 캡처 그룹 선택 부분과 연결해 설명하세요.

과제 2

정규식이 맞는데도 탐지되지 않는 이유 찾기 중급

목표: 사전 필터와 엔트로피 조건을 분리해서 이해합니다. 원본 demo.toml은 보존하고 복사본 두 개로 실험하세요.

  1. keyword.toml을 만들고 keywords = ["NEVER_PRESENT_"]로 바꿉니다.
  2. entropy.toml을 만들고 원래 키워드는 유지한 채 entropy = 4.0을 규칙에 추가합니다.
  3. 아래 명령으로 각각 같은 파일을 검사하고, 결과가 줄어든 지점을 소스에서 찾습니다.
gitleaks dir fixtures --config keyword.toml --redact --max-decode-depth 0
gitleaks dir fixtures --config entropy.toml --redact --max-decode-depth 0

완료 기준: 첫 번째는 키워드 불일치로 정규식 실행 전에 제외됩니다. 두 번째는 캡처한 열두 글자의 엔트로피가 약 3.585이므로 4.0을 넘지 못합니다. 다른 오류가 없다면 두 검사 모두 발견 0개·종료 코드 0을 예상합니다.

추가 질문: 엔트로피 임계값을 낮추는 것이 언제 오탐을 늘리고 언제 미탐을 줄일까요? 높은 수치가 항상 좋은 설정이라는 생각을 버리고, 예제 집합으로 설명해 보세요.

과제 3

지운 토큰을 Git 이력에서 다시 찾기 중급

목표: 현재 디렉터리 검사와 이력 검사의 보장 범위를 구분합니다. 다음 명령은 실습용 저장소에만 작성자 설정과 두 커밋을 만듭니다.

mkdir history-lab
cd history-lab
git init -q
git config user.name '학습자'
git config user.email 'learner@example.invalid'
printf '%s\n' 'DEMO_A1B2C3D4E5F6' > demo.txt
git add demo.txt
git commit -q -m '학습용 가짜 토큰 추가'
printf '%s\n' '공개 가능한 예제' > demo.txt
git add demo.txt
git commit -q -m '현재 파일에서 가짜 토큰 제거'
cd ..

gitleaks dir history-lab --config demo.toml --redact --max-decode-depth 0
gitleaks git history-lab --config demo.toml --redact --max-decode-depth 0

완료 기준: 현재 파일 검사에서는 0개, Git 이력 검사에서는 최초 추가 커밋의 결과 1개를 예상합니다. 삭제·변경한 두 번째 커밋이 과거의 Git 객체를 없애지 않았기 때문입니다.

생각할 질문: 깊이 1로 최신 커밋만 가진 저장소에서도 같은 결과를 기대할 수 있을까요? 보이지 않는 과거 이력까지 검사했다고 말할 수는 없습니다. 실제 자격 증명이었다면 파일 수정 외에 키 폐기·재발급 등 권한 자체의 처리도 필요합니다.

과제 4

인코딩과 압축의 서로 다른 깊이 이해하기 중급

목표: 문자열을 풀어 읽는 일과 압축 내부 파일을 여는 일을 구분합니다. gitleaks-lab에서 두 종류의 입력을 만듭니다.

python3 - <<'PY'
from pathlib import Path
import base64
import zipfile
fake = b'DEMO_A1B2C3D4E5F6'
Path('encoded.txt').write_text(base64.b64encode(fake).decode() + '\n')
with zipfile.ZipFile('bundle.zip', 'w', compression=zipfile.ZIP_DEFLATED) as z:
    z.writestr('demo.txt', fake + b'\n')
PY

# Base64 원문만 볼 때와 한 번 해제할 때
gitleaks dir encoded.txt --config demo.toml --redact --max-decode-depth 0
gitleaks dir encoded.txt --config demo.toml --redact --max-decode-depth 1 \
  --report-format json --report-path reports/decoded.json

# 압축 내부 탐색은 별도의 옵션이다
gitleaks dir bundle.zip --config demo.toml --redact --max-archive-depth 0
gitleaks dir bundle.zip --config demo.toml --redact --max-archive-depth 1 --verbose

완료 기준: Base64는 깊이 0에서 0개, 깊이 1에서 1개를 예상합니다. ZIP은 압축 깊이 0에서 내부를 건너뛰고, 1에서 bundle.zip!demo.txt의 결과가 나옵니다. 디코딩 결과의 태그와 원문 좌표는 reports/decoded.json의 Tags·StartLine·StartColumn·EndColumn에서 확인하세요.

생각할 질문: 인코딩을 알아보는 정규식 자체에도 길이·문자 조건이 있습니다. 임의의 모든 암호문을 복원하는 기능이라고 해석하면 안 되는 이유를 설명하세요.

과제 5

베이스라인으로 신규 발견만 구분하기 고급

목표: “이전에 본 결과”와 “안전한 값”을 구분합니다. 과제 1의 fixtures/demo.txt만 검사하며 보고서는 reports/에 둡니다.

# 최초 결과 1개를 기준선으로 기록. 예상 종료 코드: 1
gitleaks dir fixtures --config demo.toml --redact --max-decode-depth 0 \
  --report-format json --report-path reports/base.json

# 같은 입력과 같은 가림 정책. 예상 발견: 0개
gitleaks dir fixtures --config demo.toml --redact --max-decode-depth 0 \
  --baseline-path reports/base.json

# 새 행에 다른 가짜 토큰 추가
printf '%s\n' 'DEMO_Z9Y8X7W6V5U4' >> fixtures/demo.txt

# 신규 결과만 보고서에 기록. 예상 발견: 1개
gitleaks dir fixtures --config demo.toml --redact --max-decode-depth 0 \
  --baseline-path reports/base.json \
  --report-format json --report-path reports/new.json

완료 기준: 신규 보고서에 두 번째 행만 남는 이유를 IsNew의 필드 비교로 설명합니다. 가린 상태에서는 비밀값 비교를 생략하는 조건도 읽어보세요. 같은 위치의 값만 바꾸는 실험을 더하면 베이스라인의 의미를 더 정확히 이해할 수 있습니다.

심화 설계: .gitleaksignore 지문, 허용 목록, 베이스라인 중 무엇을 사용할지 상황별로 표를 만드세요. 예외의 근거·적용 범위·재검토 시점을 적되, 신규 기능 기여 여부는 현재 유지 방침과 따로 판단합니다.

실습에서 가장 중요한 기록은 발견 개수와 함께 남긴 검사 범위·설정·버전입니다. 결과가 예상과 다르면 기본값, 설정 출처, 경로, 이력 깊이, 허용 목록 순서로 확인하세요.

9관련 기술 심화 학습 로드맵

6주 동안 작은 CLI에서 검사 도구의 전체 계약으로 확장하기

주당 3~5시간을 가정한 학습 제안입니다. 공식 소요 시간이 아닙니다. Go 문법을 처음 접한다면 1주차를 늘리고, 이미 CLI를 만들어 봤다면 3주차부터 시작해도 좋습니다.

주차배울 기술·읽을 위치남길 결과물
1주차Go 구조체·슬라이스·인터페이스
main.go, sources/source.go, report/finding.go
표준입력 한 줄이 발견 구조체가 되는 흐름 그림과 필드 설명
2주차Cobra 명령·플래그, Viper와 TOML
cmd/root.go, config/config.go
설정 우선순위 표와 과제 1의 전용 규칙
3주차정규식·캡처 그룹·키워드 사전·정보량
detectRule, cmd/generate/config/rules/github.go, cmd/generate/config/rules/generic.go
탐지·오탐·미탐 예제표와 과제 2의 원인 설명
4주차Git 패치·스트리밍·디코딩 좌표
sources/git.go, sources/file.go, detect/codec/
현재 파일과 이력의 비교표, 과제 3·4의 관찰 기록
5주차컨텍스트·동시성 제한·뮤텍스·테스트
NewDetectorContext, sources/common_test.go
공유 상태 목록과 오류·취소 경로 그림
6주차베이스라인·SARIF·생성 코드·CI
detect/baseline.go, report/sarif.go, .github/workflows/test.yml
과제 5의 비교 결과와 팀에 적용할 검사 정책 초안

9-1. 다음 단계는 다른 입력을 가진 작은 검사기

Gitleaks 전체를 복제하기보다, 학습용 로그에서 금지된 패턴을 찾는 CLI를 설계해 보세요. 입력은 파일·표준입력 두 가지, 결과는 JSON 하나로 시작합니다. 규칙·입력·보고서를 서로 분리하고, 오류와 발견을 구분하는 계약을 먼저 적습니다.

이해 확인
결과를 설명할 수 있을 때 한 주를 마칩니다

“명령을 실행했다”보다 “왜 이 행은 탐지되고 저 행은 제외되는가”를 설명해 보세요. 함수·설정값·테스트 예제를 근거로 답할 수 있으면 다음 주제로 넘어갈 준비가 된 것입니다.

10핵심 키워드 사전

코드에 자주 나오는 말과 이 저장소에서의 구체적인 뜻
용어쉬운 설명
시크릿공개되면 안 되는 값. API 키·비밀번호·토큰 등이 대표적입니다.
하드코딩값을 프로그램이나 설정 파일 안에 직접 적는 일입니다.
CLI터미널의 명령과 옵션으로 사용하는 프로그램입니다.
표준입력프로세스가 입력을 받는 기본 통로. 파일이나 다른 명령 출력을 연결할 수 있습니다.
스테이징다음 커밋에 넣을 변경을 Git 인덱스에 골라 놓는 단계입니다.
패치·diff파일 사이의 차이. Git 모드는 패치에서 추가된 텍스트를 검사합니다.
얕은 이력최근 일부 커밋만 가진 이력. 없는 과거까지 검사할 수는 없습니다.
Fragment본문과 경로·시작 행·커밋 정보를 묶은 검사 조각입니다.
규칙 ID어떤 탐지 조건에서 결과가 나왔는지 식별하는 이름입니다.
정규식문자열의 모양을 표현하는 문법. 접두사·길이·허용 문자를 검사합니다.
캡처 그룹정규식의 괄호로 뽑는 부분. 전체 일치에서 비밀값만 고를 때 씁니다.
Aho-Corasick여러 키워드를 함께 찾는 알고리즘. 여기서는 검사할 규칙을 줄입니다.
트라이문자열의 접두사를 공유하는 나무 형태의 자료구조입니다.
엔트로피문자의 분포를 정보량으로 요약한 수치. 일부 규칙의 보조 조건입니다.
오탐·미탐시크릿이 아닌데 경고하면 오탐, 실제 시크릿을 놓치면 미탐입니다.
허용 목록특정 경로·값·커밋 등을 검사나 결과에서 제외하는 정책입니다.
베이스라인이전에 발견한 결과의 기준 목록. 기존 결과를 신규 보고에서 빼는 데 씁니다.
지문파일·규칙·행·선택적 커밋으로 만든 식별 문자열. 비밀값의 해시는 아닙니다.
Redact결과에서 비밀값을 가리는 처리. 해당 키를 폐기하는 작업과 다릅니다.
고루틴Go의 동시 실행 단위. CPU 코어 하나와 일대일로 대응하지 않습니다.
뮤텍스여러 작업이 같은 데이터를 동시에 바꾸지 못하도록 잠그는 장치입니다.
컨텍스트시간 제한·취소 같은 제어 정보를 함수 호출 사이에 전달하는 값입니다.
빌드 태그컴파일할 파일을 조건에 따라 선택하는 표시. 정규식 구현 교체에 사용합니다.
go:embed파일 내용을 컴파일한 실행 파일 안에 포함하는 Go 지시문입니다.
SARIF정적 분석 결과를 도구끼리 주고받기 위한 표준 형식. 이 구현은 2.1.0을 출력합니다.
CI·생성물 검증변경마다 검사를 자동 수행하고, 생성한 설정과 저장된 설정의 차이도 확인하는 과정입니다.

영어 식별자를 모두 번역해서 기억할 필요는 없습니다. Source는 조각을 만들고, Detector는 발견을 만들며, Reporter는 결과를 기록한다는 세 문장을 출발점으로 삼으세요.

11참고 링크

공식 문서와 코드의 기준점을 함께 두고 다시 찾아보기

11-1. 공식 저장소·사용 문서

11-2. 본문에서 따라간 소스

11-3. 관련 기술을 더 읽을 곳

현재 상태 (2026-10-23 확인)

항목값과 기준
저장소gitleaks/gitleaks · 설명: Find secrets with Gitleaks 🔑
트렌딩GitHub Trending Go Weekly #3 · 2026-10-23
스타 / 포크30,253 / 2,311 · 2026-10-23 GitHub 기준
생성일2018-01-27
주 언어 / 라이선스Go / MIT
최신 릴리스v8.30.1 · 2026-03-21 · 2026-10-23 GitHub 기준
최근 push2026-09-30 · 2026-10-23 GitHub 기준
코드 기준 커밋b58d3f1 · 2026-07-22
GitHub Actions 의존성 갱신 PR #2197 병합. 10월의 기본 브랜치 최신 커밋이라는 뜻은 아님
전체 추적 파일454개 · 분석 커밋의 파일 목록 기준
Go 코드 규모214개 파일 / 21,579줄. 비테스트 195개 / 15,664줄, 테스트 19개 / 5,915줄
설정·문서 규모TOML 52개 / 4,008줄 · YAML 8개 / 265줄 · Markdown 13개 / 902줄
보조 코드·템플릿Python 1개 / 27줄 · 셸 1개 / 80줄 · 보고서 템플릿 5개 / 3,890줄
기본 탐지 규칙config/gitleaks.toml의 [[rules]] 222개. 서비스 수와 같지 않음
빌드 기준go.mod: 1.24.11 · 테스트 CI: 1.25 · Docker 빌드: 1.24
유지 방침README 기준 신규 기능 병합 종료·보안 패치 중심, Betterleaks로 개발 초점 이동

줄 수는 해당 확장자의 추적 파일을 대상으로 빈 줄·주석을 포함해 센 물리적 줄 수이며, 끝에 개행이 없어도 마지막 행을 포함합니다. .git 내부 데이터는 제외하며, Go에는 생성기와 테스트데이터가 포함됩니다. 보고서 템플릿은 HTML·CSS 등의 혼합 내용이므로 순수 HTML 또는 JavaScript 줄 수로 분리하지 않았습니다. 전체 파일 수에는 위 표에서 따로 집계하지 않은 확장자의 파일도 포함됩니다.

사용 전에 알아둘 한계
탐지 결과는 검사한 범위와 규칙 안에서만 해석해야 합니다

이 글의 코드는 커밋 b58d3f1 기준이며, 2026-10-23 GitHub 메타데이터와 시점이 다릅니다. 릴리스 실행 파일·이후 코드가 같은 기본값과 동작을 가진다고 보장하지 않습니다. 신규 기능 종료 안내와 README의 기본값 불일치도 함께 고려하세요.

키워드·정규식·엔트로피 기반 검사는 오탐과 미탐이 있습니다. 서비스 API로 자격 증명의 활성 여부를 확인하거나, 발견한 키를 자동 폐기하는 경로는 여기서 설명한 탐지 흐름에 없습니다. 압축 깊이·파일 크기 제한·허용 목록·조각 경계·얕은 Git 이력은 검사 범위를 바꿀 수 있습니다.

베이스라인은 과거 결과를 숨기는 기준이지 안전 판정이 아닙니다. 오류 로그와 부분 검사 여부를 함께 읽어야 하며, 발견 0개만으로 유출이 전혀 없었다고 결론 내릴 수 없습니다. 제시한 실습의 예상 결과는 소스와 규칙에서 도출한 값으로, 성능·메모리·테스트 커버리지의 실측 결과는 아닙니다.