4.4.1.1. خروجیهای derivation آدرسدهیشده بر اساس محتوا
آدرسدهی مبتنی بر محتوای یک خروجی، صرفاً به خود آن شیء انبار بستگی دارد، نه به هیچ اطلاعات خارجی دیگری (مانند نحوه ساخت آن، زمان ساخت و غیره). در نتیجه، یک شیء انبار صرفنظر از اینکه بهطور دستی در انبار وارد شده باشد، توسط یک درایویشن خروجی داده شده باشد، یا توسط درایویشن دیگری تولید شده باشد، به همان شکل آدرسدهی مبتنی بر محتوا خواهد شد.
مشخصات خروجی (output spec) برای یک خروجی مبتنی بر محتوا باید شامل فیلد زیر باشد:
- method: نحوه خلاصه شدن (digest) دادههای شیء انبار به یک آدرس مبتنی بر محتوا.
انتخابهای احتمالی برای method در بخش مربوط به اشیاء انبار مبتنی بر محتوا شرح داده شدهاند. با توجه به متد، نام خروجی (که از نام درایویشن و نگاشت مشخصات خروجی همانطور که در بالا توضیح داده شد محاسبه میشود) و دادههای شیء انبار، مسیر انبار خروجی همانطور که در آن بخش توضیح داده شده است، محاسبه خواهد شد.
آدرسدهی مبتنی بر محتوای خروجی ثابت
در این حالت، آدرس مبتنی بر محتوای خروجی ثابت از پیش توسط خود درایویشن تعیین میشود. به عبارت دیگر، هنگامی که درایویشن ساخت را به پایان میرساند، و آدرس مبتنی بر محتوای خروجی موقت به عنوان بخشی از فرآیند تبدیل آن به یک شیء انبار واقعی (bona fide) محاسبه میشود، آدرس مبتنی بر محتوای محاسبهشده باید با آدرس دادهشده در درایویشن مطابقت داشته باشد، در غیر این صورت ساخت آن درایویشن ناموفق تلقی خواهد شد.
مشخصات خروجی برای یک خروجی با آدرسهای مبتنی بر محتوای ثابت همچنین شامل موارد زیر است:
- hash: هش مورد انتظار از خلاصهسازی (digest) اشیاء سیستمفایل شیء انبار. این هش میتواند متعلق به هر الگوریتم هش دلخواهی باشد که Nix از آن پشتیبانی میکند.
نکتهی طراحی
در اصول، مشخصات خروجی میتواند ارجاعاتی را که شیء انبار باید داشته باشد نیز مشخص کند، زیرا ارجاعات و اشیاء سیستمفایل به طور برابر بخشهایی از یک شیء انبار مبتنی بر محتوای واقعی هستند که در آدرسدهی مبتنی بر محتوای آن نقش دارند. با این حال، در حال حاضر این کار انجام نشده است زیرا تمام خروجیهای مبتنی بر محتوای ثابت ملزم به داشتن هیچگونه ارجاعی (از جمله بدون خودارجاعی) نیستند.
همچنین در اصول، بهجای مشخص کردن ارجاعات و دادههای شیء سیستمفایل با هشهای جداگانه، میتوان از یک هش واحد که هر دو را محدود میکند، استفاده کرد. این کار را میتوان با خلاصهٔ (digest) مسیر انبار نهایی، یا بهتر از آن، با هشی که پیش از کوتاه شدن به خلاصهٔ مسیر انبار تبدیل میشود، انجام داد.
این توسعههای احتمالی آینده برای شفافسازی ویژگی هستهای آدرسدهی مبتنی بر محتوای خروجی ثابت گنجانده شدهاند — یعنی اینکه تمام بخشهای خروجی باید به صورت رمزنگاریشده با یک یا چند هش ثابت شوند — که این موضوع جدا از جزئیات طرحهای آدرسدهی مبتنی بر محتوای شیء انبارِ پشتیبانیشده در حال حاضر است.
دلیل منطقی طراحی
هدف از ثابت کردن آدرس مبتنی بر محتوای یک خروجی از پیش چیست؟
به زبان انتزاعی، پاسخ عبارت است از: ناخالصی کنترلشدهٔ دقیق.
بر خلاف یک درایویشن معمولی، فایل اجرایی [سازنده] (builder) یک درایویشن که خروجیهای ثابت تولید میکند، به شبکه دسترسی دارد.
آدرسهای مبتنی بر محتوای تضمینشدهی خروجیها قرار است خطرات ناشی از اعطای این قابلیتها به سازنده را کاهش دهند؛
صرفنظر از اینکه سازنده در طول فرآیند ساخت چه کاری انجام میدهد، نمیتواند روی ساختهای پاییندستی به روشهای پیشبینینشدهای تأثیر بگذارد، زیرا تمام اطلاعاتی که به سمت پاییندست منتقل میکند از طریق خروجیهایی جریان مییابد که آدرسهای مبتنی بر محتوای آنها ثابت شده است.
بهبیان دقیق، هدف از این قابلیت، دریافت دادههای ورودی ثابت مانند کد منبع از شبکه است. برای مثال، خانوادهای از درایویشنهای «دریافت URL» را در نظر بگیرید. این درایویشنها فایلها را از URLهای مشخصشده بارگیری میکنند. برای اطمینان از اینکه فایل بارگیریشده دستکاری نشده است، هر درایویشن باید یک هش رمزنگاریشده از فایل را نیز مشخص کند. برای نمونه،
{
"outputs: {
"out": {
"method": "nar",
"hashAlgo": "sha256",
"hash: "1md7jsfd8pa45z73bz1kszpp01yw6x5ljkjk2hx7wl800any6465",
},
},
"env": {
"url": "http://ftp.gnu.org/pub/gnu/hello/hello-2.1.1.tar.gz"
// ...
},
// ...
} گاهی پیش میآید که URL فایل تغییر میکند،
مثلاً به این دلیل که سرورها بازسازی شدهاند یا دیگر در دسترس نیستند.
در این موارد، ما سپس باید فراخوانی fetchurl را بهروزرسانی کنیم، مثلاً:
"env": {
- "url": "http://ftp.gnu.org/pub/gnu/hello/hello-2.1.1.tar.gz"
+ "url": "ftp://ftp.nluug.nl/pub/gnu/hello/hello-2.1.1.tar.gz"
// ...
}, اگر خروجیهای یک derivation از نوع fetchurl دارای آدرسدهی مبتنی بر ورودی بودند، مسیرهای خروجی آن derivation و تمام derivationهای وابسته به آن تغییر میکردند.
برای نمونه، اگر قرار بود URL توزیع سورس Glibc را در Nixpkgs (بستهای که تقریباً تمام بستههای دیگر در لینوکس به آن وابستهاند) تغییر دهیم، ساختهای مجدد عظیمی مورد نیاز بود.
این موضوع برای تغییری که میدانیم نمیتواند تأثیر واقعی داشته باشد، در حالی که در گراف وابستگی به سمت بالا منتشر میشود، مایه تأسف است.
از سوی دیگر، برای خروجیهای مبتنی بر محتوا (ثابت یا شناور)، مسیر انبار خروجیها تنها به نام، دادهها و method مشخصات خروجیها بستگی دارد.
بقیه derivation برای محاسبه مسیر خروجی نادیده گرفته میشود.
یادداشت تاریخی
آدرسدهی مبتنی بر محتوای ثابت هم امروزه و هم در طول تاریخ از این جهت اهمیت ویژهای دارد که تنها فرم پایدارشدهی آدرسدهی مبتنی بر محتوا است. به همین دلیل است که استدلال بالا آن را در مقابل [آدرسدهی ورودی] قرار میدهد.
آدرسدهی مبتنی بر محتوا (شناور)
هشدار این بخش بخشی از یک ویژگی آزمایشی است.
برای استفاده از این نوع آدرسدهی خروجی، باید ویژگی آزمایشی
ca-derivationsرا فعال کنید. برای نمونه، در nix.conf میتوانید اینگونه اضافه کنید:extra-experimental-features = ca-derivations
با فعال بودن این ویژگی آزمایشی، خروجیهای derivationها همچنین میتوانند بدون تعیینکردنِ ثابت در مشخصات خروجی که آدرس محتوای خروجیها چه باید باشد، آدرسدهی محتوایی (content-addressed) شوند.
خلوص (Purity)
از آنجا که خروجی derivation ثابت نیست (دقیقاً مانند آدرسدهی ورودی)، هیچ قابلیت ناخالص [^purity] به [سازنده (Builder)] داده نمیشود.
نکتهی پیکربندی
بهطور دقیقتری، میزانی که ایزولهسازی (sandboxing) و سلب دسترسیهای ویژه امکانپذیر است، بسته به محیطی که نیکس در آن اجرا میشود، متفاوت است. تنظیمات پیکربندی نیکس نشان میدهند که چه سطحی از ایزولهسازی مورد نیاز یا فعال است. اگر ساختِ derivationها درخواست عدم ایزولهسازی کند که مجاز نیست، با خطا مواجه خواهد شد. ساختِ derivationها همچنین اگر سطح ایزولهسازی مشخصشده در پیکربندی از آنچه در محیط دادهشده امکانپذیر است فراتر رود، با خطا مواجه خواهند شد.
(«محیط»، در اینجا شامل صفاتی مانند سیستمعامل میزبان نیکس، به همراه امتیازات مختص سیستمعامل است که به نیکس اعطا شده است.) به دلیل نحوه کارکرد سیستمعاملهای متداول مانند macOS، لینوکس و غیره، اعطای امتیازات کمتر به سازندهها، به طرز متناقضی ممکن است مستلزم اجرای نیکس با امتیازات بیشتر باشد.)
با این اوصاف، derivationهایی که خروجیهای آدرسدهی محتوایی شناور (floating content-addressed) تولید میکنند، میتوانند سازندگان خود را به عنوان ناخالص اعلام کنند (مانند سازندگان derivationهایی که خروجیهای ثابت تولید میکنند).
این موضوع بهطور موقت به عنوان بخشی از ویژگی آزمایشی impure-derivations پشتیبانی میشود.
توافق بر سر سازگاری (Compatibility negotiation)
هر derivationای که خروجی آدرسدهی محتوایی شناور تولید کند، بهطور ضمنی به ویژگی سیستم ca-derivations نیاز دارد.
این امر مانع از زمانبندی ساخت این derivation روی ماشینی میشود که ویژگی آزمایشی مذکور در آن فعال نیست.
حتی پس از پایدارسازی ویژگی آزمایشی، این امر همچنان مفید است تا امکان استفاده از سازنده راه دور که نسخههای قدیمیتری از نیکس را اجرا میکند، یا پیادهسازیهای جایگزینی که از آدرسدهی محتوایی شناور پشتیبانی نمیکنند، فراهم شود.
قطعیت (Determinism)
در بحث قبلی پیرامون نحوه مدیریت خودارجاعیها هنگام آدرسدهی محتوایی اشیاء انبار، اشاره شد که روشهای تولید اشیاء انبار باید صرفنظر از انتخاب مسیر موقت انبار، قطعی (deterministic) باشند. برای اشیاء انبار تولیدشده از طریق درج دستی در انبار برای ایجاد یک شیء انبار، «روش تولید» یک مفهوم غیررسمی است — از نظر صوری، نیکس هیچ ایدهای ندارد که شیء انبار از کجا آمده است، و آدرسدهی محتوایی برای تضمین این موضوع که derivation بهطور ذاتی در برابر دستکاری مقاوم است، اهمیت حیاتی دارد. اما برای اشیاء انبار تولیدشده توسط derivation، «روش کار کاملاً صوری است» — بالاخره کل هدف derivationها داشتن یک مفهوم صوری از ساخت است. در این صورت، ما میتوانیم این ویژگی غیررسمی را به یک ویژگی صوری ارتقا دهیم.
یک derivation آدرسدهی محتواییِ قطعی باید خروجیهایی با آدرسهای محتوایی یکسان تولید کند:
هر بار که سازنده اجرا میشود
این به آن دلیل است که یا سازنده کاملاً ایزوله شده است، یا به این دلیل که هرگونه ناخالصی باقیمانده که به درون ایزولهساز ساخت نفوذ کند، توسط سازنده نادیده گرفته میشود و تاثیری بر رفتار آن ندارد.
صرفنظر از انتخاب هرگونه مسیر خروجی موقت
مسیرهای موقت انبار باید برای هر خروجی که دارای خودارجاعی است انتخاب شوند. انتخاب مسیر موقت انبار را میتوان یک ناخالصی در نظر گرفت، زیرا یک انتخاب دلخواه است.
اگر مسیرهای فرآوردهٔ ساخت موقت به روشی قطعی انتخاب شوند، ما در شاخهٔ اول از بخش (1) قرار داریم. سازنده (Builder)، دادههایی را که تولید میکند بر اساس آن به شیوههای دلخواه دستکاری میکند، اما این امر ما را به [آدرسدهی ورودی] نزدیکتر میکند. انتخاب قطعی مسیر موقت ممکن است با حذف یک ناخالصی به عنوان «ایزولهسازی کامل (Sandboxed)» در نظر گرفته شود، اما این رضایتبخش نیست
اگر مسیرهای فرآوردهٔ ساخت موقت به طور تصادفی انتخاب شوند، ما در شاخهٔ دوم از بخش (1) قرار داریم. سازنده (Builder) نباید اجازه دهد که ورودی تصادفی روی فرآوردههای نهایی تولیدشده توسط آن تأثیر بگذارد، و ممکن است چندین ساخت انجام شده و با یکدیگر مقایسه شوند تا اطمینان حاصل شود که واقعاً همینطور است.
شناور در برابر ثابت
در حالی که تمایز بین آدرسدهی محتوا و ورودی از جنس مکانیزم است، تمایز بین آدرسدهی محتوای ثابت و شناور بیشتر از جنس سیاست است. یک خروجی ثابت که بررسی آدرس محتوای خود را با موفقیت پشت سر میگذارد، درست مانند یک خروجی شناور است. تنها تفاوت آنها در احتمال شکست خوردن آن بررسی است.
جایی که این بررسی ممکن است با شکست مواجه شود، نقطهٔ تفاوت آنهاست.
یادداشت طراحی
در دنیای آیندهای که در آن آدرسدهی محتوای شناور نیز پایدار باشد، ما اصولاً دیگر نیازی به آدرسدهی محتوای ثابت جداگانه نخواهیم داشت. در عوض، میتوانیم همیشه از آدرسدهی محتوای شناور استفاده کنیم، و به طور جداگانه ادعا کنیم که مقدار دقیق آدرس محتوای یک شیء انبار دادهشده به عنوان یک ورودی (برای یک derivation دیگر) استفاده شود. یک شیء ادعای مستقل از این نوع هنوز پیادهسازی نشده است، اما ایجاد احتمالی آن در issue #11955 پیگیری میشود.
در نسخهٔ فعلی Nix، خروجیهای ثابتی که بررسی هش آنها با شکست مواجه میشود همچنان به عنوان اشیاء معتبر انبار ثبت میشوند، اما به عنوان خروجیهای derivationی که آنها را تولید کرده ثبت نمیشوند. این یک بهینهسازی است به این معنا که اگر هش خروجی اشتباهی در یک derivation مشخص شود، و سپس آن derivation با هش خروجی درست دوباره ایجاد شود، نیازی به ساخت مجدد derivation نیست — که از بارگیری مقادیر زیادی از دادهها به صورت بالقوه برای دو بار جلوگیری میکند. این بهینهسازی پیشدرآمد طراحی ذکرشده در بالا است: اگر ادعای هش خروجی در خارج از خود derivation حذف میشد، Nix علاوه بر اینکه میتوانست آن شیء انبار خروجیدادهشده را مانند امروز ثبت کند، همچنین میتوانست یادداشتی ثبت کند که آن derivation در واقع توانسته است مقداری داده را با موفقیت بارگیری کند. مثلاً برای مثال «fetch URL» در بالا، ثبت چنین یادداشتی به منزلهٔ ثبت این موضوع است که چه دادههایی در زمان بارگیری در URL دادهشده در دسترس هستند. تنها زمانی که Nix متعاقباً بخواهد چیزی را با استفاده از آن کد منبع بارگیریشده (با اصلاح مثال خود) بسازد، مجبور خواهد شد ادعای هش خروجی را بررسی کند، و از این طریق مانع از اقداماتی نظیر ساخت بدافزار آلوده میشود.
به طور خلاصه، Nix کارهای زیر را انجام خواهد داد:
۱. بارگیری موفقیتآمیز دادهها ۲. درج آن دادهها در انبار ۳. مرتبط کردن (احتمالاً با نوعی سیاست انقضا) دادههای بارگیریشده با derivationای که آنها را بارگیری کرده است
اما تنها در صورتی از شیء انبار بارگیریشده در derivationهای بعدی که به این ادعا وابستهاند استفاده میکند که ادعا تأیید شود.
این توسعهٔ احتمالی آینده برای نشان دادن این تمایز گنجانده شده است:
nix.dev/manual/nix/stable/store/derivation/outputs/content-address.html