Przejdź do głównej zawartości

Receptury pipeline’ów CI/CD dla agentów AI to gotowe prompty i przejrzany YAML, dzięki którym Claude Code, Codex lub Cursor generują pipeline’y GitHub Actions, GitLab CI albo Jenkins z bramkami, które potrafią zablokować zmianę: testy z prawdziwych skryptów repozytorium, skan obrazu przed pushem, akcje przypięte do commitów i deploy czekający na zatwierdzenie przez człowieka.

Twój deploy przeszedł wszystkie checki w CI, a mimo to wypuścił krytyczne CVE. Testy były zielone, obraz się zbudował, ale krok skanowania tylko wgrywał raport, więc nic w pipeline’ie nie mogło powiedzieć „nie”. Agent, który napisał workflow, zrobił dokładnie to, o co go poproszono. Nikt nie poprosił go o bramkę, która potrafi zatrzymać zmianę.

Ta strona jest dla developera albo tech leada, który odpowiada za pipeline serwisu i chce, żeby pisał go agent. Receptury poniżej generują YAML, a potem udowadniają, że każda bramka potrafi zrobić się czerwona, więc ufasz pipeline’owi bez ponownego czytania 200 linii.

  • Prompt, który z package.json i Dockerfile robi workflow GitHub Actions z matrycą wersji Node, skanem Trivy uruchamianym przed pushem i jobem wdrożeniowym za GitHub Environment.
  • Ćwiczenie bramek: actionlint, zizmor i jednorazowe pull requesty, które muszą zrobić się czerwone, więc wiesz, że każda bramka blokuje, zamiast to zakładać.
  • Prompt, który zamienia log nieudanego uruchomienia w jedną przyczynę źródłową i jedną poprawkę.
  • Krok AI review dla pull requestów zmieniających pipeline w Claude Code, Codex albo Cursorze, skonfigurowany z najmniejszymi uprawnieniami.
  • Tryby awarii, na które wygenerowane pipeline’y trafiają najpierw, razem ze sposobem wyjścia z każdego.

Szersze techniki pipeline’owe (buildy świadome zmian, kwarantanna niestabilnych testów, progresywne rollouty) opisuje automatyzacja pipeline’ów z AI. Ta strona zajmuje się wyłącznie generowaniem i utwardzaniem samego pliku pipeline’u.

Jak sprawić, żeby agent wygenerował pipeline pasujący do twojego repozytorium?

Dział zatytułowany „Jak sprawić, żeby agent wygenerował pipeline pasujący do twojego repozytorium?”

Goły prompt „stwórz pipeline CI/CD” daje wiarygodnie wyglądający workflow dla projektu, którego nie masz: zły menedżer pakietów, wymyślony npm run test:ci, wersja Node, której nigdy nie używałeś. Zakotwicz agenta w plikach, które już istnieją, i opisz bramki przez to, co ma je wywrócić.

W katalogu głównym repozytorium uruchom claude. Claude Code sam czyta package.json, Dockerfile i istniejące .github/workflows/*, więc niczego nie wklejasz. Żeby przejrzeć plan, zanim zmieni się jakikolwiek plik, zacznij w trybie planowania:

Okno terminala
claude --permission-mode plan

Wklej prompt poniżej. Gdy plan wymieni skrypty znalezione w package.json, zatwierdź go i pozwól Claude Code zapisać plik.

Dobry wynik ma taki kształt. Fragment pokazuje tagi dla czytelności; wynik agenta zawiera SHA:

# .github/workflows/ci.yml (excerpt)
name: CI
on:
push: { branches: [main] }
pull_request:
release: { types: [published] }
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix: { node: [22, 24] }
steps:
- uses: actions/checkout@v7
with: { persist-credentials: false }
- uses: actions/setup-node@v7
with:
node-version: ${{ matrix.node }}
cache: npm
- run: npm ci
- run: npm test # the script that exists in package.json
image:
needs: test
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
env:
IMAGE: ghcr.io/acme/billing-api:${{ github.sha }} # GHCR names must be lowercase
steps:
- uses: actions/checkout@v7
with: { persist-credentials: false }
- uses: docker/setup-buildx-action@v4
- name: Build (loaded locally, not pushed)
uses: docker/build-push-action@v7
with:
load: true
tags: ${{ env.IMAGE }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Scan - fails the job on fixable CRITICAL/HIGH
uses: aquasecurity/trivy-action@v0.36.0
with:
image-ref: ${{ env.IMAGE }}
severity: CRITICAL,HIGH
ignore-unfixed: true
exit-code: '1'
- if: github.event_name != 'pull_request'
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Push only what passed the scan
if: github.event_name != 'pull_request'
run: docker push "$IMAGE"
deploy-prod:
needs: image
if: github.event_name == 'release'
runs-on: ubuntu-latest
environment: production # required reviewers on this environment = the human sign-off
permissions:
contents: read
id-token: write # OIDC to the cloud, no stored cloud keys
steps:
- uses: actions/checkout@v7
with: { persist-credentials: false }
# TODO: cloud login via OIDC, then the rollout

Bezpieczeństwo trzymają trzy linie, więc to je sprawdzasz najpierw:

  • exit-code: '1' zamienia skan z raportu w bramkę. Bez tego Trivy wypisuje znaleziska, a job zostaje zielony.
  • load: true przed skanem i docker push po nim sprawiają, że podatny obraz nigdy nie trafia do rejestru. Skan po push: true blokuje deploy, ale zły obraz jest już opublikowany.
  • environment: production nic nie robi, dopóki nie dodasz do tego środowiska wymaganych recenzentów w ustawieniach repozytorium. YAML nazywa bramkę, ustawienie ją egzekwuje.

O Dockerfile, który buduje pipeline, piszemy we wzorcach Docker i kontenerów. Rollout, który uruchamia job wdrożeniowy, opisują wzorce orkiestracji Kubernetes oraz progressive delivery zmian pisanych przez agentów.

Jak udowodnić, że bramki pipeline’u naprawdę blokują?

Dział zatytułowany „Jak udowodnić, że bramki pipeline’u naprawdę blokują?”

Wygenerowany pipeline, który nigdy nie był czerwony, jest pipeline’em nieprzetestowanym. Zamiast czytać każdą linię, uruchom dwa statyczne checkery i jedno ćwiczenie, które celowo wywraca każdą bramkę. Z testami jest tak samo: bramka, która nie potrafi zawieść, jest gorsza niż brak bramki, bo daje zielony check bez żadnego bezpieczeństwa.

  1. Sprawdź składnię i wyrażenia workflow. actionlint wyłapuje nieprawidłowe klucze, zepsute wyrażenia ${{ }} i błędy powłoki w blokach run:. Zainstaluj go przez brew install actionlint albo go install github.com/rhysd/actionlint/cmd/actionlint@latest i uruchom actionlint w katalogu głównym repozytorium.

  2. Przeprowadź audyt bezpieczeństwa workflow. zizmor (PyPI zizmor 1.30.1, sprawdzone 2026-09-26) zgłasza template-injection, excessive-permissions, unpinned-uses, cache-poisoning i artipacked (poświadczenia checkoutu zostawione na dysku). Uruchom uvx zizmor .github/workflows/. Od wersji 1.20.0 domyślna polityka wymaga przypięcia każdej akcji przez SHA, także actions/*, więc workflow przypięty tagami nie przejdzie tego kroku, dopóki agent nie rozwiąże SHA.

  3. Przeprowadź ćwiczenie bramek. Niech agent otworzy szkicowe pull requesty z jednorazowych gałęzi, z których każda niesie dokładnie jedną celową awarię (prompt poniżej). Trzymaj awarie na osobnych gałęziach: image zależy od test, więc padający test na tej samej gałęzi pominąłby skan i niczego by o nim nie udowodnił. Każda bramka musi zrobić się czerwona na swojej gałęzi, a deploy-prod nie może wystartować.

  4. Spraw, żeby bramki były wiążące. W ochronie gałęzi albo w zestawie reguł (ruleset) dla main oznacz test i image jako wymagane status checki i dodaj wymaganych recenzentów do środowiska production. Do tego czasu czerwony check jest tylko radą: każdy z prawem merge’a może go obejść. Wymagane checki nadal uruchamiają plik workflow z samego pull requesta, więc pull request może usunąć krok skanowania i pozostać zielony; obejmij /.github/ regułą CODEOWNERS i włącz w tym samym zestawie reguł wymaganą recenzję właścicieli kodu.

  5. Zapisz, kto zatwierdza. Wymagani recenzenci środowiska production to osoby z uprawnieniami produkcyjnymi. Agent pisze i naprawia pipeline, a każdy deploy produkcyjny zatwierdza wskazany z nazwiska człowiek. Zobacz akceptację produkcji jako granicę systemu.

Gdy ćwiczenie się skończy, porównaj faktycznie czerwone checki z listą agenta. Bramka, która została zielona na swojej gałęzi, to znalezisko, a nie przypadkowa, niestabilna awaria. Zamknij szkicowe pull requesty i usuń gałęzie, gdy każda bramka zawiodła tam, gdzie powinna.

Jak zdiagnozować czerwone uruchomienie bez przewijania logu?

Dział zatytułowany „Jak zdiagnozować czerwone uruchomienie bez przewijania logu?”

Najdroższa część CI to uruchomienie, które pada 400 linii w głąb logu, bo npm ci zwróciło 1. Pobierz przez GitHub CLI tylko nieudane kroki i daj agentowi log razem z definicją joba:

Okno terminala
gh run view RUN_ID --log-failed > failed.log

RUN_ID to numer z adresu URL uruchomienia. Workflow jest identyczny we wszystkich trzech narzędziach: w Claude Code i Codex podajesz w prompcie ścieżkę failed.log, w Cursorze dołączasz plik przez @failed.log.

Żeby agent sam czytał uruchomienia, zarejestruj zestaw narzędzi Actions serwera GitHub MCP w trybie tylko do odczytu, z drobnoziarnistym tokenem dostępu tylko do odczytu w zmiennej GITHUB_PAT:

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

Powłoka rozwija $GITHUB_PAT jednorazowo, a Claude Code zapisuje otrzymaną wartość w swojej konfiguracji, więc użyj tokenu ograniczonego do odczytu Actions.

Więcej o zestawach narzędzi serwera i trybie lockdown znajdziesz na stronie serwera GitHub MCP.

Pytanie „dlaczego w CI tak, a lokalnie nie” kieruje model ku przyczynom środowiskowym: kluczowi cache, który przywraca zależności zbudowane dla innej wersji Node, lockfile’owi rozjechanemu z package.json, brakującemu kontenerowi usługi albo tokenowi bez uprawnienia, którego potrzebuje krok. Punkt 4 to weryfikacja: poprawka jest skończona, gdy ten check zrobi się zielony, a nie gdy wyjaśnienie brzmi przekonująco.

Pętla „wygeneruj, potem przećwicz” jest ta sama; zmienia się tylko plik docelowy i składnia bramek. W promptach zamień .github/workflows/ci.yml na .gitlab-ci.yml albo deklaratywny Jenkinsfile i dopisz uwagi dla platformy:

  • GitLab CI: poproś o utrzymywane przez GitLab szablony include: - template: Jobs/SAST.gitlab-ci.yml i Jobs/Container-Scanning.gitlab-ci.yml zamiast ręcznie pisanych jobów skanera. Starsze ścieżki Security/ to już tylko przekierowania (Container Scanning przeniesiono w GitLab 15.6), a wygenerowane pipeline’y często wciąż je emitują. Przypinaj obrazy jobów do prawdziwego tagu, np. node:22-alpine, i kluczuj cache lockfile’em przez cache: key: files: [package-lock.json].
  • Jenkins: poproś o deklaratywny Jenkinsfile z agentami Docker i równoległymi (parallel) etapami jakości oraz etap SonarQube, który wywołuje withSonarQubeEnv, a po nim waitForQualityGate abortPipeline: true. Bez abortPipeline: true nieudany quality gate zostaje tylko zaraportowany, a pipeline jedzie dalej.

Jak dodać krok AI review do pull requestów zmieniających pipeline?

Dział zatytułowany „Jak dodać krok AI review do pull requestów zmieniających pipeline?”

Recenzent AI przy zmianach pipeline’u łapie to, czego nie złapią checkery: zbyt szeroki warunek wdrożenia, uprawnienie poszerzone „tymczasowo”, skan przeniesiony za push. Jego głos jest doradczy. Bramkami pozostają wymagane checki i zatwierdzenie środowiska, a komentarz z review nigdy ich nie zastępuje.

Uruchom /install-github-app w claude, żeby zainstalować aplikację Claude GitHub i zapisać ANTHROPIC_API_KEY jako sekret repozytorium, a potem dodaj workflow review ograniczony do plików pipeline’u:

.github/workflows/claude-pipeline-review.yml
name: Claude pipeline review
on:
pull_request:
types: [opened, synchronize]
paths: ['.github/workflows/**', 'Dockerfile', '.gitlab-ci.yml', 'Jenkinsfile']
permissions:
contents: read
pull-requests: write
id-token: write # the action swaps an OIDC token for the Claude GitHub App token
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with: { persist-credentials: false, fetch-depth: 1 }
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
prompt: |
REPO: ${{ github.repository }}
PR NUMBER: ${{ github.event.pull_request.number }}
Review only the CI/CD changes in this pull request. Flag: gates
that can no longer fail, widened permissions, unpinned actions,
event data used inside run: scripts, secrets exposed to pull
request code, and deploy conditions broader than releases.
Comment inline on the exact line. Do not suggest style changes.
claude_args: '--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr diff:*),Bash(gh pr view:*)"'

id-token: write jest wymagane przy domyślnym uwierzytelnianiu przez aplikację GitHub: bez niego akcja nie dostanie tokenu OIDC, który wymienia na token aplikacji, i job kończy się błędem, zanim cokolwiek zrecenzuje. Jeśli nie chcesz używać aplikacji, przekaż zamiast tego github_token: ${{ secrets.GITHUB_TOKEN }}, a komentarze będą wtedy pochodzić od github-actions[bot]. --allowedTools ogranicza recenzenta do czytania diffu i dodawania komentarzy inline. Przy pull requestach akcja przywraca .claude/, .mcp.json i CLAUDE.md z gałęzi bazowej, zanim wystartuje Claude, więc pull request nie podmieni własnych hooków ani serwerów MCP. Akcja konfiguruje własne poświadczenia gita przed tym pobraniem, więc persist-credentials: false w checkoucie nie psuje przywracania (kod źródłowy claude-code-action, sprawdzone 2026-09-26). To przywracanie chroni konfigurację agenta, nie sam workflow: przy pull_request GitHub uruchamia YAML z pull requesta, a filtr paths obejmuje .github/workflows/**, więc każdy, kto może wypchnąć gałąź do tego repozytorium, może poszerzyć --allowedTools we własnej kopii joba, a ta kopia uruchomi się z ANTHROPIC_API_KEY, zanim ktokolwiek ją przejrzy. CODEOWNERS na /.github/ z wymaganą recenzją blokuje scalenie takiej zmiany, a nie jej uruchomienie, więc prawo push dawaj tylko zaufanym osobom, a recenzję AI traktuj jako doradczą.

  1. Cache się przywraca, a build i tak się psuje albo kompiluje wszystko od nowa. Klucz nie zawiera hasha lockfile’a albo wersji Node, więc node_modules zbudowane dla jednej wersji Node wraca pod inną. Użyj actions/setup-node z cache: npm, które cache’uje pobrane paczki npm, a nie node_modules. Jeśli potrzebujesz actions/cache, kluczuj go przez ${{ runner.os }}-node${{ matrix.node }}-${{ hashFiles('**/package-lock.json') }}.

  2. Push do GHCR pada z „repository name must be lowercase”. ${{ github.repository }} zachowuje wielkość liter nazwy właściciela. Zamień nazwę na małe litery we wcześniejszym kroku albo wpisz ją małymi literami, jak w szkielecie powyżej, i uruchom ponownie.

  3. Deploy przez OIDC pada z „Not authorized to perform sts:AssumeRoleWithWebIdentity”. YAML zwykle jest w porządku; to polityka zaufania w chmurze nie pasuje do tokenu. Job z environment: production wysyła subject repo:ORG/REPO:environment:production, a nie referencję gałęzi. Poproś agenta o wygenerowanie polityki zaufania z wyzwalacza i środowiska workflow, a potem porównaj jej warunek sub z claimem z nieudanego uruchomienia.

  4. Trivy wywraca build na CVE, które nie ma jeszcze poprawki. Nie usuwaj ani nie osłabiaj kroku skanowania; skan, który nie może zawieść, to powtórka incydentu z początku strony. ignore-unfixed: true pomija podatności bez wersji z poprawką. Resztę dopisz do .trivyignore z datą wygaśnięcia, na przykład CVE-2026-12345 exp:2026-12-31, i komentarzem wskazującym recenzenta. Trivy zgłosi ją ponownie, gdy data minie.

  5. Agent przypina akcje do tagów, @main albo do nieistniejących wersji. Agenci odtwarzają wersje z danych treningowych i zgadują SHA. Złośliwe wydania LiteLLM 1.82.7/1.82.8 na PyPI (2026-03-24) powiązano ze skompromitowanym krokiem Trivy w CI LiteLLM (doniesienia wtórne; zgłoszenie BerriAI/litellm#24518). Przypięcie przez SHA sprawia, że przesunięty albo przejęty tag nie zmieni tego, co uruchamia twój pipeline. Ponów prompt z „resolve every action to its full commit SHA with git ls-remote, tag as a comment” i pozwól audytowi unpinned-uses w zizmor to potwierdzić.

  6. Job AI review nigdy nie komentuje. Sprawdź po kolei trzy rzeczy: pull request przyszedł z forka (brak sekretów, celowo), filtr paths wykluczył zmieniony plik albo job nie ma pull-requests: write. Popraw filtr albo uprawnienie. Nie poszerzaj wyzwalacza.

Czy ten artykuł Ci pomógł?

Jedno kliknięcie, bez logowania.

wcale bardzo