shell di GitHub Actions adalah pengaturan yang menentukan cara menjalankan blok run:, tetapi sebenarnya targetnya bukan daftar shell yang sudah ditentukan, melainkan juga bisa berupa executable di $PATH
- Di workflow sifatnya opsional, sedangkan di definisi action wajib; nilai default-nya berbeda tergantung runner, seperti
bash di Linux/macOS dan pwsh di Windows
- Jika ditulis eksplisit seperti
shell: bash, GitHub menambahkan flag tambahan seperti bash --noprofile --norc -eo pipefail, tetapi target eksekusinya sendiri bisa berupa program arbitrer
- Jika executable tidak menerima satu file input, nilai
shell harus menyertakan argumen {0}, dan GitHub akan menggantinya dengan path file sementara yang berisi blok run
- Nama yang familier seperti
bash pun di-resolve dari $PATH, sehingga perubahan $GITHUB_PATH atau executable palsu dapat memengaruhi cara step berikutnya dijalankan
Perilaku dasar keyword shell
- Keyword
shell di GitHub Actions menentukan shell apa yang digunakan untuk menjalankan blok run: tertentu
- Di workflow, ini opsional, tetapi di definisi action wajib digunakan
- Shell default ditentukan berdasarkan lingkungan runner
- Di Linux dan macOS biasanya
bash
- Di Windows biasanya
pwsh
Penentuan shell secara eksplisit dan flag tambahan
- Dalam dokumentasi
defaults.run.shell, GitHub menjelaskan bahwa jika shell ditentukan secara eksplisit, flag yang dipilih GitHub juga ikut diterapkan
- Misalnya, jika
shell: bash ditulis eksplisit, bentuk eksekusinya menjadi seperti berikut
bash --noprofile --norc -eo pipefail
- Jika hanya melihat perilaku ini, mudah untuk mengira bahwa GitHub mengelola daftar nilai shell yang valid secara terbatas dan hanya menambahkan flag khusus pada nilai-nilai tersebut
Executable arbitrer di $PATH juga bisa menjadi shell
- Kenyataannya,
shell dapat diisi dengan executable arbitrer yang ada di $PATH
- GitHub menjalankan blok
run dengan executable yang ditentukan
- Jika perintah tersebut tidak menerima satu file input secara langsung, nilai
shell harus diberi {0}
- GitHub mengganti
{0} dengan path file sementara
- File sementara ini berisi isi blok
run yang sudah mengalami ekspansi template
Contoh menggunakan C sebagai runner step
- Tool yang berperilaku seperti compiler/interpreter C juga dapat digunakan untuk menjalankan step GitHub Actions
- Contoh yang menetapkan
tcc -run {0} sebagai shell berjalan dengan benar
- run: sudo apt install -y tcc
- shell: tcc -run {0}
run: |
#include <stdio.h>
int main() {
printf("Hello, world!\n");
return 0;
}
Contoh mengubah resolusi shell dengan $GITHUB_PATH
- Jika
$PATH dimodifikasi secara dinamis lewat $GITHUB_PATH, shell: bash berikutnya bisa menunjuk ke executable yang berbeda dari yang diharapkan
- Contoh ini membuat executable bernama
bash di direktori saat ini, lalu menambahkan direktori saat ini ke $GITHUB_PATH
- Setelah itu, saat
shell: bash digunakan, GitHub bisa menjalankan bash palsu yang ditemukan dari $PATH
- 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
Poin yang tidak sesuai dugaan dari sisi keamanan
- Sulit untuk memastikan apakah perilaku ini penting dari sisi keamanan
- GitHub Actions sudah memiliki banyak jalur di mana penulisan file dapat berujung pada eksekusi, dan
GITHUB_ENV termasuk salah satu contohnya
- Namun, fakta bahwa GitHub melakukan lookup
$PATH bahkan untuk nilai shell yang dikenal luas seperti bash bisa saja tidak sesuai dugaan
- Terutama jika GitHub menyisipkan flag command line berdasarkan nilai shell yang dikenal luas, orang mungkin berharap
bash dikunci ke path tertentu seperti /bin/bash
- Secara lebih umum, orang juga mungkin mengira GitHub hanya mengizinkan tool yang sudah terdaftar sebelumnya di tool cache, tetapi perilaku yang diamati adalah menggunakan executable dari
$PATH
2 komentar
Bahkan hanya dengan melihat repo github/runner-image, sudah terpasang cukup banyak paket yang bisa langsung digunakan....
Kalau membuat image, 1GB itu langsung terpakai....
Pendapat Hacker News
-xagar bash mencetak semua perintah yang dijalankan di workflow Actions, dan itu cukup membantu untuk debugginghttps://github.com/jstrieb/just.sh/blob/2da1e2a3bfb51d583be0...
pipefail juga tidak mencegah status error yang lebih rumit. Misalnya, pada langkah
curl ... | sudo tar ...di konfigurasi, kasus seperti kegagalan ekstraksitar, kegagalansudo, atau error shell akan terlihat, tetapi jikacurlgagal di tengah karena error jaringan,tarbisa saja mengekstrak binaryjusthanya separuh lalu shell langsung keluar. Saat itu tidak ada pesan error, dan executable yang rusak tertinggal di disk; jika skip-on-failure diaktifkan, executable itu bahkan bisa dicoba dijalankanrepository_dispatchbisa dicocokkan dengan wildcardBisa ditulis seperti
on: repository_dispatch: - security_scan - security_scan::*. Jika pipeline rilis dipusatkan, setiap repositori bisa dipaksa melewati reusable workflow yang sudah didefinisikan, dan dengan mengirim event sepertisecurity_scan::$product_name::$version, jauh lebih mudah mengetahui workflow untuk produk dan versi mana yang sedang berjalan di tab Actions repositori rilis pusatSaya baru bergabung dengan organisasi yang mencoba melakukan hal serupa, tetapi dalam praktiknya terlihat hampir tidak berguna. Template sering rusak, dan sering ditulis dengan asumsi cara build tertentu tanpa dokumentasi tentang bagaimana kode seharusnya dibangun
Biasanya saya lebih suka menaruh logic di sistem build seperti Make lalu GitHub Actions hanya memanggilnya, atau menulis program command-line kecil untuk dipanggil. Hal-hal seperti ini jauh lebih mudah di-debug secara lokal daripada di CI. Ini trik yang menarik, tetapi saya tidak yakin akan berguna di mana
make builddanmake testSetelah diakuisisi, saya melihat file workflow perusahaan pengakuisisi dan isinya ratusan baris dengan banyak bagian berulang. Boleh saja menyebut saya kuno, tetapi saya ingin keluar dari kampung YAML secepat mungkin
Mengetahui apa saja yang mungkin dilakukan dalam sebuah sistem berguna untuk keamanan dan debugging, sekalipun itu fitur yang tidak benar-benar akan dipakai
Terutama saat “menjelajahi” self-hosted runner
Generasi berikutnya akan gemetar ketika diminta menegakkan disiplin pada deployment yang dibuat dengan GitHub Actions
Kalau bisa dijelaskan, mungkin kami bisa mewujudkannya di organisasi kami
bashjuga bisa dikelabui agar menjalankan program arbitrerSaya sering melihat shell script yang awalnya hampir persis berupa beberapa baris perintah yang diketik manual berubah menjadi monster lebih dari seratus baris, dan setiap kali itu terjadi saya berharap ada array dan tipe sungguhan, serta fitur batteries included dari Python standard library. Meski begitu, saya tidak akan mengimplementasikan Action build perusahaan dengan elisp
Diekspos lewat metode
ScriptHandlerHelpers.GetScriptArgumentsFormat. DiScriptHandler.csada kode penyiapan environment proses dan argumen, dan kode yang benar-benar memulai proses ada di sini: https://github.com/actions/runner/blob/main/src/Runner.Worke...Secara keseluruhan saya terkejut secara positif dengan kesederhanaan kode ini. Sangat prosedural dan menangani banyak sekali kasus pengecualian, tetapi terlihat mudah dipahami dan di-debug
Sepertinya assembly juga bisa
Namun goeval belum mendukung input file secara langsung dan hanya mendukung standard input, jadi perlu trik shell. Saat ini caranya seperti
go run github.com/dolmen-go/goeval@v1 - <<'EOF' ... EOF, tetapi butuh sedikit boilerplate. Sebagai catatan, saya adalah pembuat goeval[1] https://github.com/dolmen-go/goeval
go run github.com/dolmen-go/goeval@v1 - < file.gobisa?Jika ingin mempromosikan proyek mainan dalam konteks ini, contoh yang lebih relevan daripada “mencetak hello” mungkin bisa menghemat klik
run: pipeline.sh?Job bisa dijalankan serentak di berbagai sistem operasi dan arsitektur CPU, dan Anda juga mendapatkan informasi konteks tentang event yang memicu job serta status repositori. Ini praktis untuk job per PR atau otomasi rilis, dan juga bisa terintegrasi dengan GitHub web UI, misalnya linter menandai masalah per baris di PR atau kegagalan test dirender di halaman web. Cache kecil juga bisa dipakai agar file yang tidak berubah tidak perlu diunduh atau dibangun ulang. Idealnya, sebanyak mungkin hal dimasukkan ke tool umum yang berjalan lokal, sementara konfigurasi GitHub CI hanya menangani glue code yang diperlukan untuk trigger, caching, dan integrasi GitHub
Anda bisa dengan mudah memanfaatkan GitHub Actions buatan orang lain di pipeline, memodularisasi workflow, serta mengendalikan dependency dan eksekusi paralel. Pasti masih ada lagi, tetapi keuntungan utamanya adalah Anda tidak perlu mengimplementasikan semua itu sendiri