- GitHub Actions का
shell एक setting है जो तय करती है कि run: block कैसे execute होगा, लेकिन असल में यह तय shells की सूची तक सीमित नहीं है; यह $PATH में मौजूद executable files को भी target कर सकता है
- workflows में यह optional है, action definitions में required है, और default value runner के अनुसार बदलती है, जैसे Linux/macOS पर
bash और Windows पर pwsh
shell: bash जैसा स्पष्ट रूप से लिखने पर GitHub bash --noprofile --norc -eo pipefail जैसे extra flags जोड़ता है, लेकिन execute होने वाला target खुद कोई भी arbitrary program हो सकता है
- अगर executable single file input नहीं लेता, तो
shell value में {0} argument डालना होगा; GitHub इसे run block वाले temporary file path से replace करता है
bash जैसे परिचित नाम भी $PATH से resolve होते हैं, इसलिए $GITHUB_PATH में बदलाव या fake executable बाद के steps के execution तरीके को प्रभावित कर सकते हैं
shell keyword का basic behavior
- GitHub Actions का
shell keyword यह specify करता है कि किसी खास run: block को किस shell से execute करना है
- workflows में यह optional है, लेकिन action definitions में इसे required रूप से use किया जाता है
- default shell runner environment के अनुसार तय होता है
- Linux और macOS में आमतौर पर
bash
- Windows में आमतौर पर
pwsh
explicit shell specification और extra flags
- GitHub
defaults.run.shell docs में बताता है कि shell को explicit रूप से specify करने पर GitHub चुने हुए flags भी साथ में apply करता है
- उदाहरण के लिए,
shell: bash specify करने पर execution form इस तरह हो जाता है
bash --noprofile --norc -eo pipefail
- सिर्फ इस behavior को देखकर यह सोचना आसान है कि GitHub valid shell values की सीमित सूची maintain करता है और सिर्फ उन्हीं values पर special flags जोड़ता है
$PATH की arbitrary executable file भी shell बन सकती है
- असल में
shell में $PATH में मौजूद कोई भी arbitrary executable file specify की जा सकती है
- GitHub specified executable से
run block execute करता है
- अगर वह command single file input सीधे नहीं लेती, तो
shell value में {0} pass करना होगा
- GitHub
{0} को temporary file path से बदल देता है
- इस temporary file में template-expanded
run block content होता है
C को step runner के रूप में use करने का example
- C compiler/interpreter की तरह काम करने वाले tools भी GitHub Actions step execution के लिए use किए जा सकते हैं
shell के रूप में tcc -run {0} specify करने वाला example ठीक से काम करता है
- run: sudo apt install -y tcc
- shell: tcc -run {0}
run: |
#include <stdio.h>
int main() {
printf("Hello, world!\n");
return 0;
}
$GITHUB_PATH से shell resolution बदलने का example
$GITHUB_PATH से $PATH को dynamically modify करने पर, बाद में shell: bash expected executable से अलग किसी file को point कर सकता है
- example current directory में
bash नाम की executable file बनाता है और current directory को $GITHUB_PATH में add करता है
- इसके बाद
shell: bash use करने पर GitHub $PATH में मिली fake bash execute कर सकता है
- 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
security के लिहाज से उम्मीद से अलग पहलू
- यह behavior security के लिहाज से महत्वपूर्ण है या नहीं, यह पक्का कहना मुश्किल है
- GitHub Actions में file writing से execution तक जाने वाले रास्ते पहले से ही कई हैं, और
GITHUB_ENV भी ऐसे cases में शामिल है
- हालांकि GitHub का
bash जैसे well-known shell values के लिए भी $PATH lookup करना उम्मीद से अलग हो सकता है
- खासकर अगर well-known shell value के आधार पर command-line flags inject किए जाते हैं, तो उम्मीद हो सकती है कि
bash को /bin/bash जैसे specific path पर fixed किया जाएगा
- ज्यादा generally, यह भी सोचा जा सकता है कि GitHub सिर्फ tool cache में pre-registered tools को allow करता होगा, लेकिन observed behavior
$PATH की executable files use करने वाला है
2 टिप्पणियां
github/runner-image रेपो को ही देखें तो काफ़ी सारे ऐसे पैकेज पहले से इंस्टॉल मिलते हैं जिन्हें सीधे इस्तेमाल किया जा सकता है....
इमेज बनाते ही आराम से 1GB तो चला ही जाता है....
Hacker News की राय
-xflag इस्तेमाल किया था, और यह debugging में काफी मददगार होता हैhttps://github.com/jstrieb/just.sh/blob/2da1e2a3bfb51d583be0...
pipefail ज्यादा जटिल error states को भी नहीं रोकता। उदाहरण के लिए, setup के
curl ... | sudo tar ...step मेंtarextraction failure,sudofailure, shell error जैसी चीजें दिख जाती हैं, लेकिन अगरcurlnetwork error की वजह से बीच में fail हो जाए, तोtarjustbinary को आधा ही unpack करके छोड़ सकता है और shell तुरंत exit हो सकता है। ऐसे में कोई error message नहीं होता, और corrupted executable disk पर रह जाता है; अगर failure skipping चालू हो तो उसे run करने की कोशिश भी हो सकती हैrepository_dispatchevent name में wildcard इस्तेमाल करके match किया जा सकता हैइसे
on: repository_dispatch: - security_scan - security_scan::*की तरह लिखा जा सकता है। release pipeline को centralize करने पर हर repository को defined reusable workflow से गुजरने के लिए मजबूर किया जा सकता है, औरsecurity_scan::$product_name::$versionजैसे event भेजने पर central release repository के Actions tab में यह समझना काफी आसान हो जाता है कि किस product और version का workflow चल रहा हैमैं अभी-अभी एक ऐसे organization में शामिल हुआ हूं जो कुछ ऐसा ही करना चाहता है, लेकिन व्यवहार में यह लगभग बेकार लगता है। templates अक्सर टूट जाते हैं, और कई बार वे बिना documentation के किसी खास build method को assume करके लिखे होते हैं कि code किस तरीके से build होना चाहिए
आम तौर पर Make जैसे build system में logic रखना और GitHub Actions से सिर्फ उसे call करना, या कोई छोटा command-line program लिखकर उसे call करना मुझे पसंद है। ऐसी चीजों को CI की तुलना में local पर debug करना कहीं आसान होता है। यह interesting trick जरूर है, लेकिन यह कहां useful होगी, यह साफ नहीं है
make buildऔरmake testजैसा ही हैacquisition के बाद acquiring company की workflow file देखी तो वह सैकड़ों lines की थी और उसमें बहुत repetition भी था। चाहें तो इसे old-fashioned कह लें, लेकिन YAML village से मैं जितनी जल्दी हो सके बाहर निकलना चाहता हूं
किसी feature को इस्तेमाल करने का plan न भी हो, तब भी system में क्या possible है यह जानना security और debugging के लिए useful होता है
खासकर self-hosted runner को “explore” करते समय
अगली generation तब डरेगी जब उनसे GitHub Actions से बने deployment में discipline लाने को कहा जाएगा
अगर आप समझा सकें, तो शायद हम इसे अपने organization में लागू कर पाएंगे
bashको धोखा देकर arbitrary program चलवाया भी जा सकता हैकई बार कुछ manually typed commands की lines को लगभग जस का तस ले जाकर शुरू किया गया shell script सौ lines से ज्यादा का monster बन जाता है, और हर बार लगता है कि काश असली arrays और types, और Python standard library की batteries included सुविधाएं होतीं। फिर भी मैं company build Action को elisp में implement नहीं करूंगा
यह
ScriptHandlerHelpers.GetScriptArgumentsFormatmethod के जरिए expose होता है।ScriptHandler.csमें process environment और arguments तैयार करने वाला code है, और actual process start code यहां है: https://github.com/actions/runner/blob/main/src/Runner.Worke...कुल मिलाकर इस code की simplicity ने मुझे अच्छे अर्थ में surprised किया। यह बहुत procedural है और बहुत सारे edge cases handle करता है, लेकिन समझने और debug करने में आसान लगता है
assembly भी संभव लगती है
हालांकि goeval अभी file input को सीधे support नहीं करता और सिर्फ standard input support करता है, इसलिए shell trick चाहिए। अभी तरीका
go run github.com/dolmen-go/goeval@v1 - <<'EOF' ... EOFजैसा है, जिसमें थोड़ा boilerplate चाहिए। संदर्भ के लिए, मैं goeval का author हूं[1] https://github.com/dolmen-go/goeval
go run github.com/dolmen-go/goeval@v1 - < file.goसे काम नहीं हो जाएगा?इस context में toy project को promote करना हो तो “hello print करना” से ज्यादा relevant example दिखाते, तो मेरा click बच सकता था
run: pipeline.shजैसे bash script की तुलना में बेहतर क्या है?कई operating systems और CPU architectures पर jobs parallel में चलाए जा सकते हैं, और job trigger करने वाले event तथा repository state के बारे में context information भी मिलती है। PR-specific jobs या release automation के लिए convenient है, और linter PR की हर line पर problems दिखा सकता है या test failure को web page पर render कर सकता है—इस तरह GitHub web UI के साथ भी integration possible है। unchanged files को फिर से download या rebuild न करना पड़े, इसके लिए छोटा cache भी इस्तेमाल किया जा सकता है। Ideally, जितना हो सके उतना logic local पर चलने वाले सामान्य tools में रखना चाहिए, और GitHub CI configuration को केवल triggers, caching और GitHub integration के लिए जरूरी glue code संभालने देना चाहिए
दूसरे लोगों द्वारा बनाए गए GitHub Actions को pipeline में आसानी से use किया जा सकता है, workflows को modularize किया जा सकता है, और dependencies तथा parallel execution control किए जा सकते हैं। और भी फायदे होंगे, लेकिन core benefit यह है कि ये सब खुद implement नहीं करना पड़ता