mrgoonie/maskara. Claude Code·Codex·Cursor·Gemini CLI 같은 코딩 에이전트가 디스크에 남긴 대화 로그를 훑어, 거기 섞여 들어간 OpenAI·Anthropic·GitHub·AWS 토큰, JWT, 개인키, DB 접속 주소 같은 비밀값을 찾아내는 작은 Go 명령줄 도구다. 찾은 비밀은 전체를 보여주지 않고 가린 미리보기 + SHA-256 지문만 리포트(마크다운·JSON)로 남기고, 원하면 로컬 사본을 *.maskara.bak 백업과 함께 가림 처리(redact)한다. 핵심은 철저히 오프라인 — 발견한 내용을 어디로도 보내지 않는다. 이름은 mascara(마스카라) + mask(가리다)의 합성어. (저장소: mrgoonie/maskara · 언어 Go · ★낮음(초기 v0.1단계) · 라이선스 MIT · TrendShift 라이브 멘션 등재)
"AI한테 시킨 작업 기록에 비밀번호가 적혀 있진 않은지, 내 컴퓨터 안에서만 조용히 점검한다."
요즘 우리는 Claude Code, Codex, Cursor 같은 AI 코딩 에이전트에게 일을 시키면서 "이 API 키로 테스트해줘", ".env 파일 좀 봐줘" 같은 말을 무심코 한다. 그 대화는 전부 내 컴퓨터의 로그 파일로 차곡차곡 쌓인다. maskara는 그 로그 더미를 훑어 "여기 진짜 비밀번호가 적혀 있다"를 짚어주고, 그 자리에 안전한 표식을 덮어쓴다. 마치 마스카라가 번지면 닦아내듯, 새어 나간 비밀을 가려준다.
[MASKARA_REDACTED:openai-api-key] 같은 표식으로 바꿔치기해, 원래 값을 파일에서 지워 버린다(원본은 백업).구체적으로 maskara는 Go로 짜인 단일 바이너리 CLI다. 아직 초기 단계(v0.1 수준)의 작은 프로젝트지만 구조가 깔끔하다. 인자 없이 그냥 maskara라고 치면 "스캔 → (백업 후) 가림 → 리포트 작성"의 전체 워크플로가 한 번에 돌고, scan/report/guardrails 하위 명령으로 단계를 나눠 쓸 수도 있다. 이름 그대로 마스카라(mascara) + 마스크(mask) — "비밀을 흘려 울지 않으려면 가려라"는 농담 섞인 작명이다.
이 문서가 주목하는 건 도구의 사용법만이 아니라 그 안의 설계다. "정규식으로 비밀을 어떻게 잡아내는가", "전체 값을 안 보여주면서 어떻게 같은 비밀임을 증명하는가(지문)", "남의 파일을 고치는 위험한 작업을 어떻게 안전하게 하는가" — 보안 도구를 처음 만들어 보려는 개발자에게 좋은 교본이다.
"비밀은 git 저장소만 새는 게 아니다 — AI와의 대화 기록이 새로운 구멍이다."
전통적으로 "비밀 유출"은 git 커밋에 .env를 실수로 넣는 것을 뜻했다. 그래서 git-secrets, ggshield 같은 도구가 커밋 전에 막아준다. 그런데 AI 코딩 에이전트 시대에는 완전히 새로운 누출 경로가 생겼다. 사용자가 에이전트에게 "이 토큰으로 API 호출해줘", "왜 인증이 안 되는지 봐줘" 하며 비밀값을 채팅에 그대로 붙여넣고, 에이전트도 디버깅하다 키를 출력한다. 이 모든 대화는 ~/.claude/projects, ~/.codex/sessions 같은 곳에 JSON·JSONL 로그로 영구 저장된다. git에는 안 올라가니 기존 도구는 못 잡지만, 백업·동기화·실수 공유로 새어 나갈 수 있는 진짜 위험이다.
로컬 에이전트 로그는 보통 평문(plain text)이다. 클라우드 백업(iCloud·OneDrive)에 딸려 올라가거나, 디버깅 로그를 통째로 이슈에 첨부하거나, 화면 공유 중 노출되는 식으로 새어 나간다. 게다가 한 번 대화에 들어간 키는 이미 모델 제공사 서버에도 전송된 상태다. 그래서 maskara의 철학은 "발견 = 이미 노출됐다고 가정하고 즉시 폐기·재발급(rotate)하라"는 것 — 로컬 가림은 추가 확산을 막을 뿐, 만능 방패가 아니다.
maskara가 사람들 눈에 띈 이유는 이 틈새를 정확히 겨냥했기 때문이다. 같은 "시크릿 스캐너"라도 대상이 다르다.
| 항목 | maskara | ggshield (GitGuardian) | git-secrets |
|---|---|---|---|
| 스캔 대상 | 에이전트 세션 로그 (~/.claude 등) | git 저장소·커밋·diff | git 커밋(커밋 직전 훅) |
| 네트워크 | 완전 오프라인 | 클라우드 API로 검증 | 오프라인 |
| 가림(redact) | 로컬 사본을 직접 가림 + 백업 | 탐지·차단 위주 | 커밋 차단 위주 |
| 예방 장치 | 가드레일(에이전트 훅·지침) 설치 | pre-commit 훅 | git 훅 |
| 규모 | 초기 v0.1 소형 Go CLI | 성숙한 상용/OSS | 성숙한 OSS |
기존 도구가 git이라는 문을 지켰다면, maskara는 에이전트 로그라는 새 문을 지킨다. 그리고 비밀을 다루는 도구가 그 비밀을 어디로도 보내지 않는다는 점(완전 오프라인)이 핵심 신뢰 포인트다 — 시크릿 스캐너를 쓰려다 오히려 시크릿을 클라우드로 보내는 모순을 피한다.
요약하면 주목 포인트는 셋이다. ① 새로운 위협 모델(에이전트 로그 누출)을 정조준했고, ② 탐지에서 그치지 않고 가림·백업·예방(가드레일)까지 한 바퀴를 돌며, ③ Go 단일 바이너리라 설치가 가볍고 오프라인이다. 다만 아직 작고 어린 프로젝트라, 탐지 규칙 수나 성숙도는 상용 도구에 못 미친다는 점은 솔직히 감안해야 한다.
"Go 표준 라이브러리만으로 — 외부 의존성이 거의 없는, 의도된 미니멀 설계."
maskara의 go.mod를 열면 놀랍도록 비어 있다. 모듈 선언과 Go 1.25 한 줄뿐, 외부 라이브러리 의존성이 사실상 0개다. CLI 파싱도 cobra 같은 인기 프레임워크 대신 표준 라이브러리 flag 패키지로 직접 짰다. 보안 도구일수록 의존성을 줄여 공급망 위험(남의 코드에 숨은 악성)을 없애려는 의도된 선택이다.
regexp), 해시(crypto/sha256), 파일 탐색(path/filepath), CLI 인자(flag), JSON까지 표준 라이브러리만으로 풍부하다. 외부 패키지를 끌어오지 않으면 빌드가 빠르고, "남의 코드를 믿어야 하는 위험"이 줄어든다. 보안 도구가 특히 선호하는 방식.| 레이어 | 기술 | 역할 |
|---|---|---|
| 언어 | Go 1.25 | 전체 구현. CGO_ENABLED=0로 빌드해 의존성 없는 단일 정적 바이너리 생성 |
| CLI 파싱 | 표준 flag 패키지 | 서브커맨드(scan·report·guardrails)와 플래그(-a·--root·-o·--json) 직접 구현. cobra 미사용 |
| 탐지 엔진 | 표준 regexp | OpenAI·Anthropic·GitHub·AWS·Slack·Stripe·JWT·개인키·DB URL·env 대입 등 11종 패턴 |
| 지문 | 표준 crypto/sha256 | 비밀값을 해시해 12자 지문 생성 — 전체 값 없이 동일성 비교 |
| 가드레일 자산 | embed.FS | 지침·스킬·훅 파일을 바이너리에 내장(//go:embed)해 별도 파일 없이 배포 |
| 릴리스 | GoReleaser v2 | linux·darwin·windows × amd64·arm64 = 6종 바이너리를 한 번에 빌드·패키징 |
| CI | GitHub Actions | ubuntu·macos·windows 3-OS 매트릭스에서 go test ./... + 빌드. 푸시마다 semantic 릴리스 |
.goreleaser.yaml) 하나로 리눅스/맥/윈도우 × amd64/arm64를 동시에 만들어 GitHub Releases에 올린다. "한 번 누르면 전 플랫폼 설치본이 나오는" 자판기. maskara는 conventional commits에서 버전을 자동으로 정하는 semantic-release까지 붙여 두었다."내가 maskara 한 줄을 치면, Claude 로그 속 sk-... 토큰 하나가 발견되어 가려지기까지 안에서 무슨 일이 벌어지나."
maskara는 작지만 내부 패키지(internal/)가 책임별로 깔끔히 갈려 있다. 각 패키지가 컨베이어 벨트의 한 공정처럼 결과를 다음으로 넘긴다. 먼저 기본 워크플로(인자 없는 maskara) 전체 그림을 보자.
sk-로 시작해 영숫자가 20자 이상 이어진다. 이 모양을 정규식 sk-...{20,}로 적어 두면, 로그를 훑으며 그 모양에 맞는 부분을 전부 집어낸다. "특정 양식의 종이만 골라내는 분류기"라고 보면 된다.maskara의 심장은 internal/detect의 규칙 카탈로그다. 비밀의 종류마다 "이런 모양이다"라는 정규식 + 심각도(critical/high/medium)를 한 줄씩 적어 둔 표다. 실제 규칙 몇 개를 보자(요점만).
// internal/detect/detect.go — DefaultRules() (발췌, 단순화)
{ID: "openai-api-key", Sev: critical, Expr: `\bsk-(?:proj-)?[A-Za-z0-9_-]{20,}\b`},
{ID: "anthropic-api-key",Sev: critical, Expr: `\bsk-ant-[A-Za-z0-9_-]{20,}\b`},
{ID: "github-token", Sev: critical, Expr: `\bgh[pousr]_[A-Za-z0-9_]{36,}\b ...`},
{ID: "aws-access-key", Sev: high, Expr: `\b(?:AKIA|ASIA)[0-9A-Z]{16}\b`},
{ID: "jwt", Sev: high, Expr: `\beyJ...\....\....\b`},
{ID: "private-key", Sev: critical, Expr: `-----BEGIN ... PRIVATE KEY----- ...`},
{ID: "database-url", Sev: critical, Expr: `postgres|mysql|mongodb|redis ://...`},
{ID: "env-secret", Sev: medium, Expr: `(api_key|secret|token|password)=...`, ValueGroup: 1}
읽는 법은 간단하다. 각 규칙은 고유 ID + 심각도 + 정규식 세 가지가 핵심이다. 대부분은 매칭된 전체를 비밀로 보지만, 마지막 env-secret처럼 API_KEY=실제값 형태는 등호 뒤의 값만 비밀이므로 ValueGroup으로 "정규식 안 1번 괄호 그룹만 잡으라"고 지정한다. 매칭 뒤에는 겹치는 결과를 정리하고(dedupeOverlaps), 이미 가려진 표식(MASKARA_REDACTED)은 다시 잡지 않도록 거른다.
정규식 카탈로그는 지명수배 몽타주 모음집이다. "이마에 sk- 문신, 키 20자 이상" 같은 인상착의를 종류별로 적어 두면, 순찰(스캔) 중 그 인상에 맞는 인물(문자열)을 전부 검거한다. 몽타주가 11장이라도 마을 전체(로그)를 한 번에 훑을 수 있고, 새 유형이 나타나면 몽타주 한 장만 추가하면 된다 — 이게 데이터(규칙)와 실행(스캐너)을 가른 효과다.
비밀을 찾았다고 리포트에 통째로 적으면, 리포트 자체가 또 하나의 유출이 된다. maskara는 이를 두 가지로 푼다.
// Mask: 앞 4 + ... + 뒤 4 만 남긴다 (8자 이하면 그냥 ***)
Mask("sk-proj-abcdEFGH1234wxyz") → "sk-p...wxyz"
// 지문: 전체 값을 SHA-256 해시 → 앞 12자만 표시
sha256("sk-proj-abcdEFGH1234wxyz") → "9f86d081884c"...
덕분에 리포트는 "어느 파일·몇 번째 줄에, 어떤 종류의 비밀이, 가려진 미리보기와 지문은 무엇"까지만 담는다. 사람은 그것만으로 "아, 그 Stripe 키구나"를 알아채 폐기할 수 있고, 리포트가 새어도 진짜 비밀은 안 새는 것이다.
남의 파일을 프로그램이 직접 수정하는 건 위험하다. internal/redact는 여러 안전장치를 겹쳐 둔다. ① 스캔 대상(targets) 바깥 경로는 거부, ② 심볼릭 링크는 거부, ③ 무엇보다 수정 전에 원본을 *.maskara.bak으로 백업한 뒤에야 덮어쓴다. 비밀 위치(start~end)를 뒤에서부터 잘라내 표식으로 바꾸는데(앞에서 바꾸면 뒤 위치가 어긋나므로), JSON처럼 구조가 깨지면 안 되는 파일은 구조 보존 방식으로 다시 시도한다.
// "Claude 로그에 들어간 OpenAI 키 하나"가 가려지기까지 (개념 단순화)
① $ maskara → cli가 "기본 워크플로"로 진입
② agents.Resolve("auto") → ~/.claude/projects 가 존재 → 스캔 타깃 확정
③ scanner가 walk → conversation.jsonl (텍스트·25MB 이하) 통과, .png는 skip
④ detect.Find: 줄 안에서 sk-proj-abcd... 가 openai 규칙에 매칭
⑤ Finding 생성: preview "sk-p...wxyz", sha256 "9f86...", line=42
⑥ report.WriteOutput: 마크다운 표에 가린 미리보기+지문 기록 (값 없음)
⑦ redact.Apply: conversation.jsonl 을 .maskara.bak 로 백업
⑧ 원본의 그 자리를 [MASKARA_REDACTED:openai-api-key] 로 덮어씀
⑨ 종료 코드 1 반환 (findings 있음) — CI 등에서 "샜다"를 감지 가능
여기서 배울 핵심은 "읽기(스캔)·보고(리포트)·고치기(가림)가 깔끔히 분리"돼 있다는 점이다. 그래서 scan은 안전하게 들여다보기만 하고, report는 기록만 남기며, 위험한 파일 수정(가림)은 전체 워크플로일 때만 일어난다. 사용자가 "얼마나 위험한 일까지 허용할지"를 명령으로 고르게 한 설계다.
"엔트리포인트 한 줄(cmd) + 책임별 internal 패키지 한 줌 — 작아서 하루면 다 읽는다."
maskara는 Go의 관례적 구조를 따른다. 실행 진입점은 cmd/에, 실제 로직은 외부에서 import 못 하는 internal/에 두어 "공개 API가 아니라 도구 내부 부품"임을 분명히 한다.
| 경로 | 역할 |
|---|---|
| cmd/maskara/ | 실행 진입점. main()이 os.Args를 cli.Execute에 넘기고 종료 코드로 끝낸다(로직 없음) |
| internal/cli/ | 두뇌 격 조립부. 서브커맨드 분기, 플래그 파싱, "scan→redact→report" 순서 엮기, 종료 코드 결정 |
| internal/agents/ | 지원 에이전트 17종의 정규명·별칭·기본 로그 경로. auto(존재하는 것만)·all 해석 |
| internal/scanner/ | 디렉토리를 재귀 탐색(walk)하며 .git/node_modules 등 skip, 바이너리·25MB 초과·무관 확장자 제외 |
| internal/detect/ | 핵심 탐지 엔진. 정규식 카탈로그·마스킹·지문·중복 정리 |
| internal/redact/ | 가림 처리 전담. 경로 안전검사·심링크 거부·백업·원자적 쓰기·JSON 구조 보존 |
| internal/guardrails/ | 예방책 설치기. embed.FS로 내장한 지침·스킬·훅을 에이전트별 위치에 배치(기존 파일 백업) |
| internal/version/ | 버전 문자열. 빌드 시 -ldflags -X로 값 주입(소스엔 "dev"만) |
internal/ 폴더 안의 코드는 그 프로젝트 바깥에서 import할 수 없다. 즉 "이건 우리 내부 부품일 뿐, 라이브러리로 가져다 쓰라고 만든 게 아니다"를 컴파일러가 강제한다. 식당의 '관계자 외 출입금지' 주방 같은 것. 덕분에 maskara는 내부 구조를 자유롭게 바꿔도 외부 사용자와의 호환성을 신경 쓸 필요가 없다."작은 레포 하나에 'Go CLI · 정규식 보안 · 안전한 파일 IO · 릴리스 자동화'가 압축돼 있다."
maskara는 코드량이 적어 처음부터 끝까지 읽어볼 수 있는 드문 실전 예제다. 분야별로 무엇을 배울지 + 작게 실습할 거리를 정리했다.
배울 것: cobra 같은 프레임워크 없이 flag 패키지만으로 scan/report/guardrails 서브커맨드와 단·장 플래그(-a/--agent)를 짜는 법. FlagSet을 명령마다 따로 만들고, 입력 검증 후 종료 코드로 결과를 알리는 패턴.
실습: cli.go의 Execute가 args[0]로 분기하는 부분을 따라 읽고, 새 서브커맨드 하나(예: maskara rules = 규칙 목록 출력)를 상상해 시그니처를 그려 보기.
배울 것: 비밀의 "모양"을 정규식으로 기술하는 법(접두사·길이·문자집합), 캡처 그룹으로 값만 뽑기(ValueGroup), 그리고 겹친 결과 정리. 핵심은 오탐(false positive)과 미탐의 균형 — 너무 느슨하면 평범한 문자열을 비밀로 오인하고, 너무 빡빡하면 진짜를 놓친다.
실습: detect.go의 규칙 하나를 골라 정규식을 한 조각씩 해부(예: \bsk-...{20,}\b의 \b가 왜 필요한지). 그다음 새 패턴 하나(예: Telegram 봇 토큰)를 상상해 정규식을 적어 보기.
배울 것: filepath.WalkDir로 디렉토리 재귀 탐색, .git·node_modules 같은 폴더 건너뛰기(SkipDir), 바이너리 판별(앞부분에 0바이트가 있나), 용량 상한. 그리고 파일을 고치기 전 반드시 백업하고, 경로가 대상 밖이면 거부하는 방어적 코딩.
실습: scanner.go의 looksLikeSessionText·isBinary를 읽고 "왜 .png는 스캔 안 하나"를 설명해 보기. redact.go가 왜 뒤에서부터 치환하는지 종이에 위치 인덱스를 그려 확인.
배울 것: 하나의 Go 코드에서 6종 바이너리를 뽑는 크로스 컴파일(goos×goarch), -ldflags -X로 빌드 시 버전 주입, 그리고 conventional commits로 버전을 자동 결정하는 semantic-release(feat=minor, breaking=major).
실습: .goreleaser.yaml의 goos/goarch 목록과 ldflags를 보고, "왜 CGO_ENABLED=0인가"(정적 바이너리·크로스컴파일 쉬움)를 한 줄로 정리. release.yml의 채널(dev=beta, main=stable) 분기도 훑기.
배울 것: 탐지·정리에서 끝내지 않고 재발 방지까지 가는 발상. guardrails는 에이전트별 지침 파일·작은 프라이버시 스킬·훅 스크립트(비밀을 출력할 법한 명령을 자제시키는)를 설치한다. 자산을 //go:embed로 바이너리에 내장해 별도 파일 없이 배포하는 기법도 배운다.
실습: guardrails 명령을 --dry-run으로 돌려 "어디에 무엇을 깔려는지"만 확인. resolveAgents가 설치된 에이전트만 자동 감지하는 로직을 따라 읽기.
"순수 소프트웨어 — 설치 바이너리는 의존성 0, 빌드만 Go가 필요하다."
maskara는 단일 정적 바이너리라 설치해서 쓰는 데는 아무 런타임도 필요 없다. 소스에서 빌드하거나 개발하려는 경우에만 Go가 필요하다.
| 구분 | 요구사항 |
|---|---|
| 설치(바이너리) | 의존성 없음. GitHub Releases에서 OS·아키텍처에 맞는 바이너리를 받아 PATH에 두면 끝. CGO_ENABLED=0 정적 빌드라 추가 라이브러리 불필요 |
| 빌드/개발 | Go 1.25 이상. go install github.com/mrgoonie/maskara/cmd/maskara@latest 또는 클론 후 go build ./cmd/maskara |
| 지원 OS | Linux · macOS · Windows (각 amd64·arm64). CI가 세 OS 모두에서 테스트 |
| 스캔 대상 | 로컬 에이전트 로그 디렉토리(아래 표). 읽기·(가림 시) 쓰기 권한 필요. 네트워크 불필요 |
maskara는 17종 에이전트의 기본 로그 위치를 카탈로그로 알고 있다. auto는 실제로 존재하는 디렉토리만 골라 스캔하고, --root로 임의 경로를 지정할 수도 있다.
| 에이전트 | 기본 스캔 위치 |
|---|---|
| Claude Code | ~/.claude/projects |
| Codex | ~/.codex/sessions |
| Cursor | ~/.cursor + OS별 Cursor 설정/데이터 디렉토리 |
| Gemini CLI | ~/.gemini + OS별 설정/데이터 디렉토리 |
| GitHub Copilot | ~/.github-copilot + OS별 설정/데이터 디렉토리 |
| OpenCode 외 다수 | 홈 dotdir + OS별 config/data 디렉토리 (총 17종: Antigravity·Kimi·Droid·Kilo·Kiro·Pi·Qoder·Qwen·Trae·Hermes·OpenClaw 등) |
# 설치 — Go만 있으면 한 줄
go install github.com/mrgoonie/maskara/cmd/maskara@latest
# 기본 워크플로: 스캔 + (백업 후) 가림 + 리포트
maskara
# 안전하게 들여다보기만 (가림 안 함)
maskara scan # 전체 자동 감지
maskara scan -a codex # Codex 로그만
# 리포트 파일로 — JSON 출력
maskara report --json -o ./maskara-report.json
# 예방책(가드레일) — 무엇을 깔지 미리보기만
maskara guardrails --dry-run
핵심은 인자 없는 maskara가 "가림까지" 하는 강한 명령이라는 점 — 처음엔 maskara scan으로 읽기만 해보고, 결과를 확인한 뒤 가림을 결정하는 것이 안전하다. 모든 동작은 네트워크 없이 로컬에서만 일어난다.
"읽기만 하면 안 남는다 — 난이도별로 손을 움직여 보자. (가림은 꼭 백업/사본에서!)"
maskara scan 한 번 돌려 리포트 읽기설치 후 maskara scan만 실행해(가림 없음) 어떤 파일에서 무엇이 잡히는지 본다. 진짜 키가 없더라도, 테스트용 폴더에 API_KEY=sk-test-1234...wxyz 같은 더미 한 줄을 적고 --root로 그 폴더를 지정하면 탐지·마스킹·지문이 어떻게 출력되는지 안전하게 체감한다.
--json / --output 으로 리포트 형식 바꿔 보기같은 스캔을 maskara report --json -o ./out.json으로 돌려 마크다운과 JSON 리포트를 비교한다. JSON에는 줄·열·심각도·지문이 구조화돼 들어가 "다른 도구가 이 결과를 받아 처리하기 좋은" 형태임을 확인. 기계가 읽는 출력과 사람이 읽는 출력의 차이를 느낀다.
internal/detect/detect.go의 규칙 중 하나(예: slack-token)를 골라 정규식을 한 조각씩 해석한다. 그다음 공개 토큰 양식(예: SendGrid SG. 키, Telegram 봇 토큰)을 찾아보고 새 Rule 한 줄을 직접 적어 본다. 심각도를 어디에 둘지도 생각해 보기.
guardrails --dry-run 으로 예방책 들여다보기maskara guardrails --dry-run을 돌려 "어떤 에이전트에, 어떤 파일(지침·스킬·훅)을, 어디에 설치하려는지" 계획만 출력해 본다. 실제로 깔지 않으니 안전하다. 출력 경로를 보고 internal/guardrails/assets/의 템플릿이 무엇인지 소스와 대조하며, "재발 방지를 코드로 설치한다"는 발상을 이해한다.
cli.go의 분기 구조를 따라가, 새 읽기 전용 서브커맨드(예: maskara rules = 현재 탐지 규칙 ID·심각도 목록 출력)를 설계해 본다. detect.DefaultRules()를 호출해 표로 찍는 정도면 충분하다. 테스트(*_test.go 패턴)와 CONTRIBUTING.md를 읽고 conventional commit 형식까지 맞춰 첫 PR 흐름을 경험.
"Go 기초에서 '나만의 시크릿 스캐너'까지 — 5주 코스 예시."
아래는 "Go를 조금 아는 사람이 maskara 코드를 읽고 비슷한 보안 CLI를 만들 수 있는 수준"까지의 한 가지 길이다. 작은 레포라 속도를 붙이기 좋다.
| 주차 | 주제 | 무엇을 / 왜 + 학습 자료 |
|---|---|---|
| 1주 | Go + CLI 기초 | flag 패키지, os.Args, 종료 코드. Tour of Go + maskara cli.go를 교본으로 서브커맨드 패턴 익히기 |
| 2주 | 정규식 마스터 | 캡처 그룹·경계(\b)·게으른 매칭. regex101.com에서 detect.go의 규칙들을 직접 돌려 보기 |
| 3주 | 파일시스템 & 해시 | filepath.WalkDir, 바이너리 판별, crypto/sha256. "백업 후 수정" 같은 방어적 IO 패턴 연습 |
| 4주 | 시크릿 탐지 도메인 | 각 제공사 토큰 양식(OpenAI·GitHub·AWS 문서), 오탐/미탐 트레이드오프. gitleaks 규칙셋과 비교 |
| 5주 | 릴리스 자동화 | GoReleaser로 크로스컴파일, GitHub Actions 매트릭스, conventional commits → semantic 버전. maskara CI 따라 만들기 |
maskara 코드베이스는 잘 정리된 1인 공방 같다. 거대한 공장(상용 도구)을 통째로 이해하려다 지치는 대신, "작업대(패키지) 하나씩"—탐지대(detect) → 가림대(redact) → 포장대(goreleaser)—을 차례로 들여다보면, 보안 CLI 한 채가 어떻게 굴러가는지 전체 그림이 손에 잡힌다. 작은 레포의 가장 큰 장점이다.
"이 문서와 maskara 코드에서 거듭 나오는 용어들 — 한 곳에 모아 풀었다."
[MASKARA_REDACTED:규칙ID]로 바꿔 파일에서 지운다(원본은 .maskara.bak 백업).guardrails는 에이전트에 지침·스킬·훅을 설치한다. 훅은 "특정 시점에 자동 실행되는 작은 스크립트" — 비밀을 출력할 법한 명령을 미리 자제시켜 재발을 막는다.sk-로 시작해 영숫자 20자 이상 같은 인상착의를 적어 두면, 텍스트에서 그 모양을 전부 찾아낸다. maskara 탐지의 토대.eyJ...로 시작하고 점(.) 두 개로 셋(헤더·페이로드·서명)이 나뉘는, 널리 쓰이는 인증 토큰 형식. 이 모양 자체가 정규식으로 잘 잡혀서 maskara의 탐지 규칙 중 하나다.API_KEY=..., SECRET: ...처럼 비밀스러운 변수명 = 값 꼴. 키 양식이 제각각이어도 이 "이름의 패턴"으로 잡는다(심각도 medium). 등호 뒤 값만 비밀이라 캡처 그룹으로 값만 추출한다.feat:·fix: 같은 접두사로 커밋을 분류하는 규약으로, maskara는 이로부터 버전(major/minor/patch)을 자동 결정한다.공식 저장소와 비슷한 결의 도구들(README References).
GitHub 저장소 · github.com/mrgoonie/maskara — 본체. internal/detect(규칙)와 internal/cli(조립부)부터 읽으면 좋다.
ggshield (GitGuardian) · github.com/GitGuardian/ggshield — 성숙한 시크릿 스캐너. git 저장소·CI 대상, 클라우드 검증 결합형. maskara와 대상·철학을 비교해 보기 좋다.
scan-for-secrets (simonw) · github.com/simonw/scan-for-secrets — 비슷한 결의 경량 스캐너. README의 References에 인용됨.
agent-sweep · github.com/Ishannaik/agent-sweep — 에이전트 로그/흔적 정리 계열 도구. README References에 함께 소개.
Agent Support Reference · 저장소 docs/agent-support-reference.md — 지원 에이전트 정규명·별칭·경로 휴리스틱·가드레일 설치 동작 정리.