Przejdź do głównej zawartości

Automatyzacja zgodności regulacyjnej wykorzystuje agenta kodującego do mapowania kontroli SOC 2, HIPAA i RODO (GDPR) na kod, pisania bramek CI, które je egzekwują, oraz generowania skryptów zbierających dowody audytowe. Dowody wytwarzają deterministyczne narzędzia, a podpisuje je wskazany właściciel kontroli; agent pisze kolektory i szkice, ale nigdy nie wytwarza samych dowodów.

W poniedziałek przychodzi lista żądań od audytora: ustawienia ochrony gałęzi za cały okres obserwacji, dowód, że każda zmiana w src/auth/ przeszła code review, lista zależności produkcyjnych z licencjami i opis przepływu danych osobowych objętych RODO. Rok temu zajęło to dwóm inżynierom dwa tygodnie zrzutów ekranu i arkuszy. Ta strona jest dla programisty albo tech leada, który odpowiada za tę listę i chce, żeby następny audyt był ponownym uruchomieniem skryptów, a nie gaszeniem pożaru.

  • Prompt mapujący kontrolę, który zwraca tabelę luk z cytatami plik:linia, oraz krótki skrypt odrzucający każdy cytat, który nie istnieje.
  • Bramkę polityki licencji i bramkę sekretów, które blokują merge (albo własny commit agenta) i przy każdym uruchomieniu zostawiają datowany artefakt.
  • Kolektor zarządzania zmianą dla SOC 2 CC8.1, który czyta zatwierdzenia z GitHuba, a nie z git log.
  • Szkic rejestru przepływu danych RODO i kontrolę pokrycia żądań DSAR zbudowane na żywym schemacie bazy.
  • Zaplanowane zadanie, które co tydzień regeneruje dowody, oraz regułę podpisu określającą, kto za nie odpowiada.

Jeśli dopiero decydujesz, jakie dane w ogóle mogą trafić do agenta, zacznij od strony prywatność danych i polityki firmowe dla agentów kodujących. Jeśli pracujesz w finansach, ochronie zdrowia albo sektorze publicznym, przeczytaj o inżynierii agentowej w branżach regulowanych, gdzie omówiony jest podział obowiązków. Ta strona zakłada, że obie sprawy są już rozstrzygnięte.

Compliance-as-code zamienia każdą kontrolę w sprawdzenie uruchamiane przy każdej zmianie, więc dowody gromadzą się przy okazji dostarczania kodu. Agent szybko robi to, co jest żmudne do napisania, a błędy w tym łatwo przeoczyć. Właśnie dlatego nie może mieć ostatniego słowa.

WarstwaZadanie agentaCo to uruchamiaJaki dowód zostaje
Mapowanie kontroliSzkic tabeli luk z cytatamiTy, raz na kwartał dla każdej kontroliTabela luk (JSON) i log sprawdzenia cytatów
Hook agentaNapisanie konfiguracji hookaClaude Code, gdy agent uruchamia git commitKomunikat o blokadzie od skanera (tylko lokalnie)
Pre-commitNapisanie .pre-commit-config.yamlgit commit każdego programistyŻaden (tylko lokalnie), więc nigdy nie polegaj na nim samym
Bramka CINapisanie workflow i skryptów pomocniczychGitHub Actions przy każdym pull requeścieLog zadania i artefakt z każdego uruchomienia
Kolektor dowodówNapisanie skryptuZaplanowane zadanie, deterministycznieDatowany JSON z API systemu źródłowego
NarracjaSzkic tekstu i diagramów na podstawie JSONTy recenzujesz, właściciel kontroli podpisujePodpisany dokument cytujący JSON

Czytaj tabelę od góry do dołu jako kolejność budowania. Narracja bez kolektorów pod spodem to opowieść, a nie dowód.

Zacznij od jednej kontroli, nie od całego frameworka. SOC 2 CC6.1 (dostęp logiczny) to dobry pierwszy wybór, bo większość dowodów już leży w repozytorium: middleware uwierzytelniania, sprawdzenia autoryzacji, polityki IAM w Terraformie i obsługa sekretów.

Zapisz ten prompt jako .compliance/prompts/cc6.1.md.

Cała wartość tkwi w regule „Met tylko z cytatem”. Prompt o zgodność to miejsce, w którym model najchętniej zwraca schludną odpowiedź „wszystko spełnione”. Wymóg cytatów zamienia taką odpowiedź w coś, co może sprawdzić skrypt.

Uruchom go w trybie headless (nieinteraktywnie) i tylko do odczytu. --allowedTools jedynie automatycznie zatwierdza wymienione narzędzia, ale nie usuwa pozostałych. --tools usuwa z sesji wszystkie inne wbudowane narzędzia, więc nie zostaje żadne, które mogłoby pytać o zgodę. --strict-mcp-config nie wpuszcza do sesji skonfigurowanych serwerów MCP. --json-schema razem z --output-format json sprawdza odpowiedź względem schematu z karty Codex (zapisz go jako .compliance/gap.schema.json) i zwraca ją w polu structured_output (wszystko sprawdzone w Claude Code 2.1.283).

Okno terminala
mkdir -p evidence
claude -p "$(cat .compliance/prompts/cc6.1.md)" \
--tools "Read,Grep,Glob" --allowedTools "Read,Grep,Glob" \
--strict-mcp-config \
--output-format json --json-schema "$(cat .compliance/gap.schema.json)" \
| jq -e '.structured_output' > evidence/cc6.1-gap.json # exits 1 if no validated object

Teraz sprawdź każdy cytat mechanicznie, zamiast czytać tabelę. Zapisz to jako scripts/compliance/check-citations.sh i uruchamiaj z katalogu głównego repozytorium. Skrypt wymaga basha, bo czyta z podstawienia procesu; potok jq … | while ustawiałby broken w podpowłoce i zawsze kończył się kodem 0.

#!/usr/bin/env bash
# scripts/compliance/check-citations.sh <file.json> [jq filter]
# Exits 1 on any citation that is not an existing file plus one line number.
filter="${2:-.requirements[] | select(.status==\"Met\") | .evidence[]}"
jq empty "$1" || exit 1
# The loop only sees citations that exist, so reject a "Met" row with none first.
if [ -z "$2" ]; then
jq -e 'all(.requirements[]; .status != "Met" or (.evidence | length > 0))' "$1" >/dev/null \
|| { echo 'MET WITHOUT CITATION'; exit 1; }
fi
broken=0
while IFS=: read -r file line; do
case "$line" in
''|*[!0-9]*) echo "BROKEN CITATION (no single line number): $file:$line"; broken=1; continue ;;
esac
if [ ! -f "$file" ] || [ "$line" -lt 1 ] || [ "$line" -gt "$(awk 'END{print NR}' "$file")" ]; then
echo "BROKEN CITATION: $file:$line"; broken=1
fi
done < <(jq -r "$filter" "$1")
exit "$broken"

Zanim mu zaufasz, dopisz do kopii JSON-a jeden fałszywy cytat (src/nope.ts:1) i potwierdź, że skrypt wypisuje BROKEN CITATION i kończy się kodem 1. Cytat bez pojedynczego numeru linii, na przykład file.ts albo file.ts:42-50, również nie przechodzi, podobnie jak wiersz „Met” z pustą tablicą evidence (MET WITHOUT CITATION). Liczbę linii podaje awk, a nie wc -l, bo wc -l liczy znaki nowej linii i odrzuciłby cytat ostatniej linii pliku, który nie kończy się znakiem nowej linii.

Jeden błędny cytat oznacza, że cała tabela jest niewiarygodna: wyrzuć ją i uruchom ponownie, nie poprawiaj pojedynczego wiersza. Gdy wszystkie cytaty się zgadzają, otwórz trzy losowe wiersze „Met” i sprawdź, czy wskazana linia rzeczywiście realizuje wymaganie. Twoim przeglądem jest ta próbka, a nie lektura całości.

Podłącz bramki, które zostawiają dowód przy każdym uruchomieniu

Dział zatytułowany „Podłącz bramki, które zostawiają dowód przy każdym uruchomieniu”

Bramka jest lepszym dowodem niż raport, bo działa przy każdej zmianie przez cały okres obserwacji. Najszybciej zwracają się dwie: licencje zależności i sekrety. Skanowanie sekretów gitleaks, Semgrep i Trivy opisuje szczegółowo strona o automatyzacji operacji bezpieczeństwa; ta sekcja dodaje bramkę licencji i sprawia, że obie zostawiają artefakty, z których audytor może pobrać próbkę.

Wynik powinien wyglądać tak. Porównaj go z promptem, zamiast mu ufać:

name: license-policy
on:
pull_request:
permissions:
contents: read
jobs:
licenses:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: actions/setup-node@v7
with:
node-version: 22
- run: npm ci --ignore-scripts
- name: Write the license report (always)
run: >
npx --yes license-checker-rseidelsohn@5 --production --excludePrivatePackages
--json --out license-report.json
- name: Enforce the allowlist (the gate)
run: >
npx --yes license-checker-rseidelsohn@5 --production --excludePrivatePackages
--onlyAllow "MIT;Apache-2.0;BSD-2-Clause;BSD-3-Clause;ISC;0BSD"
- if: always()
uses: actions/upload-artifact@v7
with:
name: license-report
path: license-report.json
retention-days: 90

Używaj listy dozwolonych licencji (--onlyAllow), a nie listy zakazanych (--failOn). Lista zakazanych z GPL-3.0 przepuści GPL-3.0-only, GPL-3.0-or-later i każdy ciąg licencji wpisany ręcznie przez opiekuna pakietu. Lista dozwolonych odrzuca wszystko nieznane, a to bezpieczny kierunek: decyzję podejmuje wtedy człowiek i zapisuje wyjątek.

Raport i bramka to osobne kroki, bo --onlyAllow kończy działanie przy pierwszej niedozwolonej licencji, więc jeden połączony krok może w ogóle nie zapisać license-report.json, a audytor pobiera próbki właśnie z nieudanych uruchomień. Ustaw bramkę jako wymaganą w ochronie gałęzi, a zanim zaczniesz na niej polegać, udowodnij, że działa: otwórz testowy pull request dodający jeden pakiet spoza listy i potwierdź, że sprawdzenie zmienia się na czerwone.

CI łapie naruszenie po wypchnięciu. Hook łapie je, zanim w ogóle powstanie. Warstwy różnią się między narzędziami, więc skonfiguruj tę, której używa twój zespół, a wspólną konfigurację pre-commit utrzymuj dla wszystkich.

Hook PreToolUse z warunkiem if uruchamia się tylko wtedy, gdy agent próbuje wykonać git commit. Dodaj go do .claude/settings.json:

{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"if": "Bash(git commit *)",
"command": "gitleaks git --staged --redact --exit-code 2"
}
]
}
]
}
}

--exit-code 2 jest tu kluczowe. Claude Code blokuje wywołanie narzędzia tylko przy kodzie wyjścia 2. gitleaks po znalezieniu wycieku domyślnie kończy się kodem 1, który Claude Code traktuje jako błąd nieblokujący, więc commit by przeszedł.

Najpierw zainstaluj gitleaks na każdej maszynie: brakujący plik wykonywalny kończy się kodem 127, który niczego nie blokuje. Hook skanuje to, co jest w poczekalni (staged) przed uruchomieniem polecenia, więc git add -A && git commit w jednym wywołaniu go omija; dlatego kontrolą pozostaje bramka CI.

Wzorzec pasuje tylko do zapisu, który wymienia, więc git -C . commit przez niego przejdzie, a dokumentacja hooków nazywa filtr if rozwiązaniem typu best-effort; traktuj ten hook jako wczesne ostrzeżenie. Kontrolą pozostaje wymagana bramka CI.

Wspólną warstwą dla każdego autora zmian, człowieka czy agenta, jest .pre-commit-config.yaml:

repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.30.1
hooks:
- id: gitleaks

W każdym klonie uruchom raz pre-commit install. Hooki pre-commit trzeba włączyć w każdym klonie, a każdy może je pominąć przez --no-verify. Zmniejszają szum w CI, ale nie są kontrolą. Kontrolą jest bramka CI i tylko jej uruchomienia możesz pokazać audytorowi.

Zbieraj ścieżkę audytową zarządzania zmianą z GitHuba, a nie z git log

Dział zatytułowany „Zbieraj ścieżkę audytową zarządzania zmianą z GitHuba, a nie z git log”

SOC 2 CC8.1 pyta, czy zmiany były autoryzowane, zrecenzowane i przetestowane. git log na to nie odpowie: nie zapisuje, kto zatwierdził pull request, czy recenzja została unieważniona (dismissed) ani czy wymagane sprawdzenia przeszły. Te dane są w GitHubie. Daj agentowi dostęp tylko do odczytu przez serwer GitHub MCP, korzystając z endpointu /readonly, dzięki czemu żadne narzędzie zapisujące nie jest nawet oferowane.

Okno terminala
claude mcp add --transport http github-ro https://api.githubcopilot.com/mcp/readonly \
-H "Authorization: Bearer $GITHUB_PAT"

Powłoka rozwija $GITHUB_PAT, zanim Claude Code go zobaczy, więc token trafia jawnym tekstem do konfiguracji MCP Claude Code. Użyj tokena krótkotrwałego albo umieść serwer w .mcp.json z "Authorization": "Bearer ${GITHUB_PAT}", które Claude Code rozwija ze zmiennych środowiskowych przy starcie; dokładny JSON jest na stronie o GitHub MCP. W obu przypadkach użyj tokena fine-grained ograniczonego do audytowanych repozytoriów, z uprawnieniami tylko do odczytu. Po podłączeniu serwera ten sam prompt działa we wszystkich trzech narzędziach.

Raport to szkic dla człowieka. Dowodem, który zachowuje audytor, są surowe dane, a te powinny pochodzić ze skryptu, który uruchomisz ponownie rano w dniu audytu, a nie z transkryptu czatu. Poproś agenta, żeby napisał ten skrypt raz:

Zrecenzuj kolektor jak każdy skrypt istotny dla bezpieczeństwa: sprawdź, czy każda ścieżka gh api istnieje, czy nic nie loguje tokena i czy warunek wyjścia odpowiada twojej polityce. Potem uruchom go raz i porównaj JSON ze stroną ochrony gałęzi w interfejsie GitHuba. Odczyt ochrony gałęzi wymaga tokena z uprawnieniem administration read do repozytorium i to najczęstsza przyczyna pierwszego niepowodzenia.

Przygotuj rejestr przepływu danych RODO i pokrycie DSAR z żywego schematu

Dział zatytułowany „Przygotuj rejestr przepływu danych RODO i pokrycie DSAR z żywego schematu”

Art. 30 RODO wymaga rejestru czynności przetwarzania, a art. 15 i 17 dają osobom, których dane dotyczą, prawo dostępu do danych i ich usunięcia. Jedno i drugie psuje się po cichu, gdy pojawia się nowa tabela albo nowe SDK zewnętrznego dostawcy. Agent prześledzi pola z danymi osobowymi w kodzie szybciej niż ty grepem, pod warunkiem że czyta prawdziwy schemat i oznacza to, czego nie potrafi prześledzić.

Podłącz serwer MCP bazy danych z rolą bazodanową tylko do odczytu (opcje opisuje strona o serwerach MCP dla baz danych). Nie używaj zarchiwizowanego pakietu referencyjnego @modelcontextprotocol/server-postgres: jego wpis w npm jest oznaczony jako deprecated (sprawdzone 2026-09-26).

W przypadku HIPAA uruchom ten sam prompt dla chronionych informacji zdrowotnych (PHI) zamiast danych osobowych i dodaj do każdego przepływu jedno pytanie: czy dostęp jest logowany z użytkownikiem i czasem? To wiąże każdy przepływ z zabezpieczeniami kontroli audytu (audit controls) i kontroli dostępu (access control) z 45 CFR 164.312.

Znacznik NEEDS REVIEW to zawór bezpieczeństwa: wskazuje dokładnie to, co inspektor ochrony danych musi domknąć ręcznie. Następnie zamień tę samą analizę w stałe sprawdzenie, bo handler DSAR, który pomija jeden magazyn danych, nie realizuje żądania dostępu i nie zgłasza przy tym żadnego błędu:

Uruchamiaj go według harmonogramu i zapisuj odpowiedź jako evidence/dsar.json. Pierwsze polecenie oznacza zadanie jako nieudane, gdy którakolwiek wartość export lub erasure wynosi null albo gdy tablica jest pusta, bo all na pustym zbiorze zwraca prawdę; drugie przekazuje skryptowi cytatów filtr dopasowany do kształtu DSAR, bo domyślny czyta .requirements[] i nie znalazłby niczego do sprawdzenia:

Okno terminala
jq -e 'length > 0 and all(.[]; .export != null and .erasure != null)' evidence/dsar.json
scripts/compliance/check-citations.sh evidence/dsar.json \
'.[] | .export, .erasure | select(. != null)'

Ścieżka usuwania jest destrukcyjna, więc trafia do kodu wyłącznie przez zrecenzowany pull request z testami na bazie z danymi testowymi, nigdy prosto z sesji agenta.

Ciągłe dowody oznaczają, że kolektory działają według kalendarza, a nie w tygodniu przed audytem. Zaplanowany workflow uruchamia się z gałęzi domyślnej, więc wykonuje tylko zrecenzowany kod. Ręczne uruchomienie przez workflow_dispatch już nie: każdy z prawem zapisu może je wywołać z dowolnej gałęzi i dostałoby ono oba sekrety. Warunek if na poziomie zadania ogranicza także ręczne uruchomienia do gałęzi domyślnej; zastąp main nazwą swojej. Ręczne uruchomienie czyta jednak plik workflow z gałęzi, z której je wywołano, więc ta gałąź może ten if usunąć, a gałąź, która doda wyzwalacz push, też dostanie sekrety repozytorium. Twardą gwarancję daje dopiero umieszczenie obu sekretów w środowisku (environment), którego gałęzie wdrożeń są ograniczone do domyślnej, i dodanie do zadania environment: z jego nazwą. Krok agenta zostaw tylko do odczytu i pozwól, żeby dowód wytwarzał deterministyczny kolektor, który agent jedynie streszcza.

CLI agenta jest przypięte do konkretnej wersji (2.1.283, kanał latest 26.09.2026), więc każde cotygodniowe uruchomienie korzysta z tego samego, zrecenzowanego pliku binarnego; podbijaj ją w pull requeście, jak każdą inną zależność.

name: weekly-compliance-evidence
on:
schedule:
- cron: '17 6 * * 1'
workflow_dispatch:
permissions:
contents: read
jobs:
evidence:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- name: Collect raw evidence (deterministic)
env:
GH_TOKEN: ${{ secrets.EVIDENCE_READ_TOKEN }}
run: node scripts/compliance/evidence-collect.mjs
- name: Draft the weekly summary (read-only agent)
if: always()
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
npx --yes @anthropic-ai/claude-code@2.1.283 -p \
"Read evidence/change-management-*.json. Summarize CC8.1 exceptions: PRs without approval, disabled protections, failed required checks. Cite the PR number for every exception. Do not restate anything that is not in the JSON." \
--tools "Read,Glob" --allowedTools "Read,Glob" --strict-mcp-config \
> evidence/cc8.1-summary.md
- if: always()
uses: actions/upload-artifact@v7
with:
name: compliance-evidence
path: evidence/
retention-days: 90

Kroki streszczenia i wysyłki artefaktu mają if: always(), bo kolektor kończy się kodem 1, gdy znajdzie wyjątek. Bez tego warunku nieudany kolektor pomija oba kroki, więc uruchomienia, które rejestrują wyjątek, a to właśnie je audytor bierze do próbki, nie zostawiłyby żadnego artefaktu.

Artefakty Actions wygasają zgodnie z ustawieniem retencji, które zwykle jest krótsze niż okres obserwacji. Kopiuj folder evidence/ z każdego uruchomienia do magazynu, do którego audytor ma dostęp, a którego nikt nie może nadpisać, na przykład do bucketu z object lock. Telemetrię agentów przechowuj przez ten sam okres: strona o obserwowalności agentów opisuje logi audytowe tego, co robił sam agent.

Skąd wiesz, że dowody są poprawne, bez czytania całości?

Dział zatytułowany „Skąd wiesz, że dowody są poprawne, bez czytania całości?”

Pipeline weryfikujesz raz, a wynik sprawdzasz próbkowaniem. Każde sprawdzenie poniżej łapie konkretny błąd i żadne nie wymaga czytania całego raportu.

SprawdzenieCo łapieKiedy
jq empty na każdym wyniku JSONTekst albo ucięcie wokół danychPrzy każdym uruchomieniu
Skrypt sprawdzający cytatyWymyślone pliki i numery liniiPrzy każdym uruchomieniu
Trzy losowe wiersze „Met” otwarte ręczniePrawdziwy plik, zła treśćCo kwartał, dla każdej kontroli
Podrzucone naruszenie (zła licencja, fałszywy klucz, fałszywy cytat, wiersz „Met” z pustym evidence; każde musi dać kod 1)Bramka, która nigdy nie zadziałaPo każdej zmianie bramki
Diff z JSON z poprzedniego kwartałuCichy spadek pokryciaCo kwartał
Wynik kolektora porównany z interfejsem GitHubaZły endpoint API albo uprawnieniaRaz, potem po zmianach
Podpis właściciela kontroli pod narracjąBrak osoby odpowiedzialnej za twierdzeniePrzy każdym audycie

Reguła podpisu nie jest opcjonalna. Za każdą kontrolę odpowiada wskazany z imienia i nazwiska właściciel: agent pisze szkic, właściciel podpisuje. Dokładnie tę granicę postawi też twój audytor.

Agent oznacza kontrolę jako „Met” bez prawdziwego dowodu. Objaw: sprawdzenie cytatów wypisuje BROKEN CITATION albo MET WITHOUT CITATION. Wyjście: wyrzuć całą tabelę, zaostrz prompt („jeśli nie możesz zacytować linii, status to Partial”) i uruchom ponownie. Tabeli z jednym wymyślonym cytatem nie da się ufać wiersz po wierszu.

Hook nigdy nie blokuje. Objaw: agent commituje dodany testowy klucz i nic się nie dzieje. Przyczyna: skaner kończy się kodem 1, a Claude Code blokuje tylko przy kodzie 2. Wyjście: dodaj --exit-code 2 i powtórz test z podrzuconym kluczem.

Bramka licencji przepuszcza pakiet copyleft. Przyczyna: lista zakazanych, na której brakuje dokładnego wariantu SPDX, albo pakiet z ręcznie wpisanym ciągiem licencji. Wyjście: przejdź na --onlyAllow, zapisuj każdy wyjątek w repozytorium z nazwiskiem recenzenta i przeglądaj listę wyjątków co kwartał.

Kolektor zgłasza brak ochrony gałęzi. Przyczyna: token nie ma uprawnienia administration read; API odpowiada wtedy 404, co naiwny skrypt odczytuje jako „brak ochrony”. Wyjście: popraw zakres tokena, uruchom ponownie i porównaj z interfejsem, zanim uwierzysz w jakikolwiek wynik „brak”.

Ścieżka audytowa ma dziury. Przyczyna: ktoś z uprawnieniami administratora wypchnął zmiany prosto na main albo obszedł ochronę. Wyjście: włącz „Do not allow bypassing the above settings” (albo odpowiednik w rulesetach), a lukę opisz w raporcie zamiast ją ukrywać. Audytorzy znacznie lepiej traktują ujawniony i wyjaśniony wyjątek niż taki, który sami odkryją.

Wygenerowany dokument ujawnia prawdziwy sekret albo dane osobowe. Przyczyna: agent zacytował wartości wierszy albo konfigurację. Wyjście: każdy prompt na tej stronie prosi o nazwy, a nie wartości; trzymaj się tej zasady, skanuj evidence/ gitleaksem przed wysłaniem i rotuj wszystko, co wyciekło.

Tekst polityki i automatyzacja się rozjeżdżają. Objaw: polityka mówi, że poświadczenia są rotowane co 90 dni, a zadanie rotacji działa co 180. Wyjście: niech kolektor porównuje skonfigurowany harmonogram z polityką na piśmie i kończy się błędem przy niezgodności, zamiast powtarzać treść polityki.

Przepisy zmieniają się pod regułami. Wyjście: nadaj każdej regule identyfikator kontroli i datę przeglądu w nagłówku, a w kalendarzu właściciela kontroli umieść kwartalne zadanie przeglądu reguł względem aktualnego tekstu. O unijnych regulacjach, które obejmują już zespoły tworzące oprogramowanie, przeczytasz na stronie o CRA, NIS2 i DORA-EU.