4 puan yazan GN⁺ 2025-04-09 | 2 yorum | WhatsApp'ta paylaş
  • GitHub Actions'taki shell, run: bloğunun nasıl çalıştırılacağını belirleyen bir ayardır; ancak gerçekte önceden tanımlı bir kabuk listesiyle sınırlı değildir ve $PATH içindeki yürütülebilir dosyaları da hedef alabilir
  • Workflow içinde isteğe bağlıdır, action tanımında ise zorunludur; varsayılan değer runner'a göre değişir ve Linux/macOS'ta bash, Windows'ta pwsh olur
  • shell: bash gibi açıkça belirtildiğinde GitHub, bash --noprofile --norc -eo pipefail gibi ek bayraklar ekler; ancak çalıştırılan hedefin kendisi yine herhangi bir program olabilir
  • Yürütülebilir dosya tek bir dosya girdisini kabul etmiyorsa shell değerine {0} argümanı eklenmelidir; GitHub bunu run bloğunu içeren geçici dosyanın yoluyla değiştirir
  • bash gibi tanıdık adlar da $PATH üzerinden çözümlendiği için, $GITHUB_PATH değişiklikleri veya sahte yürütülebilir dosyalar sonraki adımların çalışma biçimini etkileyebilir

shell anahtar sözcüğünün varsayılan davranışı

  • GitHub Actions'taki shell anahtar sözcüğü, belirli bir run: bloğunun hangi kabuk ile çalıştırılacağını belirtir
  • Workflow içinde isteğe bağlıdır, ancak action tanımında zorunludur
  • Varsayılan kabuk runner ortamına göre belirlenir
    • Linux ve macOS'ta genellikle bash
    • Windows'ta genellikle pwsh

Kabuk açıkça belirtildiğinde ek bayraklar

  • GitHub, defaults.run.shell belgesinde kabuk açıkça belirtilirse GitHub'ın seçtiği bayrakların da uygulanacağını belirtir
  • Örneğin shell: bash açıkça belirtilirse yürütme biçimi şu olur
    • bash --noprofile --norc -eo pipefail
  • Yalnızca bu davranışa bakıldığında, GitHub'ın sınırlı bir geçerli kabuk değerleri listesi yönettiğini ve özel bayrakları yalnızca bu değerlere eklediğini düşünmek kolaydır

$PATH içindeki herhangi bir yürütülebilir dosya da kabuk olabilir

  • Gerçekte shell için $PATH içinde bulunan herhangi bir yürütülebilir dosya belirtilebilir
  • GitHub, run bloğunu belirtilen yürütülebilir dosyayla çalıştırır
  • İlgili komut tek bir dosya girdisini doğrudan kabul etmiyorsa shell değerine {0} eklenmelidir
    • GitHub, {0} ifadesini geçici dosya yoluyla değiştirir
    • Bu geçici dosya, şablon genişletmesi uygulanmış run bloğu içeriğini barındırır

C'yi adım çalıştırıcısı olarak kullanma örneği

  • C derleyicisi/yorumlayıcısı gibi davranan araçlar da GitHub Actions adımlarını çalıştırmak için kullanılabilir
  • tcc -run {0} değerinin shell olarak verildiği örnek sorunsuz çalışır
- run: sudo apt install -y tcc
- shell: tcc -run {0}
  run: |
    #include <stdio.h>
    int main() {
      printf("Hello, world!\n");
      return 0;
    }

$GITHUB_PATH ile kabuk çözümlemesini değiştirme örneği

  • $GITHUB_PATH üzerinden $PATH dinamik olarak değiştirilirse, sonraki shell: bash beklenenden farklı bir yürütülebilir dosyayı gösterebilir
  • Örnekte geçerli dizinde bash adlı bir yürütülebilir dosya oluşturuluyor ve geçerli dizin $GITHUB_PATH içine ekleniyor
  • Ardından shell: bash kullanıldığında GitHub, $PATH içinde bulduğu sahte bash dosyasını çalıştırabilir
- run: |
    touch ./bash
    chmod +x ./bash
    echo '#!/bin/sh' > ./bash
    echo 'echo hello from fake bash' >> ./bash
    echo "${PWD}" >> "${GITHUB_PATH}"
- run: |
    echo "this doesn't do what you expect"
  shell: bash

Güvenlik açısından beklenmedik nokta

  • Bu davranışın güvenlik açısından ne kadar önemli olduğunu kesin olarak söylemek zor
  • GitHub Actions içinde dosya yazmanın yürütmeye dönüştüğü zaten birçok yol var ve GITHUB_ENV de bu örnekler arasında yer alıyor
  • Yine de GitHub'ın bash gibi iyi bilinen kabuk değerleri için bile $PATH araması yapması beklenmedik olabilir
  • Özellikle iyi bilinen kabuk değerlerine göre komut satırı bayrakları enjekte ediliyorsa, bashin /bin/bash gibi belirli bir yola sabitleneceği düşünülebilir
  • Daha genel olarak, GitHub'ın yalnızca araç önbelleğine önceden kaydedilmiş araçlara izin verdiği sanılabilir; ancak gözlemlenen davranış $PATH içindeki yürütülebilir dosyaları kullanma yönündedir

2 yorum

 
tujuc 2025-04-09

github/runner-image deposuna baksanız bile, doğrudan kullanılabilecek epey fazla paket kurulu oluyor....

İmajı oluşturunca 1GB zaten hemen doluyor....

 
GN⁺ 2025-04-09
Hacker News yorumları
  • Eskiden Actions iş akışında bash’in çalıştırdığı tüm komutları yazdırmasını sağlamak için -x bayrağını kullanmıştım; hata ayıklamada epey işe yarıyor
    https://github.com/jstrieb/just.sh/blob/2da1e2a3bfb51d583be0...
    • Bu arada pipefail’i açarsanız, boru hattındaki öğelerden biri başarısız olduğunda adım başarısız olur ama hata çıktısı olmadığı için neden başarısız olduğunu anlamayabilirsiniz
      pipefail daha karmaşık hata durumlarını da engellemez. Örneğin yapılandırmadaki curl ... | sudo tar ... adımında tar çıkarma hatası, sudo hatası, kabuk hatası gibi durumlar görünür; ancak curl bir ağ hatasıyla ortada başarısız olursa tar, just ikilisini yarım çıkarıp bırakabilir ve kabuk hemen sonlanabilir. Bu durumda hata mesajı olmaz; bozuk çalıştırılabilir dosya diskte kalır ve başarısızlığı atlama açıksa çalıştırılmaya bile çalışılabilir
  • İş yerinde gördüğüm güzel bir kapalı GitHub Actions numarası, repository_dispatch olay adında joker karakter kullanarak eşleştirme yapılabilmesiydi
    on: repository_dispatch: - security_scan - security_scan::* gibi kullanılabiliyor. Yayın hattını merkezîleştirirseniz her deponun tanımlı yeniden kullanılabilir iş akışından geçmesini zorunlu kılabilirsiniz; security_scan::$product_name::$version gibi bir olay gönderdiğinizde de merkezî yayın deposunun Actions sekmesinde hangi ürün ve sürümün iş akışının çalıştığını anlamak çok daha kolay olur
    • Böyle bir merkezî yaklaşımın pratikte gerçekten iyi çalışıp çalışmadığını merak ediyorum. Kuruluşta her şeyin bire bir aynı şekilde derlenmesi mi isteniyor?
      Benzer bir şey yapmaya çalışan bir kuruluşa yeni katıldım; pratikte neredeyse işe yaramaz görünüyor. Şablonlar sık sık bozuluyor ve çoğu zaman kodun nasıl derlenmesi gerektiğine dair dokümantasyon olmadan belirli bir derleme yöntemini varsayarak yazılmış oluyor
  • GitHub Actions içinde ne kadar az şey yaparsanız o kadar iyi diye düşünüyorum
    Genelde mantığı Make gibi bir derleme sistemine koyup GitHub Actions’tan sadece çağırmayı ya da küçük bir komut satırı programı yazıp onu çağırmayı tercih ederim. Bunları yerelde hata ayıklamak CI’a göre çok daha kolay. İlginç bir numara ama nerede faydalı olur pek emin değilim
    • Bizim iş akışımız aslında make build ve make test civarında
      Satın alındıktan sonra bizi alan şirketin iş akışı dosyasına baktım; yüzlerce satırdı ve çok sayıda tekrar eden bölüm vardı. Eski kafalı diyebilirsiniz ama YAML kasabasından mümkün olduğunca çabuk çıkmak istiyorum
    • Bu yazı, yazarın bunu yapmayı önerdiğinden ziyade, bunun mümkün olduğunu gösteriyor gibi
      Fiilen kullanmayı planlamadığınız bir özellik olsa bile sistemde nelerin mümkün olduğunu bilmek güvenlik ve hata ayıklama açısından faydalıdır
    • Benim yorumumca bu kullanışlı değil; kesinlikle kullanışlı değil. Ama potansiyel bir güvenlik riski var
      Özellikle de kendi barındırdığınız runner’ları “keşfederken”
  • Bizim kuşak, sürekli değişen elektronik tabloları koda dönüştürmemiz istendiğinde dehşete düşüyordu
    Sonraki kuşak, GitHub Actions ile yapılmış dağıtımlara disiplin getirmeleri istendiğinde titreyecek
    • Şu anda büyük bir kurumsal yapıyı GH Actions’a taşıma işi yapıyorum; daha doğrusu “git’e bağlı YAML tabanlı pipeline” demek daha doğru. Burada disiplin nasıl görünmeli?
      Açıklayabilirseniz bizim kuruluşta muhtemelen hayata geçirebiliriz
    • Bunun neden disiplinsiz olduğunu merak ediyorum
  • Varsayılan kabuk olan bash’i kandırıp rastgele bir program çalıştırmasını da sağlayabilirsiniz
  • Action’ı okuyan diğer insanlar ne olduğunu biliyorsa oldukça faydalı görünüyor
    Elle yazılmış birkaç komutu neredeyse aynen taşıyarak başlayan kabuk betiklerinin yüz satırı aşan canavarlara dönüştüğü çok oldu; her seferinde gerçek diziler ve tipler ile Python standart kütüphanesinin piller dahil özellikleri olsaydı diye düşündüm. Yine de şirketin derleme Action’ını elisp ile uygulamayacağım
  • Github Actions Runner kodu oldukça okunabilir. Popüler kabukların/ikili dosyaların varsayılan argümanlarının tanımlandığı yer burası: https://github.com/actions/runner/blob/main/src/Runner.Worke...
    ScriptHandlerHelpers.GetScriptArgumentsFormat metodu üzerinden sunuluyor. ScriptHandler.cs içinde süreç ortamı ve argüman hazırlama kodu var; gerçek süreç başlatma kodu ise burada: https://github.com/actions/runner/blob/main/src/Runner.Worke...
    Genel olarak bu kodun basitliği beni iyi anlamda şaşırttı. Çok prosedürel ve çok sayıda uç durumu ele alıyor ama anlaşılması ve hata ayıklaması kolay görünüyor
  • Artık nihayet üretim CI/CD’de C kullanıp buna “düşük seviyeli sistem işi” diyebileceğiz
    Assembly de mümkün gibi
  • Bu, goeval [1] kullanarak GitHub iş akışı YAML dosyasında Go kodunu doğrudan CI işi olarak çalıştırmanın kolaylaşabileceğine dair umut verdi
    Ancak goeval henüz dosya girdisini doğrudan desteklemiyor, sadece standart girdiyi destekliyor; bu yüzden kabuk numarası gerekiyor. Şimdilik go run github.com/dolmen-go/goeval@v1 - <<'EOF' ... EOF gibi bir yöntem kullanılıyor ve biraz boilerplate gerekiyor. Not: goeval’in yazarıyım
    [1] https://github.com/dolmen-go/goeval
    • Neden kabuk “numarası” gerektiğini anlamadım. go run github.com/dolmen-go/goeval@v1 - < file.go olmuyor mu?
    • Depoya gidip bunun boşlukları otomatik olarak tab’a çeviren bir program olup olmadığına bakacaktım; gördüğüm kadarıyla daha çok tek satırlık ifadeler tarafına odaklanmış
      Bu bağlamda oyuncak bir projeyi tanıtacaksanız “hello yazdır” yerine daha ilgili bir örnek gösterseydiniz tıklamama gerek kalmazdı
  • GitHub CI YAML’ın run: pipeline.sh gibi bir bash betiğine göre daha iyi yanı ne?
    • Otomatik yönetilen bir GitHub API token’ı var; yayın otomasyonu, artifact ve container yayımlamak için faydalı
      Birden fazla işletim sistemi ve CPU mimarisinde işleri aynı anda çalıştırabilirsiniz; işi tetikleyen olay ve depo durumu hakkında bağlam bilgisi de alabilirsiniz. PR başına işler veya yayın otomasyonu için kullanışlıdır; linter’ın PR’daki her satırda sorunları göstermesi ya da test hatalarının bir web sayfasında render edilmesi gibi GitHub web UI ile de entegre olabilir. Değişmeyen dosyaları yeniden indirmemek veya yeniden derlememek için küçük bir cache de kullanılabilir. İdeal olarak mümkün olduğunca çok şeyi yerelde çalışan normal araçlara koymak, GitHub CI yapılandırmasının ise yalnızca tetikleyiciler, cache ve GitHub entegrasyonu için gereken yapıştırıcı kodu üstlenmesini sağlamak daha iyi
    • GitHub UI’da her adımın özetini görebilir, adım bazlı çıktıları genişletip daraltarak inceleyebilirsiniz
      Başkalarının yaptığı GitHub Actions’ları pipeline’da kolayca kullanabilir, iş akışını modülerleştirebilir, bağımlılıkları ve paralel çalıştırmayı kontrol edebilirsiniz. Daha fazlası da vardır ama temel avantaj, bunları kendiniz uygulamak zorunda kalmamanız
    • GitHub açısından bakınca, kullanıcıların başka bir Git forge’a geçme olasılığının azalması gibi bir avantajı var