4 पॉइंट द्वारा GN⁺ 2025-04-09 | 2 टिप्पणियां | WhatsApp पर शेयर करें
  • 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 टिप्पणियां

 
tujuc 2025-04-09

github/runner-image रेपो को ही देखें तो काफ़ी सारे ऐसे पैकेज पहले से इंस्टॉल मिलते हैं जिन्हें सीधे इस्तेमाल किया जा सकता है....

इमेज बनाते ही आराम से 1GB तो चला ही जाता है....

 
GN⁺ 2025-04-09
Hacker News की राय
  • Actions workflow में bash से चलने वाली हर command को print कराने के लिए मैंने पहले -x flag इस्तेमाल किया था, और यह debugging में काफी मददगार होता है
    https://github.com/jstrieb/just.sh/blob/2da1e2a3bfb51d583be0...
    • संदर्भ के लिए, pipefail चालू करने पर अगर pipe में से कोई एक fail हो जाए तो step fail हो जाता है, लेकिन error output नहीं होता, इसलिए यह पता नहीं चल सकता कि fail क्यों हुआ
      pipefail ज्यादा जटिल error states को भी नहीं रोकता। उदाहरण के लिए, setup के curl ... | sudo tar ... step में tar extraction failure, sudo failure, shell error जैसी चीजें दिख जाती हैं, लेकिन अगर curl network error की वजह से बीच में fail हो जाए, तो tar just binary को आधा ही unpack करके छोड़ सकता है और shell तुरंत exit हो सकता है। ऐसे में कोई error message नहीं होता, और corrupted executable disk पर रह जाता है; अगर failure skipping चालू हो तो उसे run करने की कोशिश भी हो सकती है
  • काम पर देखा गया एक शानदार private GitHub Actions trick यह है कि repository_dispatch event 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 चल रहा है
    • उत्सुकता है कि यह centralized approach असल में अच्छी तरह काम करता है या नहीं। क्या organization हर चीज को बिल्कुल एक ही तरीके से build करने की मांग करता है?
      मैं अभी-अभी एक ऐसे organization में शामिल हुआ हूं जो कुछ ऐसा ही करना चाहता है, लेकिन व्यवहार में यह लगभग बेकार लगता है। templates अक्सर टूट जाते हैं, और कई बार वे बिना documentation के किसी खास build method को assume करके लिखे होते हैं कि code किस तरीके से build होना चाहिए
  • मेरा मानना है कि GitHub Actions के अंदर जितना कम काम किया जाए, उतना बेहतर है
    आम तौर पर Make जैसे build system में logic रखना और GitHub Actions से सिर्फ उसे call करना, या कोई छोटा command-line program लिखकर उसे call करना मुझे पसंद है। ऐसी चीजों को CI की तुलना में local पर debug करना कहीं आसान होता है। यह interesting trick जरूर है, लेकिन यह कहां useful होगी, यह साफ नहीं है
    • हमारा workflow असल में बस make build और make test जैसा ही है
      acquisition के बाद acquiring company की workflow file देखी तो वह सैकड़ों lines की थी और उसमें बहुत repetition भी था। चाहें तो इसे old-fashioned कह लें, लेकिन YAML village से मैं जितनी जल्दी हो सके बाहर निकलना चाहता हूं
    • यह लेख ऐसा नहीं लगता कि author लोगों को यह करने की सलाह दे रहा है; बल्कि यह बताने के लिए है कि यह possible है
      किसी feature को इस्तेमाल करने का plan न भी हो, तब भी system में क्या possible है यह जानना security और debugging के लिए useful होता है
    • मेरी interpretation में यह useful नहीं है, और निश्चित रूप से useful नहीं है। हालांकि इसमें potential security risk है
      खासकर self-hosted runner को “explore” करते समय
  • हमारी generation से जब लगातार बदलती spreadsheets को code में बदलने को कहा जाता था, तो हम डर जाते थे
    अगली generation तब डरेगी जब उनसे GitHub Actions से बने deployment में discipline लाने को कहा जाएगा
    • मैं अभी एक बड़े enterprise को GH Actions पर migrate करने का काम कर रहा हूं; ज्यादा सटीक रूप से कहें तो यह “git से बंधी YAML-based pipelines” जैसा है। यहां discipline कैसा दिखना चाहिए?
      अगर आप समझा सकें, तो शायद हम इसे अपने organization में लागू कर पाएंगे
    • मुझे समझ नहीं आता कि इसमें discipline की कमी क्यों मानी जा रही है
  • default shell bash को धोखा देकर arbitrary program चलवाया भी जा सकता है
  • अगर Action पढ़ने वाले दूसरे लोग जानते हों कि क्या हो रहा है, तो यह काफी useful लगता है
    कई बार कुछ manually typed commands की lines को लगभग जस का तस ले जाकर शुरू किया गया shell script सौ lines से ज्यादा का monster बन जाता है, और हर बार लगता है कि काश असली arrays और types, और Python standard library की batteries included सुविधाएं होतीं। फिर भी मैं company build Action को elisp में implement नहीं करूंगा
  • Github Actions Runner code काफी readable है। popular shells/binaries के default arguments जहां define हैं, वह यहां है: https://github.com/actions/runner/blob/main/src/Runner.Worke...
    यह ScriptHandlerHelpers.GetScriptArgumentsFormat method के जरिए 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 करने में आसान लगता है
  • अब आखिरकार production CI/CD में C इस्तेमाल करके उसे “low-level systems work” कहा जा सकेगा
    assembly भी संभव लगती है
  • इसे देखकर उम्मीद होती है कि goeval [1] का इस्तेमाल करके GitHub workflow YAML file में Go code को CI job के रूप में सीधे run करना आसान हो सकता है
    हालांकि 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
    • समझ नहीं आता कि shell “trick” की जरूरत क्यों है। क्या go run github.com/dolmen-go/goeval@v1 - < file.go से काम नहीं हो जाएगा?
    • मैं repository में जाकर देखने वाला था कि क्या यह spaces को tabs में automatically convert करने वाला program है, लेकिन देखने पर लगा कि यह one-line expressions के लिए ज्यादा tuned है
      इस context में toy project को promote करना हो तो “hello print करना” से ज्यादा relevant example दिखाते, तो मेरा click बच सकता था
  • GitHub CI YAML में run: pipeline.sh जैसे bash script की तुलना में बेहतर क्या है?
    • automatically managed GitHub API token होता है, जो release automation, artifacts और containers publish करने में useful है
      कई 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 UI में हर step का overview देखकर, step-wise output को expand या collapse करके जांचा जा सकता है
      दूसरे लोगों द्वारा बनाए गए GitHub Actions को pipeline में आसानी से use किया जा सकता है, workflows को modularize किया जा सकता है, और dependencies तथा parallel execution control किए जा सकते हैं। और भी फायदे होंगे, लेकिन core benefit यह है कि ये सब खुद implement नहीं करना पड़ता
    • GitHub के नजरिए से फायदा यह है कि users के किसी दूसरी Git forge पर migrate करने की संभावना कम हो जाती है