Permissions — 도구·파일 접근 권한 정밀 제어
에이전트가 어떤 도구를, 어떤 파일·명령에 대해 사용할 수 있는지 한 줄짜리 패턴으로 정의하는 방법입니다. settings.json의 permissions.allow·permissions.deny 두 배열로 통제하며, Glob 패턴과 도구별 인자 형식을 알면 거의 모든 시나리오를 표현할 수 있습니다.
이 페이지의 permissions.allow / permissions.deny JSON 형식은 Claude Code 등 다른 에이전트의 표기법입니다. Antigravity v1.22.2(2026-04-08)부터는 Allow / Ask / Deny 3계층 통합 권한 시스템이 도입되어 GUI 중심으로 동작합니다.
Antigravity 사용자는 먼저 Unified Permissions (통합 권한) 페이지를 보고, 본 페이지는 Claude Code 호환 패턴 레퍼런스로 활용하세요.
1. 왜 권한 설정이 필요한가? #
에이전트는 기본적으로 모든 도구·파일에 접근할 수 있습니다. 이 상태로 자율적으로 동작시키면 다음과 같은 사고가 발생합니다.
- ❌ 비밀 노출 — 에이전트가 실수로
.env파일을 읽어 콘텐츠가 컨텍스트에 들어가고, 응답·로그에 유출. - ❌ 의도치 않은 파괴 —
git reset --hard나rm -rf를 자동 실행해 작업 손실. - ❌ 스코프 이탈 — 한 프로젝트 작업 중 다른 디렉터리(
~/.ssh등)를 건드림. - ❌ 매번 반복되는 확인 프롬프트 — 무한정 "이 도구를 실행할까요?"가 떠 흐름이 끊어짐.
권한 설정은 이 두 양 끝(완전 자유 vs 매번 확인)의 중간 지점을 잡아주는 도구입니다. 안전한 작업은 자동으로, 위험한 작업은 차단이라는 원칙을 한 번에 정의하고 재사용합니다.
allow), 사무실 층은 사원증으로(ask), 서버실은 관리자만(deny) 출입할 수 있도록 한 번에 규정합니다.
2. 기본 구조 & 우선순위 #
2.1 settings.json 위치
| 범위 | 파일 위치 | 적용 대상 |
|---|---|---|
| 전역 | ~/.gemini/settings.json |
이 컴퓨터의 모든 워크스페이스 |
| 워크스페이스 | 프로젝트_루트/.gemini/settings.json |
해당 프로젝트만 (팀 공유 가능) |
두 파일이 동시에 존재하면 워크스페이스 설정이 전역을 재정의합니다. 단, 권한은 "겹치는 항목 중 더 엄격한 쪽"이 적용된다고 이해하면 안전합니다 (자세한 우선순위는 2.3 참조).
2.2 가장 단순한 형태
{
"permissions": {
"allow": [
"Read(**/*.md)",
"Edit(**/*.py)",
"Write(**/*.json)",
"Bash(git diff:*)"
],
"deny": [
"Read(**/.env)",
"Edit(**/secrets/**)"
]
}
}
각 항목은 도구이름(패턴) 형식의 단일 문자열입니다. 위 예시를 한 줄씩 풀어 읽으면 다음과 같습니다.
| 패턴 | 의미 |
|---|---|
Read(**/*.md) | 워크스페이스 어디든 모든 .md 파일 읽기 자동 허용 |
Edit(**/*.py) | 모든 Python 파일 수정 자동 허용 (신규 생성은 별도) |
Write(**/*.json) | JSON 파일 신규 생성 또는 덮어쓰기 자동 허용 |
Bash(git diff:*) | git diff로 시작하는 모든 셸 명령 자동 허용 (git diff, git diff HEAD 등) |
Read(**/.env) | 이름이 .env인 모든 파일 읽기 영구 차단 (사용자 승인으로도 우회 불가) |
Edit(**/secrets/**) | secrets/ 디렉터리 안 모든 파일 수정 영구 차단 |
2.3 매칭 우선순위 (deny > allow > ask)
한 작업에 여러 패턴이 매칭될 수 있습니다. 이때 적용 순서는 다음과 같습니다.
- deny에 매칭되면 즉시 차단 — 사용자가 승인 버튼을 눌러도 실행되지 않습니다. 가장 강한 규칙입니다.
- allow에 매칭되면 자동 실행 — 별도의 사용자 확인 없이 진행됩니다.
- 둘 다 매칭되지 않으면 매번 사용자에게 묻기 — 기본 정책(ask)이 적용됩니다.
"Read(**/*)"로 모든 읽기를 허용해도, "Read(**/.env)"가 deny에 있으면 .env는 절대 읽히지 않습니다. 보안에 민감한 패턴은 항상 deny에 명시하세요. allow가 deny를 덮어쓸 수 없습니다.
2.4 전역 vs 워크스페이스 병합 규칙
두 파일이 동시에 있으면 두 배열이 합집합으로 합쳐진 뒤 위 우선순위가 적용됩니다.
- allow 합집합 — 전역과 워크스페이스 어느 한쪽에라도 있으면 허용
- deny 합집합 — 어느 한쪽에라도 있으면 차단
- 충돌 시 deny 승리 — 한쪽이 allow, 다른 쪽이 deny면 deny 적용
**/.env, **/secrets/**, ~/.ssh/** 등)만 적고, allow는 워크스페이스별로 프로젝트 특성에 맞게 작성하면 안전성과 유연성을 동시에 잡을 수 있습니다.
3. Glob 패턴 문법 #
경로 패턴은 표준 Glob 문법을 따릅니다. 정규식이 아니라 셸의 와일드카드와 같습니다.
3.1 핵심 와일드카드
| 기호 | 의미 | 매칭 예시 | 매칭 안 됨 |
|---|---|---|---|
* |
한 디렉터리 안의 임의의 문자 (구분자 / 제외) |
*.py → main.py, utils.py |
src/main.py (/ 포함) |
** |
모든 하위 디렉터리 재귀 매칭 | **/*.py → a.py, src/main.py, tests/unit/x.py |
— |
? |
임의의 한 글자 | file?.txt → file1.txt, fileA.txt |
file12.txt |
[abc] |
대괄호 안 글자 중 하나 | v[12].md → v1.md, v2.md |
v3.md |
{a,b} |
중괄호 안 옵션 중 하나 (Brace Expansion) | **/*.{js,ts} → app.js, app.ts |
app.py |
3.2 자주 헷갈리는 차이 — * vs **
* 한 개는 "이 디렉터리 안 한 단계"만, ** 두 개는 "여기부터 모든 하위 디렉터리"를 의미합니다.
# src 바로 아래 .py 파일만 (1단계)
"Edit(src/*.py)"
✅ src/main.py
❌ src/utils/helper.py # 한 단계 더 깊음
# src 아래 모든 단계의 .py 파일
"Edit(src/**/*.py)"
✅ src/main.py
✅ src/utils/helper.py
✅ src/a/b/c/x.py
# 워크스페이스 어디든 .py 파일
"Edit(**/*.py)"
✅ main.py
✅ src/utils/helper.py
✅ tests/unit/test_x.py
3.3 자주 쓰는 패턴 사전
| 목적 | 패턴 |
|---|---|
| 모든 마크다운 문서 | **/*.md |
| 여러 확장자 동시 매칭 | **/*.{py,pyi,ipynb} |
| 특정 디렉터리 전체 | tests/** |
| 특정 디렉터리 제외 (deny와 조합) | allow: **/*.py + deny: migrations/**/*.py |
| 숨김 파일·디렉터리 | **/.* (모든 dotfile) |
| 특정 환경설정 파일들 | **/{.env,.env.*,*.pem,id_rsa*} |
| 홈 디렉터리 보호 | ~/.ssh/**, ~/.aws/**, ~/.gnupg/** |
| 운영 데이터 보호 | data/raw/**, data/prod/** |
~/는 사용자 홈 디렉터리로 확장됩니다. 워크스페이스 밖의 절대 경로를 보호하고 싶을 때 유용합니다.
4. 도구별 패턴 형식 #
괄호 안에 들어가는 패턴 형식은 도구마다 조금씩 다릅니다.
4.1 파일 도구 — Read / Edit / Write
괄호 안에 파일 경로 Glob만 넣습니다.
# 읽기 — 파일 내용을 컨텍스트에 가져옴
"Read(**/*.md)"
"Read(docs/**)"
"Read(README.md)"
# 수정 — 기존 파일 변경
"Edit(src/**/*.py)"
"Edit(*.json)"
# 신규 생성 또는 덮어쓰기
"Write(output/**/*.csv)"
"Write(reports/*.html)"
Edit, 새 파일을 만들거나 통째로 덮어쓰는 것은 Write입니다. 두 권한은 독립적이므로 분석 결과만 새로 만들고 기존 코드는 못 고치게 하려면 Write만 허용하세요.
4.2 셸 도구 — Bash
Bash는 명령어 + : + 인자 패턴 형식을 씁니다. :*는 "이 명령어로 시작하는 모든 인자 조합"이라는 의미입니다.
# 정확히 'ls'만 허용 (인자 없음)
"Bash(ls)"
# 'git status'로 시작하는 모든 명령
"Bash(git status:*)"
✅ git status
✅ git status --short
✅ git status -uall
# 자주 쓰는 안전 명령 묶음
"Bash(git diff:*)"
"Bash(git log:*)"
"Bash(npm test:*)"
"Bash(pytest:*)"
# 위험 패턴은 deny로 차단
"Bash(rm -rf:*)" # deny에 추가
"Bash(git push --force:*)"
"Bash(curl:* | bash:*)"
"Bash(git:*)"처럼 너무 넓게 허용하면 git push --force origin main도 자동 실행됩니다. 명령어는 동사 단위(git diff, git log, git status)로 분리해 허용하는 것이 안전합니다.
4.3 네트워크 도구 — WebFetch
괄호 안에 URL 패턴 또는 도메인을 넣습니다.
# 특정 도메인만 허용 (서브도메인 포함)
"WebFetch(domain:docs.python.org)"
"WebFetch(domain:github.com)"
"WebFetch(domain:stackoverflow.com)"
# 서브도메인 와일드카드
"WebFetch(domain:*.anthropic.com)"
# 사내망·민감 URL은 명시적 차단
"WebFetch(domain:*.internal.example.com)" # deny에 추가
4.4 도구 형식 한눈에 보기
| 도구 | 패턴 형식 | 예시 |
|---|---|---|
Read | 파일 Glob | Read(**/*.md) |
Edit | 파일 Glob | Edit(src/**/*.py) |
Write | 파일 Glob | Write(output/*.csv) |
Bash | 명령어:인자패턴 | Bash(git diff:*) |
WebFetch | domain:호스트 | WebFetch(domain:github.com) |
5. 실전 프리셋 — 복사해 시작하기 #
아래 프리셋을 출발점으로 삼아 프로젝트에 맞게 조정하세요. 모두 "deny는 보수적으로 / allow는 점진적으로"라는 원칙을 따릅니다.
5.1 데이터 분석 프로젝트 (Python + 노트북)
{
"permissions": {
"allow": [
"Read(**/*.{md,py,ipynb,csv,xlsx,json,yaml,toml})",
"Edit(**/*.{py,ipynb,md})",
"Write(reports/**/*.{html,png,csv})",
"Write(notebooks/**/*.ipynb)",
"Bash(uv:*)",
"Bash(python:*)",
"Bash(pytest:*)",
"Bash(jupyter:*)",
"Bash(git status:*)",
"Bash(git diff:*)",
"Bash(git log:*)",
"WebFetch(domain:docs.python.org)",
"WebFetch(domain:pandas.pydata.org)",
"WebFetch(domain:scikit-learn.org)"
],
"deny": [
"Read(**/.env)",
"Read(**/.env.*)",
"Read(**/secrets/**)",
"Read(**/credentials.*)",
"Edit(data/raw/**)",
"Edit(data/prod/**)",
"Bash(rm -rf:*)",
"Bash(git push --force:*)",
"Bash(git reset --hard:*)"
]
}
}
의도: 노트북·스크립트·리포트는 자유롭게 작성·수정하되, 원본 데이터(data/raw, data/prod)와 비밀 파일은 절대 건드리지 못하게 합니다. 위험한 git 명령은 자동 실행을 막습니다.
5.2 웹 프론트엔드 프로젝트 (TypeScript + React)
{
"permissions": {
"allow": [
"Read(**/*.{ts,tsx,js,jsx,json,md,css,scss,html})",
"Edit(src/**/*.{ts,tsx,css,scss})",
"Write(src/**/*.{ts,tsx})",
"Edit(*.json)",
"Bash(npm:*)",
"Bash(pnpm:*)",
"Bash(npx:*)",
"Bash(tsc:*)",
"Bash(vitest:*)",
"Bash(eslint:*)",
"Bash(prettier:*)",
"WebFetch(domain:react.dev)",
"WebFetch(domain:developer.mozilla.org)",
"WebFetch(domain:typescriptlang.org)"
],
"deny": [
"Read(**/.env*)",
"Edit(node_modules/**)",
"Edit(dist/**)",
"Edit(build/**)",
"Bash(npm publish:*)",
"Bash(rm -rf:*)"
]
}
}
의도: src/ 안의 코드만 수정 가능하고, 빌드 산출물(dist, build, node_modules)은 보호됩니다. npm publish처럼 외부에 영향 가는 명령은 매번 확인이 필요하도록 deny.
5.3 전역 안전망 (모든 프로젝트 공통 deny)
{
"permissions": {
"deny": [
"Read(**/.env)",
"Read(**/.env.*)",
"Read(**/secrets/**)",
"Read(**/credentials.*)",
"Read(~/.ssh/**)",
"Read(~/.aws/**)",
"Read(~/.gnupg/**)",
"Read(**/id_rsa*)",
"Read(**/*.pem)",
"Edit(~/.ssh/**)",
"Edit(~/.aws/**)",
"Bash(rm -rf:*)",
"Bash(rm -rf /:*)",
"Bash(sudo:*)",
"Bash(curl:* | bash:*)",
"Bash(curl:* | sh:*)"
]
}
}
의도: 워크스페이스 설정 실수와 무관하게 비밀·시스템 디렉터리·파괴적 명령은 항상 차단됩니다. allow는 비워두고 워크스페이스에서 프로젝트별로 작성하세요.
6. 디버깅 & 트러블슈팅 #
6.1 권한이 적용되지 않을 때 체크리스트
- JSON 문법 오류 — 콤마 누락, 따옴표 불일치가 가장 흔합니다.
cat .gemini/settings.json | python3 -m json.tool로 검증하세요. - 재시작 누락 — 권한 변경은 Antigravity 재시작 후 적용됩니다. 변경 직후 같은 세션에서는 옛 정책이 동작합니다.
- 경로 패턴 미스매치 —
*.py는 한 단계만,**/*.py는 모든 단계입니다. 6.3의 빠른 테스트로 확인하세요. - 전역과 충돌 — 워크스페이스에서 allow한 항목이 전역 deny에 매칭되면 차단됩니다. 두 파일을 모두 확인하세요.
- 도구 이름 오타 —
read가 아니라Read입니다 (대소문자 구분).
6.2 "왜 자꾸 물어보지?" — 누락된 allow 찾기
같은 작업에 매번 확인 프롬프트가 뜨면, 사용자에게 표시된 도구·인자를 그대로 allow에 추가하세요. 예를 들어 "Bash uv pip install pandas 실행할까요?"가 반복된다면:
# 너무 좁음 — pandas 외에는 또 물어봄
"Bash(uv pip install pandas)"
# 적절 — 모든 패키지 설치 허용
"Bash(uv pip install:*)"
# 너무 넓음 — uv pip uninstall도 자동 실행됨
"Bash(uv:*)"
6.3 패턴 매칭 빠른 테스트
의심스러운 패턴은 셸의 Glob 확장으로 미리 확인할 수 있습니다.
# src/**/*.py 패턴이 어떤 파일을 매칭하는지 확인
shopt -s globstar # bash에서 **를 활성화
ls src/**/*.py
# Python의 pathlib로 동일 검증 (OS 독립)
python3 -c "from pathlib import Path; print('\n'.join(str(p) for p in Path('.').glob('src/**/*.py')))"
6.4 자주 묻는 질문
모든 도구 호출에 매번 사용자 확인을 요청합니다. 차단(deny)이 아니라 "매번 묻기"입니다. 완전 차단은 명시적으로 deny에 추가해야 합니다.
deny가 항상 승리합니다. 의도적으로 "예외적으로 한 파일만 허용"하려면, deny 패턴을 더 좁게 작성하세요. 예: deny
**/secrets/** + allow secrets/sample.json → 후자도 deny에 매칭되어 차단됨. 대신 deny를 secrets/**/*.real.json처럼 좁히세요.
네. MCP 서버 도구는
mcp__<server>__<tool> 형식의 도구 이름으로 매칭합니다. 예: "mcp__github__create_pull_request(*)". 자세한 형식은 도구 호출 시 표시되는 이름을 참고하세요.