Blog JSystems - uwalniamy wiedzę!

Szukaj

Z tego artykułu dowiesz się:

  • Jak działa architektura uprawnień Claude Code (trzy warstwy)
  • Czym są tryby uprawnień i kiedy używać --dangerously-skip-permissions
  • Jak zbudować hierarchię plików settings.json (enterprise -> global -> project -> local)
  • Jak konfigurować listy allow i deny (operacje dozwolone i zablokowane) oraz wzorce Bash glob
  • Jak pisać hooks PreToolUse i PostToolUse do audytu i blokowania operacji
  • Jak wdrożyć polityki organizacyjne dla całego zespołu

Kiedy dajesz asystentowi AI dostęp do systemu plików i shella (powłoki systemu — czyli wiersza poleceń, w którym wpisuje się komendy), dajesz mu w praktyce klucze do swojego środowiska pracy. Claude Code rozwiązuje to elegancko — system uprawnień działa na trzech niezależnych warstwach, które można ze sobą łączyć: interaktywne zatwierdzanie na bieżąco, statyczna (z góry ustalona) konfiguracja w plikach JSON — prostym, tekstowym formacie zapisu danych — oraz dynamiczne hooks uruchamiane przed każdą operacją. Każda warstwa daje inny poziom kontroli i pasuje do innych sytuacji.

Architektura systemu uprawnień Claude Code
Kolejność sprawdzania uprawnień w Claude Code: najpierw lista deny (blokada), potem lista allow (zgoda automatyczna), potem hook — który decyduje kodem wyjścia: 0 = przepuść, wartość różna od zera = zablokuj — a na końcu pytanie do użytkownika

1. Trzy warstwy systemu uprawnień

Zanim przejdziemy do konfiguracji, warto zrozumieć model mentalny. Claude Code sprawdza uprawnienia w ściśle określonej kolejności:

  1. Statyczna lista deny (lista zakazów; z ang. deny = odmów) — jeśli operacja pasuje do permissions.deny w settings.json, jest natychmiast blokowana bez pytania.
  2. Statyczna lista allow (lista dozwoleń; z ang. allow = zezwól) — jeśli operacja pasuje do permissions.allow, jest wykonywana automatycznie bez pytania.
  3. Hook PreToolUse — jeśli żaden z powyższych nie pasuje, a skonfigurowano hook (Twój własny skrypt uruchamiany automatycznie — dokładnie omawiamy hooki w sekcji 5), zostaje on wywołany. O tym, czy operacja przejdzie, decyduje kod wyjścia skryptu (ang. exit code): 0 = przepuść, wartość różna od zera = zablokuj. To uniwersalna konwencja systemów uniksowych: 0 zawsze znaczy „zakończono OK", a każda inna liczba „wystąpił błąd".
  4. Interaktywne zapytanie — jeśli żadna reguła nie pasuje, Claude pyta użytkownika w terminalu.

Wynik: możesz mieć jednocześnie zautomatyzowane zatwierdzanie bezpiecznych operacji (git status, czytanie plików), dynamiczną walidację operacji potencjalnie niebezpiecznych (hooks) i ostateczne pytanie do użytkownika dla wszystkiego co nie zostało skategoryzowane.

2. Tryby uprawnień

Tryb domyślny — interaktywny

Domyślnie Claude Code pyta o pozwolenie przed każdą potencjalnie destrukcyjną operacją: zapisem pliku, wykonaniem komendy bash, połączeniem z zewnętrznym API (interfejsem, przez który programy komunikują się ze sobą). Takie pytanie o zgodę (prompt) wygląda następująco:

Interaktywny prompt uprawnień Claude Code
Claude Code pyta o zgodę na wykonanie komendy bash — widoczna jest treść komendy, jej kontekst i opcje odpowiedzi

Opcje w interaktywnym promptcie:

  • Yes — zatwierdź jednorazowo
  • Yes, don't ask again (this session) — zatwierdź i nie pytaj o tę operację przez resztę sesji
  • No — odrzuć operację

Tryb automatyczny — --dangerously-skip-permissions

W środowiskach CI/CD (skrót od Continuous Integration / Continuous Delivery — zautomatyzowane budowanie, testowanie i wdrażanie kodu, np. GitHub Actions czy GitLab CI) albo w izolowanych kontenerach Docker możesz uruchomić Claude Code z flagą:

claude --dangerously-skip-permissions "napraw wszystkie błędy typowania w src/"

Uwaga: flaga --dangerously-skip-permissions wyłącza WSZYSTKIE interaktywne pytania. Używaj jej wyłącznie w izolowanych środowiskach — np. w kontenerze Docker bez podpiętych wrażliwych katalogów albo na jednorazowej, kasowanej zaraz po zadaniu maszynie wirtualnej w systemie CI. Nigdy na maszynie z dostępem do kluczy produkcyjnych, bazy danych czy konta AWS.

Tryb nieinteraktywny — --print

Flaga -p / --print uruchamia Claude w trybie jednorazowym (ang. one-shot: jedno zapytanie -> odpowiedź -> zamknięcie programu). W tym trybie brak odpowiedzi na pytanie o uprawnienia = operacja odrzucona. Bezpieczne do skryptowania (uruchamiania w skryptach) bez ryzyka, że proces się zawiesi w oczekiwaniu na odpowiedź.

claude -p "Ile linii kodu ma src/main.py?" --output-format json

3. Hierarchia plików settings.json

Claude Code ładuje konfigurację z czterech lokalizacji w kolejności rosnącego priorytetu:

Hierarchia plików settings.json w Claude Code
Cztery poziomy konfiguracji — enterprise ma najwyższy priorytet i nie może być nadpisany przez użytkownika
Poziom Lokalizacja Gitowany? Kto zarządza Priorytet
Enterprise plik wdrażany przez MDM/GPO (ścieżka zależna od platformy) NIE Dział IT / admin Najwyższy
Global ~/.claude/settings.json NIE Programista (maszyna) 2
Project .claude/settings.json TAK Cały zespół 3
Local .claude/settings.local.json NIE (gitignore) Programista (projekt) Najniższy

Plik globalny — ~/.claude/settings.json

Ustawienia globalne stosują się do WSZYSTKICH projektów na tej maszynie. Dobre miejsce na uprawnienia które dajesz sobie bezwarunkowo (np. czytanie plików, podstawowe komendy git).

Globalny plik settings.json Claude Code
Globalny plik ~/.claude/settings.json — dozwolone operacje dla całej maszyny. To zrzut ekranu; kod do skopiowania znajduje się poniżej.
// ~/.claude/settings.json — ustawienia globalne maszyny
{
  "permissions": {
    "allow": [
      "Read",
      "Bash(git status)",
      "Bash(git log *)",
      "Bash(git diff *)",
      "Bash(git branch *)"
    ],
    "deny": [
      "Bash(git push --force *)",
      "Bash(git push -f *)",
      "Bash(sudo *)"
    ]
  }
}

Powyżej to zrzut ekranu — ten sam kod skopiujesz przyciskiem „Kopiuj".

Plik projektowy — .claude/settings.json

To najważniejszy plik z perspektywy zespołu. Commitowany do repozytorium (czyli zapisany w historii projektu w git i widoczny dla wszystkich), stosuje się do każdego, kto pracuje z projektem. Definiuje zasady specyficzne dla danego projektu — jakie komendy są bezpieczne, a jakie nigdy nie powinny być uruchamiane automatycznie.

Projektowy plik .claude/settings.json
Plik .claude/settings.json commitowany do repo — zasady uprawnień dla całego zespołu. To zrzut ekranu; kod do skopiowania znajduje się poniżej.
// .claude/settings.json — zasady projektowe (commituj do repo!)
{
  "permissions": {
    "allow": [
      "Write",
      "Edit",
      "Bash(npm *)",
      "Bash(npx *)",
      "Bash(python -m pytest *)",
      "Bash(python -m mypy *)",
      "Bash(docker compose up *)",
      "Bash(docker compose down)",
      "Bash(make *)"
    ],
    "deny": [
      "Bash(rm -rf *)",
      "Bash(curl * | bash)",
      "Bash(wget * | sh)",
      "Bash(pip install *)",        // tylko przez requirements.txt
      "Bash(npm install -g *)",     // globalne instalacje zablokowane
      "Bash(docker system prune *)"
    ]
  }
}

Powyżej to zrzut ekranu — ten sam kod skopiujesz przyciskiem „Kopiuj".

Plik lokalny — .claude/settings.local.json

Lokalny plik jest niewidoczny dla współpracowników (gitignore). Służy do nadpisań specyficznych dla Twojej maszyny — np. dodatkowe uprawnienia debugowania, lokalne ścieżki, tymczasowe zmiany.

Lokalny plik .claude/settings.local.json
Plik .claude/settings.local.json — prywatne nadpisania tylko dla Twojej maszyny (poza repozytorium). To zrzut ekranu; kod do skopiowania znajduje się poniżej.
// .claude/settings.local.json — tylko moja maszyna, nie commituj!
{
  "permissions": {
    "allow": [
      "Bash(pip install *)",   // lokalnie pozwalam — mam własny venv
      "Bash(psql *)",           // dostęp do lokalnej bazy
      "Bash(./scripts/seed-db.sh)"
    ]
  }
}

Powyżej to zrzut ekranu — ten sam kod skopiujesz przyciskiem „Kopiuj".

Wskazówka: dodaj .claude/settings.local.json do .gitignore raz na zawsze przez globalny gitignore: echo ".claude/settings.local.json" >> ~/.gitignore_global i git config --global core.excludesfile ~/.gitignore_global.

4. Wzorce Bash glob — precyzyjna kontrola komend

Bash uprawnienia używają wzorców glob — to prosty sposób dopasowywania tekstu, w którym gwiazdka * zastępuje „dowolny ciąg znaków". To ten sam mechanizm, którego używasz w terminalu pisząc np. ls *.txt, żeby wylistować wszystkie pliki z rozszerzeniem .txt. Tutaj wzorzec porównywany jest z całą komendą potraktowaną jak zwykły tekst. Daje to bardzo dużą precyzję — możesz pozwolić na git commit blokując jednocześnie git push.

Wzorce Bash glob w Claude Code permissions
Wzorce glob dla Bash — od szerokich (* = cokolwiek) po precyzyjne (konkretna flaga lub argument)

Składnia wzorców

Wzorzec Dopasowuje Nie dopasowuje
Bash(git *) git status, git log, git commit npm, docker
Bash(git commit *) git commit -m "msg" git push, git reset
Bash(npm test) npm test (dokładnie) npm test -- --watch
Bash(npm test *) npm test, npm test -- --watch npm install
Bash(rm *) rm plik.txt, rm -rf /!

Pułapka: Bash(rm *) pozwala na rm -rf /. Wzorzec pasuje do całej komendy po rm, więc obejmuje też najbardziej destrukcyjne warianty. Zawsze sprawdź, czy nie dajesz zbyt szerokich uprawnień. Bezpieczniej zawęzić wzorzec — albo do konkretnego rozszerzenia: Bash(rm *.tmp) (tylko pliki .tmp w bieżącym katalogu), albo do konkretnej ścieżki: Bash(rm ./build/*) czy Bash(rm /tmp/cache/*) — wtedy usuwanie jest ograniczone do jednego katalogu i komenda nie sięgnie poza niego.

Przykłady bezpiecznych konfiguracji per typ projektu

// Projekt Python (Django/FastAPI)
"allow": [
  "Bash(python -m pytest *)",
  "Bash(python manage.py *)",
  "Bash(python manage.py migrate)",
  "Bash(python manage.py makemigrations *)",
  "Bash(python -m mypy *)",
  "Bash(python -m black *)",
  "Bash(python -m ruff *)"
]

// Projekt Node.js / TypeScript
"allow": [
  "Bash(npm run *)",
  "Bash(npx tsc *)",
  "Bash(npx eslint *)",
  "Bash(node *)",
  "Bash(pnpm *)"
]

// Projekt infrastruktury (Terraform/Ansible)
"allow": [
  "Bash(terraform fmt *)",
  "Bash(terraform validate)",
  "Bash(terraform plan *)"
],
"deny": [
  "Bash(terraform apply *)",  // ZAWSZE ręcznie!
  "Bash(terraform destroy *)"
]

5. Hooks — dynamiczna kontrola w czasie rzeczywistym

Czym w ogóle jest hook? Wyobraź sobie ochroniarza przy wejściu, który sprawdza każdego gościa, zanim wpuści go do środka — może przepuścić, zawrócić albo po prostu zanotować w zeszycie, kto i kiedy wchodził. Hook robi to samo, tylko wobec operacji Claude'a. Mówiąc technicznie: hook (dosłownie „zaczep", „hak") to Twój własny, krótki program — zwykły plik bash albo Python — który Claude Code uruchamia sam, automatycznie w ściśle określonym momencie. Najczęściej tuż przed tym, jak Claude zamierza użyć jakiegoś narzędzia (wykonać komendę w terminalu, zapisać plik), albo zaraz po tym. Nie musisz o niego prosić za każdym razem ani liczyć, że model „będzie pamiętał" — hook odpala się zawsze, tak samo, przy każdej takiej operacji.

Po co to komu? Listy allow i deny z wcześniejszych sekcji są sztywne: coś jest albo dozwolone, albo nie. Hook pozwala podjąć decyzję na bieżąco, według dowolnej reguły, którą sam napiszesz. Kilka konkretnych przykładów, do czego się przydaje:

  • Audyt — zapisuj do pliku każdą komendę, jaką Claude wykonał, żeby móc później sprawdzić, co się działo.
  • Warunkowa blokada — „zatrzymaj każdą komendę, w której pojawia się słowo prod", nawet jeśli lista allow/deny jej nie przewidziała.
  • Automatyczny porządek — po każdym zapisie pliku uruchom formatowanie kodu albo testy.
  • Zewnętrzna zgoda — zapytaj inny system (np. firmowy serwis autoryzacji), czy wolno wykonać daną operację.

To dokładnie ta sama idea, co hooki w git (skrypt uruchamiany np. przed każdym commitem) albo „nasłuchiwacze zdarzeń" znane z aplikacji — kawałek Twojego kodu, który system sam wywołuje w odpowiednim momencie.

Zapamiętaj jedno pojęcie — „kod wyjścia" (ang. exit code). Każdy program po zakończeniu zwraca systemowi jedną liczbę. Reguła jest uniwersalna w całym świecie systemów uniksowych: 0 znaczy „zakończyłem się OK", a każda inna liczba (1, 2, ...) znaczy „coś poszło nie tak / błąd". Hook typu PreToolUse wykorzystuje to jako swoją decyzję: skrypt kończy się kodem 0 = operacja przechodzi; kończy się kodem różnym od zera = operacja zostaje zablokowana. W bash ustawiasz to poleceniem exit 0 lub exit 1, w Pythonie — sys.exit(0) / sys.exit(1).

Animacja przepływu hooka w Claude Code
Animacja — przebieg hooka: Claude decyduje o narzędziu -> hook PreToolUse -> kod wyjścia 0 = zezwól, różny od zera = blokada -> uruchomienie narzędzia -> hook PostToolUse (już po operacji)

Typy hooks i kiedy są wywoływane

Hook Kiedy Kod wyjścia ma znaczenie? Zastosowanie
PreToolUse Przed wywołaniem narzędzia TAK — niezerowy = blokada Walidacja, audyt, warunkowe blokowanie
PostToolUse Po zakończeniu narzędzia NIE (informacyjny) Sprawdzanie kodu (linting), testy, powiadomienia, logi
Notification Gdy Claude ma powiadomienie NIE Integracja z systemami alertów
Stop Gdy Claude kończy pracę NIE Sprzątanie po zadaniu, raporty końcowe

Konfiguracja hooks w settings.json

Konfiguracja hooks w settings.json
Sekcja hooks w pliku settings.json — reguła dopasowania (matcher) określa, dla którego narzędzia hook ma się uruchomić. To zrzut ekranu; kod do skopiowania znajduje się poniżej.
// .claude/settings.json — konfiguracja hooks
{
  "permissions": { /* ... */ },
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",          // "Bash", "Write", "Read", "*" (wszystkie)
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/check-bash.sh"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/lint-after-write.sh"
          }
        ]
      }
    ]
  }
}

Powyżej to zrzut ekranu — ten sam kod skopiujesz przyciskiem „Kopiuj".

Struktura jest prosta: w sekcji hooks wskazujesz moment (PreToolUse — przed operacją, albo PostToolUse — po niej), a w nim listę reguł. Każda reguła ma matcher (dla którego narzędzia hook ma zadziałać — np. Bash, Write, Read lub * = wszystkie) oraz command (ścieżkę do skryptu, który zostanie uruchomiony).

Dane wejściowe hooka — JSON na wejściu

Każdy hook dostaje na standardowym wejściu (stdin — strumień, którym program przyjmuje dane; w bashu czytasz go przez cat, w Pythonie przez sys.stdin) porcję danych w formacie JSON z pełnym kontekstem wywołania narzędzia. Możesz je odczytać i przetworzyć w bashu lub Pythonie:

# Przykład JSON który hook otrzymuje na stdin (Bash PreToolUse):
{
  "tool_name": "Bash",
  "tool_input": {
    "command": "rm -rf ./build",
    "description": "Clean build directory"
  },
  "session_id": "abc-123",
  "tool_use_id": "toolu_xyz"
}

Przykład 1 — Audit log (bash)

Prosty hook który loguje każdą komendę bash do pliku — przydatny do śledzenia co Claude robił w projekcie:

Hook audytu komend bash w Claude Code
Hook PreToolUse logujący każdą komendę bash — wyniki widoczne w pliku .claude/audit.log. To zrzut ekranu; kod do skopiowania znajduje się poniżej.
#!/bin/bash
# .claude/hooks/audit-bash.sh
# Loguje każdą komendę bash wykonywaną przez Claude

AUDIT_FILE=".claude/audit.log"
INPUT=$(cat)

COMMAND=$(echo "$INPUT" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['tool_input']['command'])")
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')

echo "[$TIMESTAMP] BASH: $COMMAND" >> "$AUDIT_FILE"

exit 0  # zawsze zezwól — tylko logujemy

Powyżej to zrzut ekranu — ten sam kod skopiujesz przyciskiem „Kopiuj".

Co ten skrypt robi, linijka po linijce:

  • INPUT=$(cat) — wczytuje dane, które Claude Code podaje hookowi na wejście (to wspomniany wyżej JSON z opisem operacji).
  • linijka z python3 — wyciąga z tego JSON-a samą treść komendy bash (pole tool_input.command).
  • date — pobiera aktualną datę i godzinę, żeby wiedzieć, kiedy operacja się wydarzyła.
  • echo ... >> "$AUDIT_FILE" — dopisuje jedną linię (data + komenda) na koniec pliku .claude/audit.log (>> oznacza „dopisz na końcu", nie „nadpisz").
  • exit 0 — kończy się kodem wyjścia 0, czyli „przepuść". Ten hook niczego nie blokuje — tylko po cichu zapisuje, co się działo.

Przykład 2 — Blokowanie niebezpiecznych komend (Python)

Bardziej zaawansowany hook blokujący konkretne wzorce komend. Zwraca exit code 1 gdy komenda jest potencjalnie niebezpieczna:

Hook blokujący niebezpieczne komendy
Hook Python blokujący komendy z wzorcem 'force' lub 'reset --hard' — Claude widzi komunikat blokady. To zrzut ekranu; kod do skopiowania znajduje się poniżej.
#!/usr/bin/env python3
# .claude/hooks/check-dangerous.py
# Blokuje komendy potencjalnie destrukcyjne

import json
import sys
import re

# Wzorce które ZAWSZE wymagają ręcznego zatwierdzenia
DANGEROUS_PATTERNS = [
    r"git\s+push\s+.*(--force|-f)",
    r"git\s+reset\s+--hard",
    r"git\s+clean\s+.*-[fd]",
    r"rm\s+.*-[rf].*/",
    r"DROP\s+(TABLE|DATABASE)",
    r"(curl|wget).*\|\s*(bash|sh)",
]

try:
    data = json.load(sys.stdin)
    command = data.get("tool_input", {}).get("command", "")

    for pattern in DANGEROUS_PATTERNS:
        if re.search(pattern, command, re.IGNORECASE):
            print(f"ZABLOKOWANO: Komenda pasuje do wzorca '{pattern}'",
                  file=sys.stderr)
            print("Wymagane ręczne zatwierdzenie dla tej operacji.",
                  file=sys.stderr)
            sys.exit(1)  # kod wyjścia 1 = Claude Code blokuje operację

except Exception as e:
    print(f"Hook error: {e}", file=sys.stderr)

sys.exit(0)  # kod wyjścia 0 = operacja dozwolona

Powyżej to zrzut ekranu — ten sam kod skopiujesz przyciskiem „Kopiuj".

Jak to działa: lista DANGEROUS_PATTERNS zawiera wzorce (tzw. wyrażenia regularne — sposób opisywania „pasujących" fragmentów tekstu) dla komend, których nigdy nie chcemy puścić automatycznie: git push --force, git reset --hard, kasowanie plików przez rm, usuwanie tabel w bazie (DROP TABLE) czy pobieranie i uruchamianie skryptu prosto z internetu (curl ... | bash). Skrypt czyta komendę z wejścia i porównuje ją po kolei z każdym wzorcem:

  • jeśli komenda pasuje do któregoś wzorca — wypisuje komunikat i kończy się przez sys.exit(1) (kod wyjścia różny od zera = blokada, Claude nie wykona operacji);
  • jeśli nie pasuje do żadnego — dochodzi do sys.exit(0) na końcu (kod 0 = przepuść).

Przykład 3 — PostToolUse: automatyczne sprawdzenie kodu po zapisie

Po każdym zapisie pliku Python uruchom automatycznie linter i testy jednostkowe:

#!/bin/bash
# .claude/hooks/lint-after-write.sh
# Uruchamia linter po każdym zapisie pliku

INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | python3 -c "import json,sys; print(json.load(sys.stdin)['tool_input'].get('path',''))")

# Tylko pliki Python
if [[ "$FILE_PATH" == *.py ]]; then
    echo "Uruchamiam ruff na $FILE_PATH..."
    python3 -m ruff check "$FILE_PATH" --fix 2>&1
    if [[ "$FILE_PATH" == src/* ]]; then
        echo "Uruchamiam testy powiązane..."
        python3 -m pytest tests/ -x -q 2>&1 || echo "Testy: sprawdź błędy"
    fi
fi

exit 0  # PostToolUse — kod wyjścia bez znaczenia

Jak to działa: ten hook jest typu PostToolUse, czyli uruchamia się po zapisaniu pliku. Wyciąga z danych wejściowych ścieżkę zapisanego pliku i — jeśli to plik Pythona (.py) — automatycznie uruchamia na nim ruff (narzędzie sprawdzające i poprawiające kod, tzw. linter), a dla plików z katalogu src/ dodatkowo odpala testy. Dzięki temu zaraz po każdej zmianie od razu wiadomo, czy kod nadal się „trzyma". W hooku PostToolUse kod wyjścia nie ma już znaczenia — operacja została już wykonana, więc taki hook służy do reakcji po fakcie, a nie do blokowania.

Wskazówka: to, co hook wypisze na standardowe wyjście (stdout), trafia prosto do Claude'a jako dodatkowy kontekst. Możesz więc zwracać z hooka dowolne informacje — wynik sprawdzenia kodu (linting to automatyczna analiza kodu pod kątem błędów i stylu), status testów, ostrzeżenia — a Claude je zobaczy i na ich podstawie skoryguje kolejne kroki.

6. Uprawnienia serwerów MCP

Claude Code obsługuje serwery MCP (Model Context Protocol — standard, dzięki któremu Claude może korzystać z zewnętrznych narzędzi i źródeł danych, np. przeglądarki, bazy danych czy repozytorium plików). Każdy taki serwer działa jako osobny program i ma własne uprawnienia — możesz je kontrolować przez settings.json.

Spójrzmy na konkretny przykład. Poniższa konfiguracja robi dwie rzeczy naraz: najpierw podłącza dwa serwery MCP (sekcja mcpServers), a następnie — w sekcji permissionsdecyduje, z których dokładnie ich narzędzi Claude może korzystać:

Uprawnienia MCP servers w Claude Code
Narzędzia z serwerów MCP mają przedrostek mcp__nazwaserwera__ — możesz je dozwolić lub zablokować (allow/deny) tak samo jak wbudowane narzędzia. To zrzut ekranu; kod do skopiowania znajduje się poniżej.
// Konfiguracja MCP servers w ~/.claude/settings.json
{
  "mcpServers": {
    "playwright": {
      "command": "npx",
      "args": ["@playwright/mcp"]
    },
    "filesystem": {
      "command": "npx",
      "args": ["@modelcontextprotocol/server-filesystem", "/tmp"]
                    // ograniczamy dostęp tylko do /tmp!
    }
  },
  "permissions": {
    "allow": [
      "mcp__playwright__browser_navigate",
      "mcp__playwright__browser_take_screenshot"
    ],
    "deny": [
      "mcp__playwright__browser_evaluate"   // blokuj eval JS w przeglądarce
    ]
  }
}

Powyżej to zrzut ekranu — ten sam kod skopiujesz przyciskiem „Kopiuj".

Co robi ta konfiguracja — sekcja po sekcji:

  • mcpServers — podłącza dwa serwery MCP: playwright (sterowanie przeglądarką — otwieranie stron, klikanie, robienie zrzutów) oraz filesystem (dostęp do plików), przy czym temu drugiemu z góry ograniczamy zasięg tylko do katalogu /tmp. Same serwery to gotowe paczki uruchamiane poleceniem npx — nie musisz nic pisać samodzielnie.
  • permissions.allow — spośród wszystkich narzędzi, jakie te serwery udostępniają, pozwalamy Claude'owi tylko na dwa: otwieranie strony (browser_navigate) i robienie zrzutu ekranu (browser_take_screenshot).
  • permissions.deny — i jawnie blokujemy jedno konkretne narzędzie: browser_evaluate, które pozwala wykonać dowolny kod JavaScript w przeglądarce (a to potencjalnie groźne).

Zwróć uwagę na schemat nazw: każde narzędzie z serwera MCP ma postać mcp__nazwaserwera__nazwanarzędzia. Dzięki temu na listach allow/deny wskazujesz konkretne narzędzie, a nie cały serwer — możesz więc podłączyć serwer, ale udostępnić Claude'owi tylko jego bezpieczną część.

7. Polityki Enterprise / Organizations

W środowiskach korporacyjnych administrator może definiować polityki które nie mogą być nadpisane przez indywidualnych użytkowników. Takie odgórnie narzucone ustawienia (ang. managed settings) mają absolutny priorytet nad wszystkim innym.

Wdraża się je przez firmowe systemy do centralnego zarządzania komputerami pracowników. Dwa najczęstsze skróty, które tu spotkasz, to MDM i GPO:

  • MDM (Mobile Device Management) — system, którym dział IT zdalnie konfiguruje i pilnuje firmowych urządzeń (najczęściej macOS, telefony, tablety). Administrator „wypycha" ustawienia na wszystkie maszyny naraz.
  • GPO (Group Policy Object, zasady grupy) — odpowiednik w świecie Windows: mechanizm, którym administrator narzuca ustawienia wszystkim komputerom w firmowej domenie (dziś często przez usługę Intune).

W obu przypadkach chodzi o to samo: plik z politykami trafia na komputer pracownika odgórnie, a użytkownik nie może go zmienić ani usunąć.

Enterprise policies w Claude Code
Polityka firmowa — administrator IT wdraża ją przez MDM/konfigurację systemową, użytkownicy nie mogą jej zmienić. To zrzut ekranu; kod do skopiowania znajduje się poniżej.
// Przykład polityki enterprise (wdrożonej przez IT przez MDM/GPO):
// Blokuje wysyłanie kodu do zewnętrznych usług AI i dostęp do sekretów
{
  "permissions": {
    "deny": [
      "Bash(curl *openai.com*)",
      "Bash(curl *anthropic.com*)",
      "Bash(cat */.env*)",
      "Bash(cat *secret*)",
      "Bash(aws *)",
      "Bash(gcloud *)"
    ]
  }
}

Powyżej to zrzut ekranu — ten sam kod skopiujesz przyciskiem „Kopiuj".

Polityki enterprise wdraża się przez platformowy mechanizm zarządzania (MDM na macOS, GPO/Intune na Windows). Format JSON jest taki sam jak w zwykłym .claude/settings.json — administrator zamraża wybrane klucze, użytkownik nie może ich nadpisać.

8. Animacja — jak Claude Code wybiera tryb uprawnień

Animacja przepływu decyzji o uprawnieniach w Claude Code
Animacja: droga od żądania narzędzia do decyzji — lista deny -> lista allow -> hook -> interaktywny prompt (pytanie do użytkownika)

9. Praktyczne szablony konfiguracji

Nie ma jednego „właściwego" zestawu uprawnień — dobiera się go do ryzyka danego środowiska. Prosta zasada: im mniej wrażliwych rzeczy Claude może tu zepsuć (sekrety, produkcyjne bazy, infrastruktura), tym luźniej możesz pozwolić mu działać; im wyższa stawka, tym ciaśniej. Poniżej trzy typowe punkty na tej skali.

Projekt open-source (liberalne uprawnienia)

Dlaczego akurat projekt open-source może mieć luźne uprawnienia? Bo jego kod i tak jest publiczny, w repozytorium nie trzyma się sekretów ani danych produkcyjnych, a Claude nie ma stąd dostępu do żadnej wrażliwej infrastruktury. Najgorsze, co realnie może się zdarzyć, to lokalny bałagan w plikach — a nie wyciek danych czy awaria produkcji. Dlatego można dać modelowi więcej swobody i rzadziej go pytać:

// .claude/settings.json dla projektu open-source
{
  "permissions": {
    "allow": [
      "Read", "Write", "Edit",
      "Bash(git *)",
      "Bash(npm *)",
      "Bash(python *)",
      "Bash(make *)",
      "Bash(cargo *)",
      "Bash(go *)"
    ],
    "deny": [
      "Bash(git push --force *)",
      "Bash(rm -rf /)",
      "Bash(:(){ :|:& };:)"    // tzw. fork bomb — komenda zawieszająca system
    ]
  }
}

Projekt produkcyjny (konserwatywne uprawnienia)

// .claude/settings.json dla projektu z dostępem do prod infra
{
  "permissions": {
    "allow": [
      "Read",
      "Bash(git status)",
      "Bash(git log *)",
      "Bash(git diff *)",
      "Bash(python -m pytest *)",
      "Bash(python -m mypy *)"
    ],
    "deny": [
      "Bash(git push *)",          // push zawsze ręcznie
      "Bash(git commit *)",         // commit zawsze ręcznie
      "Bash(kubectl *)",            // k8s - nigdy automatycznie
      "Bash(terraform apply *)",
      "Bash(terraform destroy *)",
      "Bash(aws *)",
      "Bash(psql *prod*)",          // prod DB off-limits
      "Write"                       // zapis plików też wymaga OK
    ]
  },
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "*",
        "hooks": [
          {"type": "command", "command": ".claude/hooks/audit-all.sh"}
        ]
      }
    ]
  }
}

Środowisko CI/CD (headless — bez człowieka przy terminalu, pełny automat)

# GitHub Actions — Claude Code w CI
name: Claude Code Review
on: [pull_request]

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install Claude Code
        run: npm install -g @anthropic-ai/claude-code
      - name: Run Claude review
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          # --dangerously-skip-permissions BEZPIECZNE w izolowanym, jednorazowym runnerze
          claude --dangerously-skip-permissions -p \
            "Zrób code review diff'a w tym PR. Sprawdź typy, edge cases, bezpieczeństwo."

10. Dobre praktyki — gotowe zasady dla zespołu

Best practices uprawnień Claude Code
10 zasad systemu uprawnień — od minimalnych przywilejów po audyt i pracę w CI/CD
  1. Zasada minimalnych uprawnień — zaczynaj od pustej listy allow i dodawaj tylko to czego faktycznie potrzebujesz. Łatwiej rozluźniać niż naprawiać wyrządzone szkody.
  2. Commit .claude/settings.json do repo — zasady projektowe powinny być widoczne dla każdego w zespole i wersjonowane razem z kodem.
  3. Gitignore dla settings.local.json — osobiste nadpisania nie powinny trafiać do repo.
  4. Blokuj push force bezwzględnie"Bash(git push --force *)" i "Bash(git push -f *)" w deny na poziomie globalnym.
  5. Audyt log przez PreToolUse hook — nawet jeśli nie blokujesz, loguj wszystkie operacje bash. Bezcenne przy debugowaniu co Claude zrobił.
  6. Oddziel deny destrukcyjnych operacji infraterraform apply, kubectl delete, aws s3 rm zawsze wymagają ręcznego zatwierdzenia.
  7. PostToolUse = automatyczne sprawdzenie — uruchom linter i testy po każdym zapisie pliku (Write). Claude dostaje informację zwrotną i może od razu poprawić błędy.
  8. CI/CD: --dangerously-skip-permissions tylko na jednorazowej maszynie — środowisko, w którym uruchamiają się zadania CI (tzw. runner, np. w GitHub Actions), jest odizolowane i kasowane po każdym przebiegu, więc nic trwałego nie ucierpi. Twój laptop taki nie jest.
  9. Nie ufaj samemu sobie w hooku — sprawdzaj kody wyjścia, łap wyjątki, zapisuj błędy. Hook, który sam się wywali, przestaje chronić.
  10. Regularnie przeglądaj audit.log — raz w tygodniu przejrzyj, co Claude wykonał. Wychwycisz wzorce, których nie przewidziałeś.

Chcesz opanować Claude Code w praktyce?

Uprawnienia, hooks, MCP, sub-agenci i praca w CI/CD — trzy dni ćwiczeń z trenerem. Prowadzi Łukasz Matuszewski. Kurs ma termin gwarantowany.

Szkolenie Claude Code — od zera do zespołu agentów AI Szkolenie Claude Code — sprawdź terminy

Najczęściej zadawane pytania

Jak zablokować konkretne komendy bash w Claude Code?
W pliku .claude/settings.json dodaj sekcję permissions.deny z wpisami Bash(komenda *). Np. "Bash(rm -rf *)" zablokuje usuwanie rekurencyjne. Claude zostanie zapytany o potwierdzenie lub całkowicie zablokowany, zależnie od konfiguracji.
Czym różni się settings.json od settings.local.json?
settings.json w katalogu .claude/ powinien być commitowany do repozytorium — zawiera zasady dla całego zespołu. settings.local.json jest ignorowany przez git (dodaj do .gitignore) i służy do osobistych nadpisań, np. dodatkowych uprawnień dla siebie na lokalnej maszynie.
Co robi hook PreToolUse i kiedy go użyć?
PreToolUse to skrypt uruchamiany PRZED wykonaniem narzędzia przez Claude. Jeśli skrypt zwróci kod wyjścia niezerowy, operacja zostaje zablokowana. Idealny do audytu, walidacji bezpieczeństwa i dodatkowej warstwy autoryzacji ponad statyczną listą uprawnień.
Czy --dangerously-skip-permissions jest bezpieczne?
Flaga --dangerously-skip-permissions wyłącza wszystkie interaktywne zapytania o zgodę. Bezpieczna TYLKO w izolowanych środowiskach (Docker, VM, CI/CD bez dostępu do produkcji). Nigdy nie używaj jej na maszynie z dostępem do danych produkcyjnych lub wrażliwych kluczy API.
Jak działa hierarchia plików settings.json?
Claude Code ładuje ustawienia w kolejności: enterprise (zarządzane przez organizację) -> globalny (~/.claude/settings.json) -> projektowy (.claude/settings.json) -> lokalny (.claude/settings.local.json). Każdy poziom może rozszerzać lub nadpisywać poprzedni. Enterprise policies mają najwyższy priorytet i nie mogą być nadpisane przez użytkownika.

Komentarze (0)

Musisz być zalogowany by móc dodać komentarz. Zaloguj się przez Google

Brak komentarzy...