Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
gh-safe-repo — 안전한 기본 설정 — 브랜치 보호, Dependabot, 비밀 스캐닝, 사전 보안 스캐닝 — 이 자동으로 적용된 GitHub 저장소를 생성하는 Python CLI입니다. | Kitploit
도구/GitHubGitHub/ariesq/gh-safe-repo
General Purpose UtilitiesVulnerability ScannersScripting & AutomationConfiguration AuditingCloud SecurityDevSecOpsSecret Detection
GitHubariesq/gh-safe-repo

gh-safe-repo

안전한 기본 설정 — 브랜치 보호, Dependabot, 비밀 스캐닝, 사전 보안 스캐닝 — 이 자동으로 적용된 GitHub 저장소를 생성하는 Python CLI입니다.

저장소 보기
38318시간 59분 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

gh-safe-repo

안전한 기본값이 자동으로 적용된 GitHub 리포지토리를 생성합니다. 생성 후 5분 동안의 설정 체크리스트를 단일 명령어로 대체합니다.``` gh-safe-repo create <owner/repo>

root@kitploit:~
브랜치 보호, 불변 태그, Dependabot, 제한된 Actions 권한, 푸시 보호가 포함된 시크릿 스캐닝, 위키 및 프로젝트 비활성화 — 첫 줄의 코드를 작성하기 전에 모두 구성됩니다.

gh-safe-repo는 활발히 개발 중입니다. 보안 기본값으로 새 리포지토리를 만드는 사용 사례에는 잘 작동합니다. 사용자 기대에 가장 잘 맞도록 CLI 옵션을 다듬는 중입니다. 릴리스를 하고 CI/CD를 확정할 때까지 호환되지 않는 변경이 있을 수 있습니다. ✌️

---

## 목차

- [이유](#why)
- [변경 사항](#what-it-changes)
- [요구 사항](#requirements)
- [설치](#installation)
- [빠른 시작](#quick-start)
- [CLI 참조](#cli-reference)
- [드라이 런 / 계획 출력](#dry-run--plan-output)
- [수정 모드 (기존 리포지토리 감사)](#fix-mode-audit-existing-repos)
- [리포지토리 미러링 (`--from`)](#mirroring-repos---from)
- [로컬 디렉토리에서 리포지토리 생성 (`--local`)](#creating-a-repo-from-a-local-directory---local)
- [사전 실행 보안 스캐너](#pre-flight-security-scanner)
  - [독립 실행형 스캔](#standalone-scan)
  - [오탐지 억제](#suppressing-false-positives)
- [구성](#configuration)
- [GitHub 요금제 제한 사항](#github-plan-limitations)
- [작동 방식](#how-it-works)
- [개발](#development)

---

## 이유

GitHub의 기본 리포지토리 설정은 보안이 아닌 검색 가능성과 유연성에 최적화되어 있습니다. 모든 새 리포지토리에는 다음이 포함됩니다:

- 위키 및 프로젝트 활성화 (사용하지 않더라도 공격 표면)
- 병합 커밋 허용 (지저분한 기록이지만 주요 문제는 아님)
- 브랜치 보호 없음 (쓰기 권한이 있는 사람은 누구나 `main`에 직접 푸시 가능)
- Dependabot 알림 없음
- 리포지토리에 대한 쓰기 권한이 있는 GitHub Actions
- 풀 리퀘스트 승인을 허용하는 Actions

이 모든 것을 수동으로 수정하는 데는 리포지토리당 몇 분이 소요되며 쉽게 잊힙니다. `gh-safe-repo`는 한 번에 독단적이지만 실용적인 기본값 세트를 적용하며, 변경되기 전에 정확히 무엇이 변경될지 알 수 있도록 계획 미리보기를 제공합니다.

---

## 변경 사항

### 리포지토리 설정

| 설정 | GitHub 기본값 | 안전 기본값 | 비고 |
|---|---|---|---|
| 공개 여부 | 공개 | **비공개** | 재정의하려면 `--public` 전달 |
| 위키 | 활성화 | **비활성화** | |
| 프로젝트 | 활성화 | **비활성화** | |
| 이슈 | 활성화 | 활성화 | |
| 병합 시 브랜치 삭제 | 꺼짐 | 꺼짐 | 자동 정리를 위해 구성에서 `true`로 설정 |
| 병합 커밋 허용 | 켜짐 | 켜짐 | 스쿼시 전용을 위해 구성에서 `false`로 설정 |
| 스쿼시 병합 허용 | 켜짐 | 켜짐 | |
| 리베이스 병합 허용 | 켜짐 | 켜짐 | |

### GitHub Actions

| 설정 | GitHub 기본값 | 안전 기본값 |
|---|---|---|
| 허용된 Actions | 모두 | **선택됨** (GitHub 소유 + 확인된 작성자, 사용자 지정 가능) |
| 기본 워크플로 권한 | 읽기/쓰기 | **읽기 전용** |
| Actions이 PR을 승인할 수 있음 | 예 | **아니요** |
| SHA 고정 요구 | 아니요 | **예** (워크플로는 가변 태그가 아닌 커밋 SHA에 Actions을 고정해야 함) |
| 포크 PR 승인 정책 | GitHub에 처음 기여한 사용자 | **모든 외부 기여자** — 포크 PR 워크플로가 CI를 실행하기 전에 승인 필요. 옵션: 새로운 GitHub 계정만 (GitHub 기본값), 리포지토리에 처음 기여한 사용자, 또는 모든 포크 PR (가장 안전) |

### 브랜치 보호 (공개 리포지토리 또는 유료 요금제의 모든 리포지토리)

| 규칙 | 값 |
|---|---|
| 병합 전 풀 리퀘스트 필요 | 예 |
| 요구되는 승인 리뷰 | 1 |
| 푸시 시 오래된 리뷰 무시 | 예 |
| 대화 해결 필요 | 예 |
| 강제 푸시 허용 | 아니요 |
| 브랜치 삭제 허용 | 아니요 |
| 관리자에게 적용 | 아니요 (소유자가 도구로 푸시할 수 있도록 허용) |

브랜치 보호는 기본적으로 **Rulesets API**를 통해 적용됩니다 (`use_rulesets = true`):
단일 `gh-safe-repo defaults` 규칙 세트가 구성된 모든 브랜치를 포함하며
"관리자가 우회 가능"을 기존의 `enforce_admins` 플래그 대신 우회 작업자를 통해 표현합니다.
`use_rulesets = false`로 설정하면 기존의 브랜치별 클래식 경로가 사용됩니다 (한 릴리스 주기 동안 유지).

**클래식 보호에서 기존 리포지토리 마이그레이션:** `fix`가 리포지토리에서 클래식 브랜치 보호를 발견하면
`--migrate-branch-protection`을 전달하지 않는 한 이를 규칙 세트로 변환하지 않습니다.
클래식 전용 규칙은 이 도구가 구축하는 규칙 세트에 해당하는 기능이 없으며 그렇지 않으면 자동으로 삭제됩니다 — 알려진 차이점:

- `required_status_checks` — 필수 CI 검사는 규칙 세트 본문에 모델링되지 않습니다.
- `restrictions` (사용자/팀에 의한 푸시 제한) — 규칙 세트는 우회 작업자를 통해 이를 다르게 모델링하므로 1:1 매핑이 아닙니다.
- 브랜치별 차이 — 단일 공유 조건 규칙 세트는 `master`와 `main`에 대해 다른 규칙을 표현할 수 없습니다.

플래그와 함께 `fix`는 규칙 세트를 생성/업데이트한 다음 각 브랜치의 클래식 보호를 삭제하여 두 레이어가 중첩되지 않도록 합니다.

### 태그 보호 (공개 리포지토리 또는 유료 요금제의 모든 리포지토리)

태그 보호는 모든 태그 (기본적으로 `*`, `protected_tags`를 통해 구성 가능)를 대상으로 하는 GitHub Ruleset을 생성합니다. 다음 규칙이 적용됩니다:

| 규칙 집합 규칙 | 적용됨? | 비고 |
|---|---|---|
| 생성 제한 | 아니요 | |
| **업데이트 제한** | **예** | 태그 재작성/강제 푸시 방지 |
| **삭제 제한** | **예** | 태그의 `git push --delete` 방지 |
| 선형 기록 필요 | 아니요 | |
| 배포 성공 필요 | 아니요 | |
| 서명된 커밋 필요 | 아니요 | |
| 상태 검사 통과 필요 | 아니요 | |
| 강제 푸시 차단 | 아니요 | |

리포지토리 관리자는 우회 목록에 있습니다 (브랜치 보호 `enforce_admins = false` 기본값과 일관됨). 공개 리포지토리 또는 유료 GitHub 요금제에서만 작동합니다 (브랜치 보호와 동일한 제한). 무료 요금제 비공개 리포지토리의 경우 계획 출력에서 이 단계가 건너뜁니다.

### 보안

| 기능 | 동작 |
|---|---|
| Dependabot 알림 | 활성화 (공개 리포지토리 / 유료 요금제) |
| Dependabot 보안 업데이트 | 활성화 (취약한 종속성에 대해 PR 자동 생성) |
| 시크릿 스캐닝 | 공개 리포지토리에서는 자동, 비공개 유료 요금제에서는 활성화 |
| 푸시 보호 | 활성화 (지원되는 시크릿을 포함하는 커밋 차단) |
| 비공개 취약점 보고 | 활성화 (보안 연구원이 비공개로 보고 가능) |
| 종속성 그래프 | 공개 리포지토리에서는 자동, 비공개의 경우 REST API 없음 (UI만) |

---

## 요구 사항

- Python 3.8+
- [`gh` CLI](https://cli.github.com/) 설치 및 인증 (`gh auth login`) **또는** 환경에 `GITHUB_TOKEN` 설정
- `--local` / `--from` (코드를 푸시하거나 복제)의 경우: 일반 git 자격 증명이 설정되어 있어야 합니다 — SSH 키가 `ssh-agent`에 로드되거나 (`gh config get git_protocol`이 `ssh`인 경우) HTTPS 자격 증명 도우미 (`gh auth setup-git`이 자동으로 구성). git 푸시에는 OAuth 토큰이 **사용되지 않으므로** 워크플로 파일 (`.github/workflows/*`)은 OAuth `workflow` 범위 없이 푸시됩니다.
- 소스에서 설치하려면 [`uv`](https://docs.astral.sh/uv/) (권장)
- `truffleHog` v3 (선택 사항 — 사전 실행 스캐너에서 사용, PATH에서 자동 감지되거나 podman/docker를 통해 실행, 둘 다 사용할 수 없으면 정규식으로 대체)

---

## 설치

### uv를 사용한 소스 설치 (권장)```bash
git clone https://github.com/your-username/gh-safe-repo
cd gh-safe-repo
uv tool install .

이렇게 하면 gh-safe-repo가 uv의 도구 환경에 설치되고 PATH에 추가됩니다.

설치 없이 바로 실행```bash

git clone https://github.com/your-username/gh-safe-repo cd gh-safe-repo uv sync # creates .venv ./gh-safe-repo create <owner/repo>

root@kitploit:~
### 확인```bash
gh-safe-repo --help

빠른 시작```bash

Create a private repo with all safe defaults

gh-safe-repo create <owner/repo>

Preview what would happen — no changes made

gh-safe-repo create <owner/repo> --dry-run

Create a public repo (branch protection + security scanning applied)

gh-safe-repo create <owner/repo> --public

Mirror an existing repo into a new private repo (with pre-flight scan)

gh-safe-repo create <owner/repo> --from <owner/source>

Mirror a private repo to a new public repo (with pre-flight scan)

gh-safe-repo create <owner/pub> --from <owner/priv> --public

Create a repo from a local directory (with pre-flight scan)

gh-safe-repo create <owner/repo> --local ~/projects/myapp

Same, but make it public (branch protection applied before push)

gh-safe-repo create <owner/repo> --local ~/projects/myapp --public

Audit an existing repo and apply any missing safe defaults

gh-safe-repo fix <owner/repo>

Audit without making changes

gh-safe-repo fix <owner/repo> --dry-run

Apply fixes without confirmation prompt (scripting/batch use)

gh-safe-repo fix <owner/repo> --yes

Scan a local repo for secrets before pushing anywhere

gh-safe-repo scan . gh-safe-repo scan ~/projects/myapp

root@kitploit:~
## CLI 참조```
gh-safe-repo create <owner/repo> [OPTIONS]
gh-safe-repo fix <owner/repo> [OPTIONS]
gh-safe-repo scan <path> [OPTIONS]

GitHub과 상호작용하는 모든 명령어는 owner/repo 형식(예: myuser/my-repo)을 필요로 합니다. create의 경우, 소유자는 인증된 GitHub 계정을 기준으로 검증되어 다중 계정 시스템에서의 실수를 방지합니다. fix의 경우에는 대상 리포지토리에 대한 관리자 권한이 필요하므로, 조직 또는 다른 계정이 소유한 리포지토리 중 관리자 접근 권한이 있는 경우에도 수정할 수 있습니다.

create — 새로운 리포지토리 생성

--local/--from 없이 create만 실행하면 리포지토리가 초기화되어 기본 브랜치가 브랜치 보호를 위해 존재하게 되며, 그 후 자동 생성된 README.md가 제거되어 새 리포지토리가 깨끗하게 시작됩니다. README를 유지하려면 설정에서 auto_init = true로 설정하십시오. --local/--from을 사용하면 자체 히스토리를 푸시하며 README를 생성하지 않습니다.

fix — 기존 리포지토리 감사 및 수정

scan — 로컬 비밀 스캐닝

옵션설명
--config [PATH]설정 파일 경로; --config만 지정하면 기본 내장 설정만 사용합니다.
--debug스캐너 세부 정보를 표시합니다.

종료 코드는 심각한 결과가 없으면 0, 심각한 결과가 발견되면 1입니다.


Dry Run / 계획 출력

--dry-run은 gh-safe-repo가 수행할 작업을 변경 사항이나 API 호출 없이 정확히 보여줍니다. 실제 실행 전에 사용하십시오. --json과 함께 사용하면 기계가 읽을 수 있는 계획 출력을 얻을 수 있습니다:```bash gh-safe-repo create <owner/repo> --dry-run --json gh-safe-repo fix <owner/repo> --dry-run --json

root@kitploit:~
When `--json`이 활성화되면, 계획은 stdout에 JSON 객체로 기록되고, 다른 모든 메시지(진행 상황, 경고, "Dry run" 푸터)는 stderr로 전송되므로, 파이핑이나 스크립팅을 위한 출력이 깔끔해집니다.```
$ gh-safe-repo create <owner/repo> --dry-run

  Plan for my-project (private)

  Category            Action  Setting                          Value
  ──────────────────────────────────────────────────────────────────
  Repository          ADD     repository                       my-project (private)
  Repository          ADD     has_wiki                         false
  Repository          ADD     has_projects                     false
  Actions             ADD     default_workflow_permissions     read
  Actions             ADD     can_approve_pull_request_reviews false
  Branch Protection   SKIP    branch_protection                Not available for private repos on free plan
  Security            SKIP    dependabot_alerts                Not available for private repos on free plan
  1 setting skipped (GitHub plan limitation).
  Dry run — no changes made.

동작 색상:

동작의미
ADD (녹색)

JSON 출력 (--json):```json { "changes": [ { "type": "add", "category": "repository", "key": "has_wiki", "old": null, "new": false, "reason": null }, { "type": "skip", "category": "branch_protection", "key": "branch_protection", "old": null, "new": null, "reason": "Not available for private repos on free plan" } ], "summary": { "add": 5, "skip": 2 } }

root@kitploit:~
`summary`는 플랜에 존재하는 유형만 포함합니다. 소비자는 네 가지 키가 모두 존재한다고 가정하기보다 `.get("delete", 0)` 등을 사용해야 합니다.

---

## 수정 모드 (기존 리포지토리 감사)

`fix`는 기존 리포지토리의 현재 설정을 안전 기본값과 비교하고 필요한 수정 사항을 적용합니다. 비밀 검사는 수행하지 않습니다. `fix`는 순수하게 리포지토리 설정에 관한 것입니다.```bash
# See what's out of compliance
gh-safe-repo fix <owner/repo> --dry-run

# Apply missing safe defaults
gh-safe-repo fix <owner/repo>

# Apply without confirmation prompt (scripting/batch use)
gh-safe-repo fix <owner/repo> --yes

수정 모드:

  1. GitHub API를 통해 모든 설정의 현재 값을 가져옵니다.
  2. 원하는 안전 기본값과 비교합니다.
  3. 변경된 설정에는 UPDATE, 이미 원하는 값인 설정에는 SKIP을 표시하는 계획 테이블을 보여줍니다 (무효 작업 감지 — 아무것도 변경하지 않는 API 호출을 수행하지 않습니다).
  4. 적용 전 확인 메시지를 표시합니다 (--yes로 건너뛰기).

실제 변경 사항만 적용됩니다 — 이미 원하는 값인 설정은 SKIP으로 표시되며 API 호출이 생성되지 않습니다.


Repos 미러링 (--from)

--from은 기존 레포지토리를 안전 기본값이 적용된 새 레포지토리로 미러링합니다. 개인 및 공개 대상 모두에서 작동합니다:```bash

Mirror into a new private repo (default)

gh-safe-repo create <owner/repo> --from <owner/source>

Mirror a private repo to a new public repo (riskiest operation — scanned thoroughly)

gh-safe-repo create <owner/pub> --from <owner/priv> --public

root@kitploit:~
**순서대로 발생하는 작업:**

1. `github.com`에 대한 git 자격 증명이 먼저 확인됩니다(SSH 프로브: `gh config get git_protocol`이 `ssh`인 경우; HTTPS는 신뢰됨). 따라서 누락된 키가 있으면 저장소가 생성되기 전에 빠르게 실패합니다.
2. 소스 저장소가 로컬에 클론됩니다(전체 클론, `--depth` 없음, 그래서 truffleHog가 전체 커밋 기록을 탐색할 수 있습니다).
3. [사전 보안 스캐너](#pre-flight-security-scanner)가 로컬 클론에서 실행됩니다.
4. 결과를 검토하고 확인(또는 중단)합니다.
5. 새 저장소가 생성됩니다(기본적으로 비공개, 또는 `--public`으로 공개).
6. Actions 권한 및 보안 설정이 적용됩니다(Dependabot, 비밀 스캐닝, 푸시 보호).
7. 전체 기록이 미러링됩니다: `git clone --mirror` + `git push --mirror`
8. 브랜치 및 태그 보호가 적용됩니다(코드 푸시 후이므로 대상 브랜치가 존재합니다).

스캔에서 문제가 발견되어 중단하면 코드가 GitHub에 복사되지 않습니다.

> **참고:** `--from`은 소스와 대상 모두에 대해 `owner/repo` 형식을 사용합니다.

---

## 로컬 디렉터리에서 저장소 생성 (`--local`)

`--local PATH`는 `--from`에 해당하는 로컬-투-깃허브 옵션입니다. 새 GitHub 저장소를 생성하고 로컬 git 저장소에서 코드를 푸시합니다. `PATH`는 초기화된 git 저장소(`git init` 또는 클론)여야 합니다.```bash
gh-safe-repo create <owner/repo> --local ~/projects/myapp
gh-safe-repo create <owner/repo> --local ~/projects/myapp --public

순서대로 수행되는 작업:

  1. github.com에 대한 Git 자격 증명이 사전에 확인됩니다(gh config get git_protocol이 ssh일 때 SSH 프로브; HTTPS는 신뢰됨). 따라서 키가 없으면 저장소가 생성되기 전에 빠르게 실패합니다.
  2. 로컬 디렉터리에서 직접 사전 보안 스캐너가 실행됩니다(클론 필요 없음).
  3. 결과를 검토하고 확인(또는 중단)합니다.
  4. 새 저장소가 생성되고, 작업 권한 및 보안 설정이 적용됩니다.
  5. 전체 이력이 push --all --tags로 푸시됩니다(모든 브랜치 및 태그).
  6. 브랜치 및 태그 보호가 적용됩니다(코드 푸시 후이므로 대상 브랜치가 존재함).
  7. origin이 원본 로컬 저장소에 새 GitHub URL을 가리키도록 추가되고, 현재 브랜치의 업스트림 추적이 구성되어 git push 및 git pull이 추가 설정 없이 즉시 작동합니다.

--local과 --from 모두 비공개 및 공개 저장소에서 작동합니다. 서로 배타적입니다.

로컬 기본 브랜치(git -C PATH symbolic-ref HEAD를 통해)는 브랜치 보호 규칙을 대상으로 하는 데 사용되므로, 보호가 main이 아니더라도 올바른 브랜치에 적용됩니다.

팁: 아무것도 생성하지 않고 결과를 검사하려면 먼저 gh-safe-repo scan PATH를 실행하세요.

사전 보안 스캐너

스캐너는 로컬에서 실행되며 코드를 GitHub로 보내지 않습니다. 푸시 전에 독립 실행형으로 사용하거나, --from 및 --local 워크플로의 일부로 자동으로 실행됩니다.

독립 실행형 스캔```bash

Scan the current directory

gh-safe-repo scan .

Scan an explicit path

gh-safe-repo scan ~/projects/myapp

root@kitploit:~
종료 코드는 `0`으로 심각한 문제가 없음을 나타내며, `1`은 심각한 문제가 발견되었음을 의미합니다 — 따라서 다른 명령어와 깔끔하게 연동됩니다:```bash
gh-safe-repo scan . && git push

전체 [pre_flight_scan] 설정이 적용됩니다: banned_strings, max_file_size_mb, trufflehog_mode 등.

감지 항목

스캐너 엔진

gh-safe-repo는 3단계 검색 체인을 사용하여 사용 가능한 최고의 스캐너를 자동으로 선택합니다.

  1. PATH 상의 truffleHog v3 — trufflehog --version을 실행하여 v3인지 확인하고 사용합니다. v2 설치 또는 인식되지 않는 버전은 경고를 출력하고 2단계로 넘어갑니다.
  2. podman 또는 docker — 네이티브 truffleHog가 없으면 스캐너는 podman run 또는 docker run을 사용하여 컨테이너(ghcr.io/trufflesecurity/trufflehog:latest)에서 truffleHog를 실행하며, 스캔 경로를 동일한 절대 경로에 읽기 전용으로 마운트하여 JSON 출력 경로가 네이티브 실행과 동일하도록 합니다.
  3. 정규식 대체 — 네이티브 설치도 컨테이너 런타임도 사용할 수 없는 경우 경고가 출력되고 정규식 스캐너가 대신 실행됩니다. 또한 이메일 및 TODO에 대해 truffleHog 외에도 항상 실행되며, truffleHog가 의도적으로 건너뛰는 단독 키-ID 패턴을 잡아냅니다 (truffleHog는 자격 증명 쌍의 두 부분, 예: AWS Key ID 및 Secret Access Key를 모두 찾은 후에만 발견을 표시합니다).

선택된 스캐너는 'Running pre-flight security scan...' 헤더와 계획 테이블의 SCAN 항목에 표시됩니다. 예:``` Running pre-flight security scan... (truffleHog v3.93.4) Running pre-flight security scan... (truffleHog via podman) Running pre-flight security scan... (regex only — see warning above)

root@kitploit:~
컨테이너 경로에서 존중되는 환경 변수: `CONTAINER_RUNTIME` (런타임 선택을 재정의, 예: `CONTAINER_RUNTIME=docker`) 및 `TRUFFLEHOG_IMAGE` (특정 이미지 태그 고정).

### podman 또는 Docker를 통한 truffleHog 실행 (로컬 설치 불필요)

수동 설정이 필요하지 않습니다. `gh-safe-repo`는 podman 또는 docker를 자동으로 감지하여(위의 2단계) 올바른 볼륨 마운트로 컨테이너에서 truffleHog를 실행합니다. `CONTAINER_RUNTIME` 및 `TRUFFLEHOG_IMAGE` 환경 변수가 존중됩니다.

쉘 래퍼(`tools/trufflehog`)와 고정된 로컬 이미지를 빌드하기 위한 `Containerfile`이 [`tools/`](https://github.com/ariesq/gh-safe-repo/blob/HEAD/tools/README.md)에 제공됩니다. 이는 시스템 전체에서 사용 가능한 컨테이너 기반 truffleHog를 원하거나, 에어갭 이미지가 필요한 사용자를 위한 것입니다.

### 대화형 검토```
Pre-flight scan: my-private-project

  CRITICAL  my_private_project/config.py:12  AWS Access Key ID
            [redacted]

  WARNING   my_private_project/setup.py:3    Email address
            author_email="[email protected]"

  1 critical finding, 1 warning.

  Critical findings detected. Continue anyway? [y/N]:
  • 심각한 발견: 기본값은 중단(N)입니다. 계속하려면 y를 명시적으로 입력해야 합니다.
  • 경고만 해당: 기본값은 계속(Y)입니다. Enter를 눌러 진행하거나 n을 입력하여 중단합니다.
  • 발견 사항 없음: 스캔이 자동으로 완료되고 워크플로가 계속됩니다.

비밀 정보는 출력에서 가려집니다. 이메일 주소와 TODO는 일치하는 줄을 표시합니다.

스캔 범위

빌드 아티팩트 디렉토리(node_modules, __pycache__, .venv, venv, dist, build)는 스캔 속도를 유지하기 위해 기본적으로 건너뜁니다. Git 저장소에서는 이 건너뛰기가 조건부입니다. 디렉토리를 제외하기 전에 스캐너는 git ls-files -- <dir>을 실행하여 내부의 파일이 추적되는지 확인합니다. 추적되는 경우 디렉토리는 정상적으로 스캔됩니다.

즉, 커밋된 node_modules 또는 dist 트리(드물지만 발생할 수 있음)가 조용히 누락되지 않습니다. 커밋되지 않은 디렉토리(일반적인 경우)는 이전과 같이 계속 건너뜁니다.

복제된 소스 저장소에서 SKIP_DIRS 하위 디렉토리가 발견되면 여전히 경고가 출력됩니다. 이는 예상보다 많은 내용이 커밋되었음을 나타낼 수 있기 때문입니다.

오탐지 억제

두 가지 구성 키를 사용하면 전체 검사 범주를 비활성화하지 않고 알려진 안전한 발견을 억제할 수 있습니다.

scan_exclude_paths — 파일 또는 디렉토리를 완전히 건너뜁니다. 값은 상대 파일 경로와 일치하는 줄바꿈/쉼표로 구분된 정규식 패턴입니다. 일치하는 파일은 모든 검사(비밀, 이메일, TODO, 큰 파일, AI 컨텍스트 파일 탐지)에서 제외됩니다. 동일한 패턴은 --exclude-paths를 통해 truffleHog에도 전달되므로 어떤 스캐너 엔진이 활성화되어 있든 적용 범위가 일관됩니다.```ini [pre_flight_scan]

Exclude the GitHub API spec (example tokens) and all test fixtures

scan_exclude_paths = docs/api.github.com.json tests/fixtures/

root@kitploit:~
**`exclude_emails`** — 특정 주소 또는 전체 도메인에 대한 이메일 검색 결과를 숨깁니다. 값은 줄바꿈/쉼표로 구분되며, 대소문자를 구분하지 않습니다. `@`로 시작하는 항목은 해당 도메인의 모든 이메일과 일치하며, 그 외의 경우 전체 주소와 정확히 일치해야 합니다. 작업 트리 및 git 기록 검색 결과 모두에 적용됩니다.```ini
[pre_flight_scan]
# Suppress bot addresses and placeholder domains
exclude_emails = [email protected], [email protected], @example.com

스캐너 구성```ini

[pre_flight_scan] scan_for_secrets = true scan_for_emails = true scan_for_todos = true max_file_size_mb = 100

Scan git history for email addresses (requires scan_for_emails = true)

scan_email_history = true

Scanner selection: auto | native | docker | off

auto — try native truffleHog, fall back to container (podman/docker), then regex (default)

native — native truffleHog only; no container fallback

docker — container only; skip native PATH check

off — regex scanner only, no truffleHog attempt

trufflehog_mode = auto

Flag AI context files (CLAUDE.md, AGENTS.md, .cursorrules, etc.) as critical findings.

Their git history may contain more sensitive content than the current version.

warn_ai_context_files = true

Literal strings to flag as critical findings (case-insensitive).

Comma-separated or one per line (continuation lines must be indented).

banned_strings = secret

password

credential

Exclude files/directories from all scan checks (regex patterns, comma/newline separated).

The same patterns are passed to truffleHog via --exclude-paths.

scan_exclude_paths = docs/api.github.com.json

tests/fixtures/

Suppress email findings for specific addresses or entire domains (case-insensitive).

Entries starting with @ match all emails at that domain; otherwise exact address match.

exclude_emails = [email protected], [email protected], @example.com

root@kitploit:~
When banned strings or AI context files are found the scanner prints a ready-to-run `git filter-repo` command to remove them from the source repo's history before re-running.

---

## 설정

`gh-safe-repo`는 다음 순서대로 설정을 찾습니다 (첫 번째 일치 항목 사용):

1. **`--config PATH`** — 명시적 재정의
2. **`./gh-safe-repo.ini`** — 현재 작업 디렉터리
3. **`$XDG_CONFIG_HOME/gh-safe-repo/gh-safe-repo.ini`** — `$XDG_CONFIG_HOME`이 설정되지 않은 경우 `~/.config`로 기본 설정

인수 없는 `--config`는 파일 조회를 완전히 건너뛰고 내장 기본값만 사용합니다.
모든 값은 안전한 기본값을 가지므로 시작하는 데 설정 파일이 필요하지 않습니다.

완전히 주석 처리된 예제 설정 파일이 `gh-safe-repo.ini.example`로 저장소에 포함되어 있습니다. 이를 복사하여 시작하세요:```bash
# User-level config (XDG)
mkdir -p "${XDG_CONFIG_HOME:-$HOME/.config}/gh-safe-repo"
cp gh-safe-repo.ini.example "${XDG_CONFIG_HOME:-$HOME/.config}/gh-safe-repo/gh-safe-repo.ini"

# Or project-level config (current directory)
cp gh-safe-repo.ini.example ./gh-safe-repo.ini

전체 구성 참조```ini

[repo]

Whether new repos are private by default

private = true

Disable features that create clutter if unused

has_wiki = false has_projects = false has_issues = true

Auto-delete head branches after merge (default: off, matching GitHub)

delete_branch_on_merge = false

Merge strategies (all enabled by default, matching GitHub)

Set allow_merge_commit = false for squash-only workflows

allow_squash_merge = true allow_merge_commit = true allow_rebase_merge = true

Whether a plain create leaves an initialized README in the new repo.

false (default): the repo still gets a default branch (needed for branch

protection), but the auto-generated README.md is removed afterward.

true: keep the initialized README.

(Ignored for --local/--from, which always push your own history instead.)

auto_init = false

[actions]

Which actions are allowed to run: all | local_only | selected

allowed_actions = selected

When allowed_actions = selected, control which external actions are permitted:

github_owned_allowed = true # actions maintained by GitHub (e.g. actions/checkout) verified_allowed = true # actions from Marketplace verified creators

patterns_allowed = myorg/* # comma-separated allowlist (wildcards OK)

Principle of least privilege: read-only by default

Options: read | write

default_workflow_permissions = read

Prevent Actions from self-approving pull requests

can_approve_pull_request_reviews = false

Require workflows to pin actions to a specific commit SHA instead of a mutable tag

sha_pinning_required = true

[branch_protection]

Applied to public repos on any plan, and private repos on paid plans.

Branch to protect

protected_branch = main

Require a pull request before merging

require_pull_request = true

Number of approvals required

required_approving_reviews = 1

Dismiss existing approvals when new commits are pushed

dismiss_stale_reviews = true

Require all review comments to be resolved before merging

require_conversation_resolution = true

Do not enforce rules on administrators

false = repo owner can still push directly (needed for --from mirror workflow)

enforce_admins = false

Block force-pushes

allow_force_pushes = false

Block branch deletion

allow_deletions = false

Use the Rulesets API (default) instead of the legacy classic branch-protection

path. A single ruleset covers all configured branches, supports bypass actors,

and is GitHub's forward direction (new rule types are Rulesets-only). Set false

to fall back to the classic per-branch API, which is kept for one release cycle.

use_rulesets = true

[tag_protection]

Immutable tags via Rulesets API.

Only works on public repos or paid GitHub plans (same restriction as branch protection).

Glob pattern(s) for tags to protect — comma-separated.

protected_tags = *

Prevent deletion of matching tags (git tag -d / git push --delete)

prevent_tag_deletion = true

Prevent rewriting matching tags (git tag -f / force-push)

prevent_tag_update = true

[security]

Enable Dependabot vulnerability alerts

enable_dependabot_alerts = true

Auto-open PRs to fix vulnerable dependencies

enable_dependabot_security_updates = true

Let security researchers report vulnerabilities privately

enable_private_vulnerability_reporting = true

Block commits that contain supported secrets

enable_secret_scanning_push_protection = true

Note: The following features have no REST API and must be configured via UI or dependabot.yml:

- Grouped security updates: use dependabot.yml groups with applies-to: security-updates

- Automatic dependency submission: enable via repository settings UI

- Dependency graph: automatic for public repos; enable via UI for private repos

[pre_flight_scan] scan_for_secrets = true scan_for_emails = true scan_for_todos = true

Flag files larger than this threshold

max_file_size_mb = 100

Scan git history for email addresses (requires scan_for_emails = true)

scan_email_history = true

Scanner selection: auto | native | docker | off

auto = try native truffleHog, fall back to container (podman/docker), then regex

native = native PATH only

docker = container only

off = regex only

trufflehog_mode = auto

Flag AI context files (CLAUDE.md, AGENTS.md, .cursorrules, etc.) as critical findings.

warn_ai_context_files = true

Literal strings to flag as critical findings (case-insensitive).

Comma-separated, or one per line with continuation indentation.

banned_strings = secret

password

credential

Exclude files/directories from all scan checks (regex patterns, comma/newline separated).

Passed to truffleHog via --exclude-paths as well as applied to the regex walk.

scan_exclude_paths = docs/api.github.com.json

tests/fixtures/

Suppress email findings for specific addresses or entire domains (case-insensitive).

Entries starting with @ match all emails at that domain; otherwise exact address match.

exclude_emails = [email protected], [email protected], @example.com

[git_transport]

How git push/clone authenticates when using --local or --from: auto | user_creds | token

auto — use your own git credentials (SSH key or credential helper) when a

path exists; fall back to pushing over HTTPS with the API token in

the URL only when there is no SSH setup and no credential helper

(e.g. CI with just GITHUB_TOKEN). (default)

user_creds — never use the API token for git. Pushes with your own credentials

only; this avoids needing the workflow token scope to push

.github/workflows files.

token — always push over HTTPS with the API token in the URL. For CI where

the token was granted the workflow scope intentionally.

mode = auto

root@kitploit:~
---

## GitHub 요금제 제한 사항

일부 기능은 저장소 공개 여부와 GitHub 요금제에 따라 사용 가능 여부가 결정됩니다.

| 기능 | Free + Public | Free + Private | Pro/Team + Private |
|---|:---:|:---:|:---:|
| 브랜치 보호 / Rulesets | 예 | 아니오 | 예 |
| 태그 보호 (Rulesets) | 예 | 아니오 | 예 |
| Dependabot 알림 | 예 | 아니오 | 예 |
| Dependabot 보안 업데이트 | 예 | 아니오 | 예 |
| 시크릿 스캐닝 | 자동 | 아니오 | 예 |
| 푸시 보호 | 예 | 아니오 | 예 |
| 비공개 취약점 보고 | 예 | 예 | 예 |
| 종속성 그래프 | 자동 | 아니오 | 예 |

`gh-safe-repo`는 런타임에 요금제 수준과 저장소 공개 여부를 감지합니다. 사용할 수 없는 기능은 계획 출력에 `SKIP`으로 표시되고 명확한 이유가 함께 제공됩니다. 도구는 절대 조용히 실패하지 않습니다.

---

## 작동 방식```
gh-safe-repo create <owner/repo>
      │
      ├─ Parse owner/repo, validate owner matches authenticated user (create only)
      ├─ Load config (./gh-safe-repo.ini or $XDG_CONFIG_HOME/gh-safe-repo/gh-safe-repo.ini)
      ├─ Apply CLI flag overrides (--public, etc.)
      ├─ Authenticate via gh CLI or GITHUB_TOKEN
      ├─ GET /user → owner login + plan level  (single cached call)
      │
      ├─ Build plan (each plugin compares desired vs. current state)
      │   ├─ RepositoryPlugin  → repo creation + basic settings
      │   ├─ ActionsPlugin     → allowed actions, workflow permissions, SHA pinning
      │   ├─ BranchProtectionPlugin → Rulesets API (default; classic if use_rulesets = false)
      │   ├─ SecurityPlugin    → Dependabot, secret scanning, push protection, private vuln reporting
      │   └─ TagProtectionPlugin → immutable tags via Rulesets API
      │
      ├─ Print plan table
      │
      └─ Apply (unless --dry-run)
          ├─ POST /user/repos
          ├─ PATCH /repos/{owner}/{repo}       (settings)
          ├─ PUT  /repos/{owner}/{repo}/actions/permissions/workflow
          ├─ POST/PATCH /repos/{owner}/{repo}/rulesets  (branch protection; default)
          │   or PUT /repos/{owner}/{repo}/branches/main/protection (if use_rulesets = false)
          ├─ PUT  /repos/{owner}/{repo}/vulnerability-alerts
          ├─ PUT  /repos/{owner}/{repo}/automated-security-fixes
          ├─ PUT  /repos/{owner}/{repo}/private-vulnerability-reporting
          ├─ PATCH /repos/{owner}/{repo}  (security_and_analysis: push protection)
          ├─ POST /repos/{owner}/{repo}/rulesets  (tag protection ruleset)
          ├─ git clone --mirror + git push --mirror (if --from)
          └─ git clone <local> + git push --all --tags (if --local, git repo)
              or git init + add -A + commit + push (if --local, plain dir)

플러그인 아키텍처

각 설정 카테고리는 자체 포함된 플러그인 클래스(gh_safe_repo/plugins/)입니다. 모든 플러그인은:

  1. GitHub API에서 현재 상태를 가져옵니다.
  2. 설정에서 원하는 상태와 비교합니다.
  3. Plan(변경 객체 목록: ADD / UPDATE / DELETE / SKIP)을 반환합니다.
  4. 실제 변경 사항만 적용합니다 — no-op에는 API 호출이 없습니다.

즉, 감사 모드와 생성 모드는 동일한 plan/apply 경로를 사용합니다. 유일한 차이점은 현재 상태를 기존 리포지토리에서 가져오는지 아니면 GitHub 기본값으로 가정하는지 여부입니다.

인증

API 호출은 다음 순서로 토큰을 확인합니다:

  1. GITHUB_TOKEN 환경 변수 — 활성 gh 세션을 전환하지 않고 특정 계정을 대상으로 지정할 수 있습니다(그리고 CI에서 필요한 유일한 자격 증명입니다).
  2. gh auth token — gh auth login에서 설정한 모든 것.
  3. 둘 다 사용할 수 없으면 오류 발생.

토큰은 하위 프로세스 환경에서 GH_TOKEN으로 하위 gh api 프로세스에 전달되며 절대 기록되지 않습니다.

Git 작업(--local / --from push 및 clone)은 기본적으로 API 토큰이 아닌 사용자 자신의 Git 자격 증명(SSH 키 또는 자격 증명 도우미)을 사용합니다. 둘 다 없는 환경(예: GITHUB_TOKEN만 있는 CI)에서는 도구가 URL에 토큰을 포함하여 HTTPS를 통해 푸시하는 것으로 대체됩니다. [git_transport] mode 설정이 이를 제어합니다(설정 참조 참조). 토큰이 포함된 URL은 리포지토리의 .git/config에 기록되지 않으며 모든 출력에서 수정됩니다.

API 접근 방식

모든 GitHub API 호출은 subprocess를 통해 gh api를 거칩니다. 이렇게 하면 인증이 전적으로 gh CLI에 유지됩니다 — 토큰 관리 코드, OAuth 흐름, PyGithub 버전 고정이 필요 없습니다. JSON 요청 본문은 --field 플래그가 아닌 --input -(stdin)을 통해 전달됩니다.


개발```bash

Clone and set up

git clone https://github.com/your-username/gh-safe-repo cd gh-safe-repo uv sync # creates .venv, installs pytest

Run tests

uv run pytest tests/ -v

Run the tool directly (without installing)

./gh-safe-repo create <owner/repo> --dry-run

Install globally (picks up the current source)

uv tool install .

root@kitploit:~
테스트 파일 설명, 모킹 규칙 및 새 테스트를 추가하는 방법은 [`tests/README.md`](https://github.com/ariesq/gh-safe-repo/blob/HEAD/tests/README.md)를 참조하세요.

### 프로젝트 구조```
gh-safe-repo/
├── gh-safe-repo          # Thin launcher (entry point for direct use)
├── gh_safe_repo/         # Package — see gh_safe_repo/README.md for internals
│   ├── cli.py            # Subparser dispatch (create, fix, scan)
│   ├── commands/         # Subcommand implementations
│   │   ├── _common.py    # Shared helpers, CLIContext, plan formatting
│   │   ├── create.py     # create subcommand
│   │   ├── fix.py        # fix subcommand
│   │   └── scan.py       # scan subcommand
│   └── plugins/          # Settings plugins (one per category)
├── pyproject.toml        # Build config, entry points
├── gh-safe-repo.ini.example  # Fully annotated example config
└── tests/

See gh_safe_repo/README.md for the module map, plugin architecture, and a guide to adding new settings.

Dependency policy

There are no runtime dependencies. Everything uses the Python standard library (argparse, configparser, subprocess, json, re). Do not add third-party packages without discussion.

pytest is the only dev dependency, declared as a UV-native [dependency-groups] entry in pyproject.toml.


Prior Art

These projects were studied during design and influenced the architecture of gh-safe-repo. They are distinct tools with different scope and user models — see docs/LEARNINGS.md for detailed technical notes on how patterns were adapted.

  • github/safe-settings — Org-level GitHub App (Node.js/Probot) that enforces repository settings from a central config. Source of the plugin architecture pattern (one class per setting category, fetch → diff → apply) and the mergeDeep comparison approach.

  • repository-settings/app — Simpler per-repo variant of safe-settings, also Node.js/Probot. Provided a cleaner reference for the Diffable base plugin pattern.

  • nicholasgasior/gh-repo-settings — CLI extension written in Go with a plan/apply workflow. Primary inspiration for the gh api subprocess wrapper pattern and the dry-run plan output design.

도구 다운로드
옵션설명
--public공개 리포지토리로 생성 (기본값: 비공개)
--local PATH로컬 git 리포지토리에서 새 리포지토리로 코드를 푸시합니다. 먼저 사전 점검을 실행합니다. --from과 상호 배타적입니다.
--from OWNER/REPO기존 리포지토리에서 새 리포지토리로 코드를 미러링합니다. 사전 점검을 실행합니다. --local과 상호 배타적입니다.
--yes / -y확인 프롬프트를 건너뛰고 즉시 적용합니다 (스크립팅/배치 사용용)
--dry-run변경 사항 없이 계획만 출력합니다.
--jsonANSI 테이블 대신 계획을 JSON으로 stdout에 출력합니다.
--config [PATH]설정 파일 경로; --config만 지정하면 기본 내장 설정만 사용합니다.
--debug모든 API 호출 및 응답을 출력합니다.
옵션설명
--yes / -y확인 프롬프트를 건너뛰고 즉시 적용합니다 (스크립팅/배치 사용용)
--dry-run변경 사항을 적용하지 않고 설정 차이만 표시합니다.
--jsonANSI 테이블 대신 계획을 JSON으로 stdout에 출력합니다.
--config [PATH]설정 파일 경로; --config만 지정하면 기본 내장 설정만 사용합니다.
--debug모든 API 호출 및 응답과 함께 확인된 리포지토리 식별 정보(id, 전체 이름, 소유자 유형)를 출력합니다.
새 설정이 적용 중
UPDATE (노란색)기존 설정이 변경 중 (감사 모드)
DELETE (빨간색)설정이 제거 중
SKIP (희미함)필요한 동작 없음 — 이미 원하는 값이거나, 현재 요금제/가시성 조합에서 기능을 사용할 수 없음
CategorySeverityExamples
하드코딩된 비밀치명적AWS 키 (AKIA…), GitHub 토큰 (ghp_…, github_pat_…), 개인 키, 데이터베이스 URL
금지된 문자열치명적구성한 모든 리터럴 문자열 (사용자 이름, 내부 호스트 이름, 코드명)
AI 컨텍스트 파일치명적CLAUDE.md, AGENTS.md, .cursorrules, copilot-instructions.md, .cursor/ — 내부 개발 노트가 포함될 수 있음; git 히스토리는 현재 버전보다 더 민감할 수 있음
이메일 주소경고작업 트리 및 git 히스토리에서 [email protected] 패턴
대용량 파일경고설정된 크기 임계값 초과 파일 (기본값: 100 MB)
TODO/FIXME 주석정보# TODO, # FIXME, # HACK, # XXX