سینتکس $/ در GitHub Actions؛ اکشن داخلی را امن و بدون checkout صدا بزنید

سینتکس $/ در GitHub Actions؛ اکشن داخلی را امن و بدون checkout صدا بزنید

GitHub در 30 ژوئیه 2026 سینتکس تازه ای برای فراخوانی Actionها و reusable workflowهای همان مخزن معرفی کرد. در این راهنما می بینید $/ دقیقاً به چه چیزی resolve می شود، چرا مشکل pin کردن SHA را حل می کند، کجا جایگزین ./ است و چگونه بدون شکستن pipeline آن را وارد مخزن کنید.

سینتکس self-repository در GitHub Actions چیست؟

در فایل workflow، کلید uses معمولاً به یکی از سه مقصد اشاره می کند: یک Action عمومی با قالب owner/repo/path@ref، یک Action داخل workspace با مسیر نسبی ./path، یا یک reusable workflow در مخزنی مشخص. سینتکس جدید یک حالت چهارم و دقیق تر اضافه می کند: $/path. علامت دلار در اینجا به معنای «مخزن خود workflow» است؛ GitHub مسیر را در snapshot همان commitی پیدا می کند که اجرای فعلی از آن آغاز شده است.

این تفاوت ظاهراً کوچک، مفهوم مهمی دارد. resolve شدن Action از workspace جدا می شود. در روش ./ فایل باید ابتدا با actions/checkout وارد workspace شده باشد. در روش $/ پلتفرم می داند کد داخلی را از کدام repository و کدام commit بردارد؛ بنابراین برای پیدا کردن definition اکشن، checkout شرط لازم نیست. البته اگر خود اکشن به فایل های پروژه نیاز دارد، checkout همچنان ممکن است برای منطق آن اکشن لازم باشد.

GitHub اعلام کرده این روش در تمام موقعیت هایی که مسیر workspace-relative قابل استفاده بود کار می کند: step عادی workflow، step داخل composite action، composition تو در تو و فراخوانی reusable workflow. بنابراین قابلیت فقط یک shortcut برای یک سناریوی ساده نیست؛ می تواند الگوی استاندارد monorepoهایی شود که مجموعه ای از Actionهای داخلی و workflowهای قابل استفاده مجدد دارند.

چرا روش قبلی دردسرساز بود؟

وابستگی پنهان به checkout

در بسیاری از workflowها یک step شبیه uses: ./github/actions/setup دیده می شود. این خط بدون checkout قبلی کار نمی کند، زیرا Runner مسیر را در workspace جست وجو می کند. نتیجه این است که حتی jobهایی که به source code نیاز ندارند، فقط برای resolve کردن یک Action داخلی مجبور به checkout هستند. این کار زمان، I/O و سطح دسترسی workflow را افزایش می دهد و ترتیب stepها را به یک قرارداد نانوشته تبدیل می کند.

شکستن یکپارچگی commit

راه دیگر این بود که Action داخلی با نام کامل مخزن و یک branch یا tag نوشته شود؛ مثلاً acme/app/.github/actions/setup@main. این الگو ممکن است workflow اصلی را از commit A اجرا کند اما Action داخلی را از وضعیت جدیدتر branch main بگیرد. در چنین شرایطی اجرای CI دیگر یک snapshot اتمیک از repository نیست. تغییر مستقل Action می تواند نتیجه pipeline یک commit قدیمی را عوض کند و بازتولید خطا را سخت تر سازد.

حتی اگر به جای branch از SHA استفاده شود، نگهداری دشوار است. هر commit جدید باید SHAهای ارجاع داخلی را نیز به روزرسانی کند؛ سپس همین تغییر SHA یک commit تازه می سازد. تیم ها معمولاً برای فرار از این دور، به branch یا tag متغیر برمی گردند و عملاً مزیت pinning کامل را از دست می دهند. self-repository reference این حلقه را حذف می کند، چون مرجع داخلی به ref اجرای فعلی متصل است.

سینتکس جدید با نمونه های عملی

نمونه پایه زیر یک composite action را از پوشه داخلی همان مخزن فراخوانی می کند. دقت کنید برای resolve کردن Action، step مربوط به checkout وجود ندارد. این نمونه زمانی مناسب است که Action صرفاً از inputها، ابزارهای نصب شده روی Runner یا APIها استفاده می کند و به فایل های repository نیاز ندارد.

name: validate
on:
  pull_request:

jobs:
  checks:
    runs-on: ubuntu-latest
    steps:
      - name: Run repository policy checks
        uses: $/.github/actions/policy-check
        with:
          strict: "true"

اگر Action داخلی به فایل هایی مانند package.json یا source code دسترسی دارد، checkout را حذف نکنید؛ فقط وابستگی resolve شدن Action را از آن جدا کنید. الگوی درست این است که checkout را به دلیل نیاز بیزینسی job نگه دارید، نه به عنوان پیش شرط تصادفی برای پیدا شدن definition اکشن.

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@<FULL_COMMIT_SHA>
      - uses: $/.github/actions/setup-node-project
      - run: npm test

برای reusable workflow نیز مفهوم یکسان است. به جای تکرار نام repository و ref، مسیر از $/ آغاز می شود. در نتیجه caller و workflow فراخوانی شده از یک commit واحد می آیند. این رفتار برای release branchها و اجرای workflow روی pull request ارزشمند است، زیرا نسخه helper دقیقاً با تغییرات همان branch هماهنگ می ماند.

jobs:
  security-scan:
    uses: $/.github/workflows/reusable-security-scan.yml
    with:
      severity-threshold: high
    secrets: inherit
روشنیاز به checkout برای resolveمرجع نسخهریسک drift
./pathبلهفایل موجود در workspaceکم، اما وابسته به checkout
owner/repo/path@mainخیرbranch متغیربالا؛ ممکن است با commit اجرا متفاوت باشد
owner/repo/path@SHAخیرSHA ثابت دستیکم، اما نگهداری دشوار
$/pathخیرهمان commit اجرای workflowکم و بدون به روزرسانی دستی

اثر امنیتی: pinning واقعی برای اکشن های داخلی

در امنیت زنجیره تأمین CI/CD، هدف pinning این است که کد اجراشده قابل پیش بینی و قابل بازبینی باشد. سازمان ها معمولاً Actionهای خارجی را به full-length commit SHA محدود می کنند، اما Actionهای داخلی یک استثنای آزاردهنده بودند. اگر workflow به branch همان repository اشاره کند، policy ظاهراً رعایت می شود اما محتوای helper می تواند بدون تغییر caller جابه جا شود. سینتکس $/ internal composition را به commit جاری قفل می کند و GitHub نیز آن را با policy سازمانی الزام full SHA سازگار کرده است.

مزیت امنیتی اصلی این نیست که «checkout بد است»؛ مزیت این است که تمام اجزای داخلی workflow از یک snapshot واحد و قابل ممیزی اجرا می شوند.

این قابلیت جایگزین کنترل های دیگر نیست. Action داخلی هنوز می تواند permission بیش ازحد، اجرای shell ناامن، استفاده نامطمئن از inputهای pull request یا secret leakage داشته باشد. همچنین Actionهای خارجی همچنان باید با SHA معتبر pin شوند. $/ یک مسئله مشخص یعنی هم نسخه بودن اجزای داخلی را حل می کند؛ نه اینکه کل workflow را خودکار امن کند.

راهنمای مهاجرت مرحله ای

  1. Runnerها را بررسی کنید: self-repository syntax به Runner نسخه 2.336.0 یا جدیدتر نیاز دارد. برای GitHub-hosted runner معمولاً مدیریت نسخه با GitHub است؛ برای self-hosted runner inventory و upgrade plan لازم دارید.
  2. ارجاع های داخلی را پیدا کنید: در پوشه .github/workflows و Actionهای composite به دنبال uses: ./ و ارجاع به نام همان repository بگردید.
  3. نیاز واقعی به checkout را تفکیک کنید: اگر checkout فقط برای resolve اکشن داخلی است، حذف آن را آزمایش کنید. اگر build یا test به فایل ها نیاز دارد، checkout باقی بماند.
  4. ابتدا یک workflow کم ریسک را تبدیل کنید: workflow lint یا validation گزینه خوبی است. نتیجه، artifactها و permissionها را با اجرای قبلی مقایسه کنید.
  5. branch protection را در نظر بگیرید: تغییر workflow می تواند status checkهای required را تحت تأثیر قرار دهد؛ نام jobها را بی دلیل عوض نکنید.
  6. policy و مستندات داخلی را به روزرسانی کنید: در templateها و راهنمای contribution اعلام کنید که $/ روش پیش فرض composition داخلی است.

برای مهاجرت گروهی می توان یک جست وجوی ساده انجام داد، اما replacement کور توصیه نمی شود. ./ ممکن است در contextهایی به فایل محلی پس از checkout اشاره کند و هر استفاده الزاماً Action داخلی نیست. تغییر باید با درک ساختار هر job انجام شود. همچنین ارجاع کامل به همان repository شاید عمداً نسخه دیگری را هدف گرفته باشد؛ برای مثال workflow انتشار ممکن است یک Action تثبیت شده در branch مخصوص automation را بخواند. این موارد را به عنوان استثنا مستند کنید.

چک لیست Pull Request مهاجرت

  • Runner self-hosted حداقل نسخه 2.336.0 دارد.
  • هر $/ به مسیر موجود در همان commit اشاره می کند.
  • checkout فقط در jobهایی حذف شده که به فایل های repository نیاز ندارند.
  • Actionهای خارجی همچنان به full commit SHA pin شده اند.
  • permissionهای job و workflow کاهش یا دست کم ثابت مانده اند.
  • اجرای pull request، push، tag و reusable callerهای اصلی آزمایش شده اند.
  • نام checkهای required و خروجی artifactها تغییر ناخواسته نکرده است.

محدودیت ها و خطاهای رایج

اولین محدودیت نسخه Runner است. اگر self-hosted fleet ناهمگون باشد، workflow روی برخی ماشین ها موفق و روی برخی دیگر fail می شود. پیش از rollout سراسری، version label یا گروه Runner مشخص بسازید. دوم اینکه قابلیت فعلاً برای github.com اعلام شده است؛ در محیط های GitHub Enterprise Server باید release notes همان نسخه سرور را جداگانه بررسی کرد و نباید در دسترس بودن آن را فرض گرفت.

خطای رایج دیگر برداشت اشتباه از «بدون checkout» است. GitHub فقط می گوید resolve کردن Action یا workflow داخلی به checkout نیاز ندارد. اگر script داخل Action فرمانی روی repository اجرا کند، نبود workspace باعث شکست خواهد شد. این رفتار را با یک Action کوچک آزمایش کنید و قرارداد ورودی آن را روشن بنویسید: آیا Action به repository، git history، submodule یا فایل generated نیاز دارد؟

همچنین $/ برای اشتراک Action بین چند repository طراحی نشده است. اگر چند مخزن باید یک Action مرکزی را مصرف کنند، repository اختصاصی automation با full SHA، release process و Dependabot یا ابزار مشابه همچنان الگوی مناسب تری است. self-repository syntax بهترین پاسخ برای composition داخل یک repository است، نه جایگزین معماری reusable components سازمانی.

سناریوپیشنهاد
Action فقط API یا inputها را مصرف می کند$/ و احتمالاً حذف checkout
Action روی source code کار می کند$/ همراه checkout
Action بین چند repository مشترک استمخزن مرکزی و pin به full SHA
Runner self-hosted قدیمی استابتدا ارتقای Runner، سپس مهاجرت
نیاز عمدی به نسخه متفاوت همان مخزن داریدارجاع صریح و مستندسازی استثنا

پرسش های متداول

آیا $/ جای actions/checkout را می گیرد؟

فقط برای پیدا کردن Action یا reusable workflow داخلی. اگر job یا خود Action به فایل های repository نیاز دارد، checkout همچنان لازم است.

این سینتکس به کدام commit اشاره می کند؟

به دقیقاً همان commitی که workflow فعلی از آن اجرا می شود؛ بنابراین اجزای داخلی با caller هم نسخه می مانند.

آیا در composite action هم کار می کند؟

بله. GitHub استفاده در workflow steps، composite action steps، ترکیب تو در تو و reusable workflow calls را اعلام کرده است.

حداقل نسخه Runner چیست؟

نسخه 2.336.0 یا جدیدتر. این موضوع برای self-hosted runnerها باید به صورت عملی کنترل شود.

آیا استفاده از $/ کل workflow را امن می کند؟

خیر. این قابلیت drift نسخه داخلی را کاهش می دهد؛ permission، secrets، trigger، shell injection و Actionهای خارجی همچنان نیازمند ممیزی هستند.

آیا برای GitHub Enterprise Server هم در دسترس است؟

اعلام رسمی مربوط به github.com است. برای GHES باید release notes نسخه سرور بررسی شود.

جمع بندی

سینتکس $/ یک تغییر کوچک اما معماری محور در GitHub Actions است. این روش Actionها و reusable workflowهای همان repository را به commit اجرای فعلی متصل می کند، نیاز تصادفی به checkout را برمی دارد و policy pinning را برای composition داخلی قابل اجرا می سازد. بهترین مسیر، مهاجرت مرحله ای است: ابتدا Runnerها، سپس ارجاع های داخلی، بعد حذف checkoutهای غیرضروری و در پایان ممیزی permissionها.

جزئیات قابلیت و محدودیت نسخه Runner در اعلام رسمی GitHub درباره self-repository syntax منتشر شده است. برای تیم هایی که workflowهای زیادی دارند، ارزش اصلی این تغییر در کاهش drift و ساده شدن بازتولید اجرای CI است؛ نه صرفاً کوتاه تر شدن YAML.

مطالب پیشنهادی

معماری جدید cdnjs روی Cloudflare؛ درس های مهاجرت یک CDN با 9 میلیارد درخواست روزانه

معماری جدید cdnjs روی Cloudflare؛ درس های مهاجرت یک CDN با 9 میلیارد درخواست روزانه

تحلیل معماری مهاجرت cdnjs به Cloudflare؛ R2، KV، Workflows، Queues، Containers، fallback چندلایه و درس های انتقال بدون شکستن SRI و محتوای immutable.

Azure SQL Developer؛ اجرای موتور واقعی Azure SQL روی Docker برای توسعه محلی

Azure SQL Developer؛ اجرای موتور واقعی Azure SQL روی Docker برای توسعه محلی

راهنمای Azure SQL Developer در Docker؛ تفاوت با SQL Server و LocalDB، نصب، اتصال EF Core، اجرای integration test، قابلیت های Vector و محدودیت های Preview.

Chrome 152 Beta برای توسعه دهندگان؛ تغییرات CSS، APIها و موارد نیازمند مهاجرت

Chrome 152 Beta برای توسعه دهندگان؛ تغییرات CSS، APIها و موارد نیازمند مهاجرت

تحلیل Chrome 152 Beta برای توسعه دهندگان؛ قابلیت های CSS و Web API، تغییر اعلان PWA، CPU Performance، Connection Allowlist و برنامه مهاجرت XSLT.

آسیب پذیری بحرانی WordPress 7.0.2؛ راهنمای Patch و بررسی نفوذ

آسیب پذیری بحرانی WordPress 7.0.2؛ راهنمای Patch و بررسی نفوذ

راهنمای فوری WordPress 7.0.2 برای رفع SQL Injection و RCE بحرانی؛ نسخه های امن، Patch با WP-CLI، کنترل WAF، تأیید Checksum و چک لیست بررسی نفوذ.