اگر codex sandbox با پیام bwrap: execvp .../bin/codex: No such file or directory از کار می‌افتد، فایل اجرایی کدکس خراب نیست. سندباکس روی لینوکس یک ریشه‌ی تازه می‌سازد و فقط مسیرهایی را در آن می‌بیند که پروفایل مجوز اعلام کرده است. در این نوشته با کدکس 0.158.0 و bubblewrap 0.9.0 نشان می‌دهم دقیقا کدام سطر پروفایل این خطا را می‌سازد، با یک کنترل منفی ثابت می‌کنم که فایل روی دیسک هست و فقط در ریشه‌ی سندباکس نیست، و در پایان نشان می‌دهم چرا یک اسکریپت که فقط به کد خروج نگاه می‌کند، نوشتن به بیرون از پوشه‌ی کاری را موفقیت می‌شمارد.

نشانه چیست و چه چیزی را نمی‌گوید

خطایی که کدکس روی لینوکس می‌دهد یک سطر است و هیچ نامی از پروفایل مجوز در آن نیست:

$ codex sandbox echo hi
bwrap: execvp /root/.hermes/tools/node-26.7.0-linux-x64/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-x64/vendor/x86_64-unknown-linux-musl/bin/codex: No such file or directory
rc=1

سه برداشت غلط را باید کنار گذاشت. اول اینکه فایل پاک شده یا نصب ناقص است؛ دوم اینکه bubblewrap خراب است؛ سوم اینکه مسیر اشتباه نوشته شده. هر سه را در همین اجرا می‌شود رد کرد. همان دودویی بیرون از سندباکس بدون هیچ پروفایلی اجرا می‌شود:

$ V=/root/.hermes/tools/node-26.7.0-linux-x64/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-x64/vendor/x86_64-unknown-linux-musl/bin/codex
$ file "$V" | sed 's/,.*//'
ELF 64-bit LSB pie executable x86-64 version 1 (SYSV) static-pie linked stripped
$ ldd "$V"
	statically linked
$ "$V" --version
codex-cli 0.158.0
$ bwrap --version
bubblewrap 0.9.0

پس فایل وجود دارد، معماری‌اش با این ماشین می‌خواند و خودش سالم است. آنچه باقی می‌ماند این است که execvp داخل ریشه‌ی تازه اجرا می‌شود و آنجا فایلی با این نام وجود ندارد. یعنی خطا درباره‌ی نام فایل است، نه درباره‌ی سلامت آن.

این را مستقیم از bubblewrap می‌شود آزمود. همان دودویی، زیر یک ریشه‌ی دستی که فقط /usr و /bin را دارد، ناپیدا می‌شود؛ و با یک bind خواندنی روی /root برمی‌گردد:

$ bwrap --ro-bind /usr /usr --ro-bind /bin /bin --proc /proc --dev /dev --tmpfs /tmp \
    "$V" --version
bwrap: execvp $V: No such file or directory

$ bwrap --ro-bind /usr /usr --ro-bind /bin /bin --ro-bind /root /root --proc /proc --dev /dev --tmpfs /tmp \
    "$V" --version
WARNING: proceeding, even though we could not create PATH aliases: Read-only file system (os error 30)
codex-cli 0.158.0

کنترل منفی هم لازم است، وگرنه این نتیجه فقط یک مشاهده‌ی خوش‌بینانه است. یک دودویی که واقعا وجود ندارد، خطای متفاوتی می‌دهد و مسیر خودش را نام می‌برد:

$ codex sandbox -p tools /no/such/binary-xyz

thread 'main' (2) panicked at linux-sandbox/src/linux_run_main.rs:1598:5:
Failed to execvp /no/such/binary-xyz: No such file or directory (os error 2)

همان No such file or directory، اما با Failed to execvp و با مسیری که شما در فرمان نوشته بودید. پس آن پیام اول درباره‌ی جایی است که کدکس خودش را در آن پیدا نمی‌کند، نه درباره‌ی فرمان شما.

ریشه‌ی تازه از کجا می‌آید

روی لینوکس، codex sandbox یک فرایند تازه زیر bubblewrap بالا می‌آورد و ریشه‌ی فایل‌سیستم آن را از روی پروفایل مجوز می‌سازد. مستندات پروفایل‌های مجوز این مدل را صریح می‌گویند: یک پروفایل، جدولی از قواعد فایل‌سیستم است که تعیین می‌کند فرمان‌ها چه چیزی را بخوانند و کجا بنویسند.

دو بخش را باید جدا کرد. workspace_roots مسیرهایی را نام می‌برد که پروفایل به آن‌ها اجازه می‌دهد، و جدول filesystem تعیین می‌کند با هرکدام چه شود: read، write یا deny. کلید :minimal مجموعه‌ی حداقلی لازم برای اجرای فرمان است. یک پروفایل می‌تواند از :read-only یا :workspace ارث ببرد، اما نمی‌تواند از :danger-full-access ارث ببرد.

همین ساختار توضیح می‌دهد چرا خطا رخ می‌دهد. پروفایل حداقلی فقط :minimal را می‌بیند، و مسیر نصب npm در آن نیست، پس نقطه‌ی ورود کدکس در ریشه‌ی تازه وجود ندارد و execvp شکست می‌خورد.

پروفایل‌ها از کجا خوانده می‌شوند هم مهم است. کدکس فایل‌های لایه‌ای را از CODEX_HOME می‌خواند، یعنی به‌طور پیش‌فرض ~/.codex، و پرچم -p یک لایه‌ی <name>.config.toml را روی پایه سوار می‌کند. آزمایش این را جدا کرد: با CODEX_HOME روی یک پوشه‌ی آزمایشی، فرمان بالا می‌آید؛ با همان فرمان و CODEX_HOME پیش‌فرض که پرونده‌ی لایه‌ای با آن نام ندارد، خطا برمی‌گردد.

رفع خطا با یک ریشه‌ی خواندنی

راه‌حل، اعلام صریح مسیر نصب به‌عنوان یک ریشه‌ی خواندنی است. دو پروفایل زیر را کنار هم می‌گذاریم؛ تنها فرقشان آن چهار خط است.

# CODEX_HOME را به پوشه‌ای آزمایشی ببرید تا تنظیمات واقعی دست‌نخورده بماند
export CODEX_HOME=/tmp/cx-lab
mkdir -p "$CODEX_HOME"

# پروفایل الف: فقط ریشه‌ی حداقلی
cat > "$CODEX_HOME/minimal.config.toml" <<'EOF'
default_permissions = "demo"

[permissions.demo]
description = "فقط ریشه‌ی حداقلی، بدون ریشه‌ی کاری"

[permissions.demo.filesystem]
":minimal" = "read"
EOF

# پروفایل ب: همان، اما مسیر نصب کدکس صریحا یک ریشه‌ی خواندنی است
cat > "$CODEX_HOME/tools.config.toml" <<'EOF'
default_permissions = "demo"

[permissions.demo]
description = "ریشه‌ی نصب کدکس صریحا خواندنی"

[permissions.demo.workspace_roots]
"/root/.hermes/tools" = true

[permissions.demo.filesystem]
":minimal" = "read"
":workspace_roots" = "read"
EOF

حالا همان فرمان را با هر دو پروفایل اجرا می‌کنیم. این تنها تفاوت دو خط بعدی است و هر دو خروجی واقعی‌اند:

$ codex sandbox -p minimal echo hi
bwrap: execvp .../vendor/x86_64-unknown-linux-musl/bin/codex: No such file or directory
rc=1

$ codex sandbox -p tools echo hi
hi
rc=0

تفسیر همین یک سطر hi ساده است: با پروفایل ب، کدکس توانست فرایند را در ریشه‌ی تازه بالا بیاورد و فرمان اجرا شد؛ با پروفایل الف، اصلا فرایندی ساخته نشد. برای اطمینان بیشتر می‌توان مسیر نصب را به پوشه‌ای روی دیسک مانند /usr/local/lib هم برد؛ در آزمایش ما نسخه‌ی کپی‌شده آنجا بدون هیچ پروفایلی هم کار کرد، چون آن مسیر در ریشه‌ی حداقلی هست. اما این راه با به‌روزرسانی بعدی دوباره می‌شکند؛ راه درست اعلام ریشه است.

ریشه‌ی تازه چه چیزی را می‌بیند

پس از آنکه سندباکس بالا آمد، فهرست مسیرها را از داخل خودش می‌سنجیم. این جدول از یک اجرای واقعی با پروفایل ب است:

مسیرنتیجه
/usr/bin/envدیده می‌شود
/etc/sslدیده می‌شود
/root/.hermes/toolsدیده می‌شود، چون اعلام شده
/root/.hermesدیده می‌شود، چون والدِ ریشه‌ی اعلام‌شده هم هست
/rootدیده می‌شود
/tmpنیست

سطر آخر معنادار است: /tmp که روی میزبان وجود دارد، در ریشه‌ی سندباکس نیست. برای کنترل، پروفایلی دیگر ساختیم که فقط :minimal را می‌دهد؛ در آن پروفایل حتی /root/.hermes/tools هم ناپیدا بود. پس دیده‌شدن این مسیرها اثر مستقیم همان workspace_roots است و نه یک حدس. دیده‌شدن یک مسیر به معنی دسترسی نوشتن به آن نیست، و تضمین هم نمی‌کند نوشتن در آن روی میزبان بنشیند؛ بخش بعد همین را اندازه می‌گیرد.

نوشتن: جایی که پروفایل ساکت می‌ماند

این مهم‌ترین یافته‌ی این نوشته است. با پروفایل ب دو نوشتن می‌زنیم. یکی داخل ریشه‌ی فقط‌خواندنی، و یکی در مسیری که اعلام نشده ولی در ریشه دیده می‌شود.

$ codex sandbox -p tools sh -c 'echo x > /root/.hermes/tools/demo.txt'
sh: 1: cannot create /root/.hermes/tools/demo.txt: Read-only file system
rc=2

$ codex sandbox -p tools sh -c 'echo y > /root/.hermes/ovl.txt; cat /root/.hermes/ovl.txt'
y
rc=0

$ ls -l /root/.hermes/tools/demo.txt /root/.hermes/ovl.txt
ls: cannot access '/root/.hermes/tools/demo.txt': No such file or directory
ls: cannot access '/root/.hermes/ovl.txt': No such file or directory

دو نتیجه را جدا بخوانید. نوشتن در ریشه‌ی فقط‌خواندنی با خطا و کد خروج 2 رد می‌شود، که رفتار درستی است. نوشتن در مسیر اعلام‌نشده اما موفق می‌شود، کد خروج صفر می‌گیرد، فایل در همان فراخوانی قابل خواندن است، و پس از پایان سندباکس روی میزبان هیچ اثری نمی‌گذارد.

آن فایل در یک لایه‌ی رویی نوشته می‌شود: داخل همان فراخوانی خوانده می‌شود و بیرون از آن نیست. پس نتیجه‌ی عملی این است که فقط به کد خروج نگاه نکنید. اگر می‌خواهید بدانید یک فرمان واقعا روی دیسک شما نوشته شده، پس از پایان سندباکس وجود فایل را روی میزبان بررسی کنید، نه داخل همان نشست.

کدام پروفایل را انتخاب کنیم

چهار پروفایل را روی همین ماشین سنجیدیم و نتیجه فقط در یک چیز فرق داشت: اینکه نقطه‌ی ورود کدکس در ریشه‌ی سندباکس دیده شود یا نه.

پروفایلسندباکس بالا می‌آید؟/root/.hermes/tools
فقط :minimalنهناپیدا
:minimal به‌علاوه‌ی :homeنهناپیدا
extends = ":workspace"بلهدیده می‌شود
workspace_roots روی مسیر نصببلهدیده می‌شود

ردیف دوم ارزش دیدن دارد: اضافه‌کردن :home به‌عنوان ریشه‌ی خواندنی، خطا را درست نکرد. چون پوشه‌ی .codex اینجا داخل /root است و پروفایل فقط یک جدول مسیر را به ریشه اضافه می‌کند؛ نام مستعار جای مسیر واقعی را نمی‌گیرد.

اگر کدکس را با npm نصب کرده‌اید، راه تمیز دیگری دارید: نسخه‌ی مستقل را با نصب‌کننده‌ی رسمی بگذارید که در مسیر سیستمی می‌نشیند. صفحه‌ی نصب Codex CLI چهار روش می‌دهد؛ آن که به مسیر سیستمی می‌رود، بدون تغییر پروفایل کار می‌کند.

سه دستور برای وقتی که دوباره شکست خورد

این ترتیب کار را کوتاه می‌کند. اول ببینید فایل واقعا هست یا نه، بعد ببینید بیرون از سندباکس اجرا می‌شود یا نه، و تازه بعد سراغ پروفایل بروید.

$ V=$(dirname "$(readlink -f "$(command -v codex)")")/../node_modules/@openai/codex-linux-x64/vendor/x86_64-unknown-linux-musl/bin/codex
$ ls -l "$V" && "$V" --version
codex-cli 0.158.0
$ CODEX_HOME=/tmp/cx-lab codex sandbox -p tools echo ok
ok
$ codex sandbox --help | sed -n '1,4p'
Run commands within a Codex-provided sandbox

Usage: codex sandbox [OPTIONS] [COMMAND]...

اگر سطر اول و دوم درست بود و سوم شکست خورد، مشکل از پروفایل است، نه از نصب. اگر سطر اول شکست خورد، اول نصب را درست کنید. اگر پیام خطا Failed to execvp داشت و مسیر خودتان را نام می‌برد، مسیر فرمان اشتباه است و ربطی به پروفایل ندارد.

برای دیدن قواعد امنیتی پیش‌فرض کدکس، صفحه‌ی تأییدها و امنیت ایجنت‌ها را بخوانید: به‌طور پیش‌فرض شبکه خاموش است و دسترسی نوشتن به پوشه‌ی کاری محدود می‌شود. یادداشت‌های انتشار bubblewrap هم نشان می‌دهد نسخه‌ی 0.11.2 یک به‌روزرسانی امنیتی برای CVE-2026-41163 است؛ روی ماشینی که ما آزمودیم 0.9.0 نصب بود. برای دیدن اینکه آخرین نسخه‌ی پایدار کدکس کدام است، فهرست انتشارهای کدکس و نقشه‌ی مستندات رسمی کافی است.

اگر قبلا یک لایه‌ی مجوز دیگر ساخته بودید، راهنمای پروفایل مجوز کدکس همان لایه را از سمت مجوز توضیح می‌دهد. اگر تازه‌کار هستید و می‌خواهید اول یک لایه‌ی کوچک بسازید، اسکن خط فرمان codex-security یک نمونه‌ی کامل‌تر از پیکربندی دارد.

منابع

  1. پروفایل‌های مجوز کدکس — workspace_roots، جدول filesystem و ارث‌بری از پروفایل‌های پایه؛ خوانده‌شده در ۶ اکتبر ۲۰۲۶
  2. نصب و اجرای Codex CLI — چهار روش نصب؛ خوانده‌شده در ۶ اکتبر ۲۰۲۶
  3. تأییدها و امنیت ایجنت‌ها — شبکه‌ی خاموش پیش‌فرض و حالت workspace-write؛ خوانده‌شده در ۶ اکتبر ۲۰۲۶
  4. یادداشت‌های انتشار bubblewrap — نسخه‌ی 0.11.2 و CVE-2026-41163؛ خوانده‌شده در ۶ اکتبر ۲۰۲۶
  5. انتشارهای کدکس — آخرین نسخه‌ی پایدار و شماره‌ی نسخه‌های آلفا؛ خوانده‌شده در ۶ اکتبر ۲۰۲۶
  6. نقشه‌ی مستندات کدکس — فهرست صفحه‌های رسمی؛ خوانده‌شده در ۶ اکتبر ۲۰۲۶