0Pricing
DevOps Bootcamp · Ders

ShellCheck ile Statik Analiz ve Denetim

ShellCheck'i bir güvenlik kapısına entegre edin ve her betiği güçlendirmek için bulgularını yorumlayın.

ShellCheck ile Statik Analiz ve Denetim, CoddyKit'te ücretsiz bir DevOps Bootcamp dersidir. Bu, 4 dersinin 4. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, DevOps Bootcamp öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. DevOps Bootcamp kursu toplamda 4 dersten oluşur.

ShellCheck Nedir ve Neden Önemlidir

ShellCheck, kabuk betikleri için açık kaynaklı bir statik analiz aracıdır. Bash (ve POSIX sh, dash, ksh) kaynak kodunuzu çalıştırmadan ayrıştırır; hataları, güvensiz yapıları, taşınabilirlik sorunlarını ve biçem problemlerini bildirir. Her bulgu SC2086 gibi benzersiz bir kural koduyla etiketlenir.

Güvenliği güçlendirilmiş bir işlem hattında ShellCheck, zorunlu bir geçit görevi görür: hiçbir betik denetimden geçmeden yayımlanmaz. Bunun önemli olmasının nedenleri şunlardır:

  • Pek çok kabuk güvenlik açığı (kelime bölme, ekleme, tırnak içine alınmamış genişletme), normal akış testleri sırasında görünmez; ancak saldırganın denetimindeki girdilerle tetiklenir.
  • ShellCheck bu hata sınıflarını çalışma zamanından önce, hiçbir ek maliyet olmadan yakalar.
  • Her kalıbın neden tehlikeli olduğunu belgeleyerek ekibinizin zamanla daha bilinçli olmasını sağlar.

Herhangi bir sisteme yükleyin:

# Debian / Ubuntu
sudo apt-get install shellcheck

# macOS (Homebrew)
brew install shellcheck

# From source via Cabal (any platform)
cabal update && cabal install ShellCheck

# Verify
shellcheck --version

ShellCheck'i İlk Kez Çalıştırma

En basit çağrı shellcheck <script> biçimindedir. ShellCheck, kabuk lehçesini belirlemek için shebang satırını okur ve ardından bulguları stdout'a yazar.

Her bulgu şunları içerir:

  • Dosya ve satır numarası — tam konum
  • Önem derecesi — error, warning, info veya style
  • SC kodu — bakabileceğiniz veya bastırabileceğiniz kararlı kural tanımlayıcısı
  • İnsanların anlayacağı açıklama — neyin yanlış olduğunu ve çoğu zaman nasıl düzeltileceğini söyler

Aşağıdaki betiği çalıştırın ve ShellCheck'in üreteceği çıktıyı inceleyin:

#!/usr/bin/env bash
# demo_bad.sh — intentionally flawed for ShellCheck demonstration

FILE=$1

if [ $FILE == '' ]; then
  echo "No file given"
fi

cat $FILE | grep 'error' | wc -l

ShellCheck Çıktısını ve SC Kodlarını Yorumlama

Önceki sahnedeki betik için ShellCheck şu tür bulgular üretirdi:

  • SC2086 (warning) — Glob genişletmesini ve kelime bölmeyi önlemek için çift tırnak kullanın — [ $FILE == '' ] içindeki $FILE ve cat $FILE içindeki $FILE için.
  • SC2039 / SC3010 (info) — [ ] içinde == Bash'e özgüdür; POSIX için = kullanın.
  • SC2002 (style) — Gereksiz cat. cat file | cmd yerine cmd < file kullanmayı düşünün.

Her SC kodu, gerekçe ve düzeltilmiş bir örnek içeren https://www.shellcheck.net/wiki/SCxxxx adresindeki bir wiki sayfasına karşılık gelir.

Bu betiğin düzeltilmiş sürümü:

#!/usr/bin/env bash
# demo_fixed.sh — ShellCheck-clean

FILE="$1"

if [ -z "$FILE" ]; then
  echo "No file given" >&2
  exit 1
fi

grep -c 'error' "$FILE"

Önem Derecesi Düzeyleri ve Yapılacaklar

ShellCheck her bulguyu önem derecesine göre sınıflandırır. Bir güvenlik geçidinde bunları şöyle ele almalısınız:

  • error — Neredeyse kesinlikle bir hata veya güvenlik açığıdır. Derlemeyi engelleyin. Hemen düzeltin. Örnek: shebang eksikliği olan SC2148, tırnak içine alınmamış $? için SC2070.
  • warning — Sıklıkla istismar edilebilen yüksek riskli kalıptır. Derlemeyi engelleyin. Düzeltin veya bastırmayı açıkça gerekçelendirin. Örnek: tırnak içine alınmamış değişken için SC2086.
  • info — Bugün büyük olasılıkla doğrudur; ancak kırılgan veya taşınabilir olmayabilir. Kapsam dışında bırakılmadıysa aynı PR içinde düzeltin.
  • style — Görsel veya POSIX tercihiyle ilgilidir. Salt Bash kod tabanında önerilir, ancak isteğe bağlıdır.

Yalnızca warning ve üzeri bulgularda sıfırdan farklı çıkış kodu vermek için --severity=warning kullanın; bu, standart güvenlik geçidi eşiğidir:

#!/usr/bin/env bash
# gate.sh — fail CI on errors and warnings only
shellcheck --severity=warning scripts/*.sh
echo "ShellCheck exit code: $?"

ShellCheck'i CI Güvenlik Geçidi Olarak Entegre Etme

Bir güvenlik geçidi ancak zorunlu ve otomatik olduğunda işe yarar. Aşağıdaki kalıp, ShellCheck'i şu işlemleri yapan bir CI adımına sarar:

  • Depodaki tüm .sh dosyalarını bulur.
  • ShellCheck'i --severity=warning ve makinelerin okuyabileceği JSON çıktısıyla çalıştırır.
  • Herhangi bir bulgu varsa işlem hattını (exit 1) başarısız kılar.
  • Mühendislerin CI günlüğünden ayrılmadan bulgular üzerinde işlem yapabilmesi için bir özet yazdırır.

Bu dosyayı deponuza ekleyin ve CI işlem hattınızdan (GitHub Actions, Jenkins, GitLab CI vb.) çağırın:

#!/usr/bin/env bash
# ci/shellcheck_gate.sh
set -euo pipefail

SCRIPTS=$(find . -name '*.sh' -not -path './.git/*')
FAILED=0

for script in $SCRIPTS; do
  echo "==> Checking: $script"
  if ! shellcheck --severity=warning --format=tty "$script"; then
    FAILED=1
  fi
done

if [ "$FAILED" -eq 1 ]; then
  echo "[GATE] ShellCheck found warnings or errors. Build blocked." >&2
  exit 1
fi

echo "[GATE] All scripts passed ShellCheck."

SC2086 Ailesi: Tırnak İçine Alınmamış Değişken Genişletmeleri

SC2086, en yaygın ShellCheck bulgusu ve en çok istismar edilen kabuk güvenlik açıklarından biridir: tırnak içine alınmamış değişken genişletmeleri.

Bir değişken çift tırnak içine alınmadığında kabuk, değeri üzerinde kelime bölme işlemi (IFS üzerinden böler) ve glob genişletmesi gerçekleştirir. Değişkeni denetleyen bir saldırgan, ek bağımsız değişkenler ekleyebilir, dosya sistemi geçişini tetikleyebilir veya komutların beklenmeyen işlenenler almasına neden olabilir.

Klasik tehlikeli kalıp:

#!/usr/bin/env bash
# Attacker sets: FILENAME="important.txt /etc/passwd"
FILENAME="$1"

# UNSAFE — word splitting turns this into two args
rm $FILENAME

# SAFE — double quotes prevent splitting
rm "$FILENAME"

# Arrays are the right tool for lists
FILES=("$@")
rm -- "${FILES[@]}"

SC2046 ve SC2035 ile Komut Ekleme Riskini Belirleme

Daha az bilinen ancak kritik iki kural, alt kabuk çıktısı üzerinden komut ekleme sorununu ele alır:

  • SC2046 — $(…) içindeki kelime bölme ve glob genişlemesini önlemek için bunu tırnak içine alın. Alt kabuğun çıktısı tırnak içine alınmadan kullanılırsa çıktıda bulunan her boşluk veya glob karakteri bir kabuk belirtecine dönüşür.
  • SC2035 — - ile başlayan dosya adlarının seçenek olarak yorumlanmasını önlemek için *.sh yerine ./*.sh kullanın; bu, klasik bir bağımsız değişken ekleme vektörüdür.

Somut istismar senaryosu ve düzeltmesi:

#!/usr/bin/env bash
# SC2046 example — output of find fed unquoted to chmod
# If a filename contains spaces, extra arguments appear

# UNSAFE
chmod 600 $(find /secrets -name '*.key')

# SAFE — use a while-read loop or xargs with -0
find /secrets -name '*.key' -print0 \
  | xargs -0 chmod 600

# SC2035 example
# UNSAFE — a file named '-rf' would be passed as an option
rm *.sh

# SAFE
rm -- ./*.sh

Otomasyon İçin JSON Çıktı Biçimini Kullanma

ShellCheck, --format aracılığıyla birden çok çıktı biçimini destekler:

  • tty (varsayılan) — insanların okuyabileceği terminal çıktısı
  • json — makinelerin okuyabileceği biçim; panolar, özel engelleyiciler veya SAST platformlarına yükleme için idealdir
  • gcc — GCC hata biçimini ayrıştıran araçlarla uyumludur (IDE'ler, Vim/Emacs)
  • checkstyle — Jenkins Checkstyle eklentisinin kullandığı XML biçimi

JSON biçimi, örneğin yalnızca belirli SC kodlarını engellemek veya büyük bir kod tabanındaki bulguları tek bir güvenlik raporunda toplamak gibi otomatik politikalar yazmanıza olanak tanır.

#!/usr/bin/env bash
# Emit JSON and filter for only error-severity findings using jq
shellcheck --format=json scripts/deploy.sh \
  | jq '[.[] | select(.level == "error")]'

# Count distinct SC codes across all scripts
find . -name '*.sh' -print0 \
  | xargs -0 shellcheck --format=json 2>/dev/null \
  | jq '[.[] | .code] | group_by(.) | map({code: .[0], count: length}) | sort_by(-.count)'

Yanlış Pozitifleri Doğru Biçimde Bastırma

ShellCheck'i topluca devre dışı bırakmak amacını boşa çıkarır. Doğru yaklaşım, yalnızca bulgunun gerçekten uygulanamadığı tam satırı veya bloğu etkileyen hedefli ve belgelenmiş bir bastırma kullanmaktır.

Üç bastırma mekanizması vardır:

  • Satır içi devre dışı bırakma — sorunlu kodun üstündeki satıra # shellcheck disable=SC2086 yazın. Yalnızca o satırı etkiler.
  • Blok için devre dışı bırakma/etkinleştirme — bir bölümü # shellcheck disable=… ve # shellcheck enable=… ile sarın.
  • Dosya düzeyinde yönerge — # shellcheck disable=… ifadesini dosyanın en üstüne yerleştirin (nadiren gerekçelendirilebilir; nedenini belgeleyin).

Her bastırma, bulgunun neden yanlış pozitif olduğunu açıklayan bir yorum içermelidir:

#!/usr/bin/env bash
# deploy.sh

# Legitimate suppression: $DEPLOY_ARGS is intentionally word-split
# because it is a pre-validated list of flags from a trusted config file.
# shellcheck disable=SC2086
exec deploy-tool $DEPLOY_ARGS

# Block suppression for a section that generates dynamic code
# shellcheck disable=SC2016
VARS='$HOME $PATH $USER'
echo "Unexpanded vars: $VARS"
# shellcheck enable=SC2016

.shellcheckrc Üzerinden ShellCheck Yapılandırma

Proje genelindeki ayarlar için ShellCheck, betiğin bulunduğu dizinden başlayarak / dizinine kadar yukarı doğru .shellcheckrc dosyasını okur. Böylece her çağrıda seçenekleri tekrarlamaktan kaçınabilir ve geçit betiklerini basit tutabilirsiniz.

.shellcheckrc içindeki kullanışlı yönergeler:

  • shell=bash — lehçe algılamasını geçersiz kılar (shebang içermeyen dosyalar için kullanışlıdır)
  • enable=all — isteğe bağlı denetimleri etkinleştirir (ör. avoid-nullary-conditions, require-variable-braces)
  • disable=SC2059 — gerekçelendirilmiş bir istisna için proje genelinde bastırma
  • external-sources=true — source / . yönergelerini izler ve denetler
# .shellcheckrc — project root
shell=bash
enable=all
external-sources=true

# SC2312: consider invoking this command separately to avoid masking its
# return value — suppressed project-wide because we use set -e.
# Rationale: errexit already aborts on failure; masking risk is mitigated.
disable=SC2312

Uçtan Uca Güçlendirilmiş Betik: Öncesi ve Sonrası

ShellCheck bulgularını içselleştirmenin en etkili yolu, gerçekçi bir betiği başarısız bir durumdan temiz ve güçlendirilmiş bir duruma yeniden düzenlemektir. Aşağıdaki betik bir dizini yedekler ve güvenlik dikkate alınmadan yazılmıştır. En az beş farklı kural açısından ShellCheck denetiminden geçemez.

Her iki sürümü de inceleyin. Sonraki sürüm, bastırma yönergeleri olmadan shellcheck --severity=warning denetiminden geçer ve saldırganın denetimindeki girdiler karşısında önemli ölçüde daha güvenlidir:

#!/usr/bin/env bash
# BEFORE — multiple ShellCheck violations
DEST=$1
SRC=$2
DATE=`date +%Y%m%d`

if [ ! -d $DEST ]; then
  mkdir $DEST
fi

cp -r $SRC $DEST/$DATE
echo Done


#!/usr/bin/env bash
# AFTER — ShellCheck-clean and hardened
set -euo pipefail

DEST="${1:?Usage: backup.sh <dest> <src>}"
SRC="${2:?Usage: backup.sh <dest> <src>}"
DATE=$(date +%Y%m%d)

if [ ! -d "$DEST" ]; then
  mkdir -p -- "$DEST"
fi

cp -r -- "$SRC" "$DEST/$DATE"
echo 'Done' >&2

Bilgi Yoklaması: Güvenlik Geçidinde ShellCheck

ShellCheck'in güvenlik geçidi olarak rolünü ne kadar anladığınızı sınayın.

Özet: Güvenlik Geçidi Olarak Statik Analiz

Bu derste ShellCheck'i Bash iş akışınızda zorunlu bir güvenlik geçidi hâline getirmeyi öğrendiniz:

  • ShellCheck, betiklerinizi çalıştırmadan statik analiz gerçekleştirir; tırnak kullanımı hatalarını, ekleme risklerini ve güvensiz kalıpları çalışma zamanından önce yakalar.
  • Her bulgu, ayrıntılı belgelere ve düzeltme yönergelerine bağlanan bir SC kodu (ör. SC2086) içerir.
  • Önem derecesi basamakları — error, warning, info, style — geçidi ayarlamanıza olanak tanır: --severity=warning önerilen güvenlik eşiğidir.
  • Raporlamayı, eğilim takibini ve SAST entegrasyonunu otomatikleştirmek için makinelerin okuyabileceği çıktıyı (--format=json) kullanın.
  • Bastırmayı ölçülü kullanın: her zaman tek bir satırı hedefleyin, nedenini her zaman bir yorumda belgeleyin ve gerekçelendirilmedikçe .shellcheckrc aracılığıyla bile olsa genel olarak bastırmayın.
  • Derinlemesine savunma için ShellCheck'i set -euo pipefail, açık tırnak kullanımı, -- argument sonlandırıcıları ve girdi doğrulamasıyla birlikte kullanın.

ShellCheck denetiminden geçen bir betik otomatik olarak güvenli değildir; ancak ShellCheck denetiminden geçemeyen bir betik asla üretim ortamına ulaşmamalıdır.

Sıkça Sorulan Sorular

“ShellCheck ile Statik Analiz ve Denetim” dersi ücretsiz mi?

Evet — “ShellCheck ile Statik Analiz ve Denetim” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve DevOps Bootcamp kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. DevOps Bootcamp kursu toplamda 4 dersten oluşur.

“ShellCheck ile Statik Analiz ve Denetim” dersinde ne öğreneceğim?

ShellCheck'i bir güvenlik kapısına entegre edin ve her betiği güçlendirmek için bulgularını yorumlayın. DevOps Bootcamp ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.

DevOps Bootcamp öğrenmeye başlamak için deneyim gerekli mi?

Önceden deneyim gerekmez. CoddyKit'te DevOps Bootcamp, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 4. dersidir.

“ShellCheck ile Statik Analiz ve Denetim” dersi ne kadar sürer?

Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.

Bu DevOps Bootcamp dersinde kod yazıp çalıştırabilir miyim?

Evet. Her DevOps Bootcamp dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.

Bu kursun tüm dersleri

  1. Komut ve Bağımsız Değişken Enjeksiyonunu Önleme
  2. Güvenli Gizli Bilgi Yönetimi ve Ortam Hijyeni
  3. En Az Ayrıcalıklı Çalıştırma ve sudo Disiplini
  4. ShellCheck ile Statik Analiz ve Denetim
← DevOps Bootcamp Sayfasına Dön