سینتکس $/ در GitHub Actions؛ اکشن داخلی را امن و بدون checkout صدا بزنید
GitHub در 30 ژوئیه 2026 سینتکس تازه ای برای فراخوانی Actionها و reusable workflowهای همان مخزن معرفی کرد. در این راهنما می بینید $/ دقیقاً به چه چیزی resolve می شود، چرا مشکل pin کردن SHA را حل می کند، کجا جایگزین ./ است و چگونه بدون شکستن pipeline آن را وارد مخزن کنید.
uses: که با $/ آغاز شود، به همان مخزن و دقیقاً همان commit در حال اجرا اشاره می کند. برای resolve شدن اکشن داخلی به checkout نیاز ندارد، در stepهای workflow، composite action، ترکیب تو در تو و reusable workflow کار می کند و به Runner نسخه 2.336.0 یا جدیدتر نیاز دارد.سینتکس 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 را خودکار امن کند.
GITHUB_TOKEN، triggerها، secrets و shell interpolation را جداگانه ممیزی کنید.راهنمای مهاجرت مرحله ای
- Runnerها را بررسی کنید: self-repository syntax به Runner نسخه 2.336.0 یا جدیدتر نیاز دارد. برای GitHub-hosted runner معمولاً مدیریت نسخه با GitHub است؛ برای self-hosted runner inventory و upgrade plan لازم دارید.
- ارجاع های داخلی را پیدا کنید: در پوشه
.github/workflowsو Actionهای composite به دنبالuses: ./و ارجاع به نام همان repository بگردید. - نیاز واقعی به checkout را تفکیک کنید: اگر checkout فقط برای resolve اکشن داخلی است، حذف آن را آزمایش کنید. اگر build یا test به فایل ها نیاز دارد، checkout باقی بماند.
- ابتدا یک workflow کم ریسک را تبدیل کنید: workflow lint یا validation گزینه خوبی است. نتیجه، artifactها و permissionها را با اجرای قبلی مقایسه کنید.
- branch protection را در نظر بگیرید: تغییر workflow می تواند status checkهای required را تحت تأثیر قرار دهد؛ نام jobها را بی دلیل عوض نکنید.
- 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.