دسکتاپ، Worker و محاسبات محلی · فصل ۱ — Device Identity، Tauri، Tray و Admin CLI · 175
Tauri Native Boundary و Command Mediation
اپ یا worker محلی را اجرا میکند اما device identity، privilege، offline state و fleet behavior را طراحی نکرده است. موضوع جاری: «Tauri Native Boundary و Command Mediation». میتواند «Tauri Native Boundary و Command Mediation» را برای یک node محلی با identity، state، privilege و recovery boundary مناسب طراحی کند.
خلاصهٔ درس
اپ یا worker محلی را اجرا میکند اما device identity، privilege، offline state و fleet behavior را طراحی نکرده است. موضوع جاری: «Tauri Native Boundary و Command Mediation».
میتواند «Tauri Native Boundary و Command Mediation» را برای یک node محلی با identity، state، privilege و recovery boundary مناسب طراحی کند.
خروجی این درس
میتواند «Tauri Native Boundary و Command Mediation» را برای یک node محلی با identity، state، privilege و recovery boundary مناسب طراحی کند.
پیشنیازها
1. مسئله: یک Command عمومی، مرز اعتماد را محو میکند
فرض کنید UI دسکتاپ سه کار Native دارد: وضعیت worker را بخواند، credential محلی را بچرخاند و restart کنترلشده بخواهد. اگر همهچیز را داخل admin_action(name, payload) بریزید، نام عملیات، ورودی، مجوز، Scope منبع، اثر Native و Audit در یک تونل مبهم جمع میشوند. این راحتی کوتاهمدت است اما بعداً جواب دادن به یک سؤال ساده سخت میشود: «این WebView دقیقاً مجاز بود کدام اثر Native را با کدام ورودی و برای کدام node ایجاد کند؟» هدف LOC-002 حذف همین ابهام است.
2. مرز مالکیت LOC-002
این درس Command mediation را مالک است، نه Capability/CSP را. LOC-003 تعیین میکند کدام Window/WebView به کدام Permission/Scope Tauri دسترسی داشته باشد؛ LOC-002 میپرسد وقتی Invoke مجاز به Command رسید، خود Command چگونه باریک، نوعدار، محدود و قابل Audit بماند. همچنین Human Identity یا Device Identity کامل را در این درس اثبات نمیکنیم. Actor ID و Node ID فقط باید به Evidence معتبر قبلی متصل شوند و از UI حدس زده نشوند.
3. مکانیک واقعی Command در Tauri
در Tauri v2 یک تابع Rust با #[tauri::command] به Command تبدیل میشود، در Builder داخل invoke_handler(tauri::generate_handler![...]) ثبت میشود و Frontend آن را با invoke(...) صدا میزند. آرگومانها باید قابل Deserialize و خروجیها قابل Serialize باشند. این مکانیک مهم است، اما فقط «قابل فراخوانی بودن» را توضیح میدهد؛ ثبت شدن یک تابع بهتنهایی Domain Authorization یا امن بودن معنایی ورودی را ثابت نمیکند.
4. Runtime Authority قبل از Command چه میکند؟
Runtime Authority در Tauri قبل از رسیدن درخواست به Command بررسی میکند Origin اجازه استفاده از Command را دارد یا نه و Capability/Permission/Scope قابلاعمال را لحاظ میکند. اگر Origin مجاز نباشد، Command اجرا نمیشود. این یک مرز ضروری است، ولی مرز نهایی برنامه نیست. مثلاً ممکن است Window مجاز به rotate_local_credential باشد اما Actor فعلی در سیاست MAKNOW اجازه Rotation روی node-42 را نداشته باشد؛ آن تصمیم داخل قرارداد دامنهای شما باقی میماند.
5. یک عملیات حساس = یک Command باریک
بهجای admin_action(name, payload) سه Command مشخص بسازید: inspect_worker_status, rotate_local_credential, request_controlled_restart. نام Command باید Intent و Side-effect class را روشن کند. هر Command فقط ورودیهای خودش را میپذیرد و منابعی را لمس میکند که برای همان Use Case لازم است. اگر بعداً عملیات چهارمی اضافه شد، یک Command چهارم تعریف کنید؛ Scope را با Action string توسعه ندهید.
6. ورودی Type-safe کافی نیست؛ Semantic Validation هم لازم است
String بودن node_id فقط نوع را میسنجد. هنوز باید بررسی کنید Node واقعاً در Scope Actor است، Credential version معتبر و مورد انتظار است، Reason از مقادیر مجاز میآید و Path یا Key از Boundary مجاز بیرون نمیزند. بنابراین دو سطح دارید: Schema validation و Semantic/domain validation. خطای هر سطح باید کد مشخص داشته باشد، نه اینکه همهچیز به false یا یک متن مبهم تبدیل شود.
7. Domain Authorization را با Tauri Permission یکی نکنید
Tauri Permission میتواند بگوید Frontend اجازه دسترسی به یک Command یا Scope فنی را دارد. Domain Authorization باید بگوید Actor/Node/Policy فعلی اجازه همین عملیات کسبوکاری را دارد یا نه. این دو میتوانند همزمان درست یا غلط باشند. PASS فقط وقتی قابل دفاع است که Runtime Authority، ورودی، Domain Authorization و Resource Scope همگی برای همان درخواست بسته باشند.
8. Resource Scope را داخل Command دوباره محدود کنید
عملیات Native نباید Path، Process، Credential target یا Cache key آزاد بگیرد. اگر rotate_local_credential فقط credential/node-42/* را مالک است، credential/global/root باید BLOCK شود حتی اگر Permission فنی Tauri بهطور گستردهتری اجازه رسیدن به Command را داده باشد. Scope دامنهای نزدیک اثر Native قرار میگیرد تا خطای تنظیمات بالادستی به یک Escape hatch تبدیل نشود.
9. Managed State را Authority فرض نکنید
Tauri میتواند State مدیریتشده را به Command تزریق کند و این برای Repository، Session، Cache یا Policy snapshot مفید است. اما وجود State<T> خودش صحت یا تازگی آن State را ثابت نمیکند. Command باید بداند State از کجا آمده، Freshness آن چیست و چه حالتهایی مثل STALE، REVOKED یا UNBOUND باید به DENIED/DEFER تبدیل شوند. State یک dependency است؛ Proof نیست.
10. State-changing Command بدون Idempotency خطرناک است
UI ممکن است دوبار کلیک کند، Promise timeout شود یا Retry بعد از reconnect اتفاق بیفتد. اگر Rotation یا Restart با هر Invoke دوباره اثر ایجاد کند، Side effect تکثیر میشود. برای عملیات تغییردهنده، request_id و idempotency_key را به Actor/Node/Operation ببندید. اگر همان Key قبلاً با همان Content-bound request اجرا شده، پاسخ قبلی را Traceable replay کنید و اثر جدید نسازید.
11. Audit باید نتیجه و عدمنتیجه را ثبت کند
Audit فقط برای PASS نیست. DENIED بهخاطر Runtime Authority، BLOCK بهخاطر Scope، DEFER بهخاطر Unknown policy و Idempotent replay هم باید قابل Trace باشند. حداقل Request ID، Actor ID، Node ID، Command name، Side-effect class، Decision، Error/Reason و Audit event ID را ثبت کنید. از ثبت secret خام یا payload حساس خودداری کنید؛ Audit باید قابل بررسی باشد بدون اینکه خودش نشت داده بسازد.
12. Failure example: «Capability اجازه داد، پس امن است»
فرض کنید rotate_local_credential از Window اصلی قابل Invoke است. Input هم از نظر نوع معتبر است، اما domain_authorized=false. نتیجه نباید PASS شود؛ DENIED / DOMAIN_AUTHORIZATION_DENIED درست است. Tauri موفق شده مرز فریمورک را اعمال کند، اما سیاست برنامه هنوز اجازه اثر Native را نداده است. این دقیقاً تفاوت «قابل فراخوانی» و «مجاز برای این Actor/Node» است.
13. Failure example: Path خارج از Scope
درخواست Rotation برای credential/global/root میآید، در حالی که Command فقط credential/node-42/ را مالک است. حتی با Origin، Capability و Permission مجاز و ورودی Type-correct، Decision باید BLOCK / RESOURCE_SCOPE_EXCEEDED باشد. هیچ Fallback به Dispatcher عمومی یا Path آزاد مجاز نیست. اگر Use Case واقعاً جدید است، Contract جدید و review جدید لازم است.
14. Lab: Tauri Command Boundary & Mediation Contract v1
در lab://LOC-002/LOC002-LAB1 هشت Fixture مصنوعی دارید. باید برای هر Case مرز Command، Runtime Authority، Input validation، Resource scope، Idempotency، Auditability و Decision را بسازید. Oracle در Learner root نیست. تستها شامل Happy path، Dispatcher عمومی، Runtime denial، ورودی نامعتبر، Domain denial، Scope expansion، Authority نامعلوم و Transfer با حذف stale cache هستند. هدف حفظ حالتهای PASS/BLOCK/DENIED/DEFER است، نه رسیدن اجباری به PASS.
15. Transfer: حذف فقط Stale Cache بدون بازگشت Dispatcher
عملیات چهارم delete_stale_cache_entry را اضافه کنید. Command فقط Cache keyهای cache/stale/ را میپذیرد، باید stale=true را اعتبارسنجی کند، Domain Authorization مستقل داشته باشد و برای Side effect از Idempotency key استفاده کند. اگر همان Request دوباره رسید، پاسخ قبلی را بدون Effect دوم برگردانید. اگر UI تلاش کرد Scope را به cache/live/ یا Path دیگری گسترش دهد، BLOCK و Audit کنید. خروجی شما باید نشان دهد که توسعه قابلیت، Native Boundary را پهن نکرده است.
منابع رسمی و مرز ادعا
- Tauri v2 — Calling Rust from the Frontend:
https://v2.tauri.app/develop/calling-rust/ - Tauri v2 — Runtime Authority:
https://v2.tauri.app/security/runtime-authority/
K1 و K2 واقعیتهای فریمورک Tauri هستند و در 2026-09-17 دوباره بررسی شدهاند. K3 (Commandهای باریک) و K4 (Idempotency/Audit binding) قواعد طراحی MAKNOW هستند و بهعنوان الزام رسمی Tauri معرفی نمیشوند.
ارزیابی
پاسخنامهی این درس در بستهی آموزش وجود ندارد؛ خودت جواب بده و صادقانه علامت بزن. «نیاز به مرور» درس را به صف تکرار میفرستد.
LOC-002-Q1 boundary
LOC-002-Q2 negative
LOC-002-Q3 reliability
LOC-002-Q4 transfer
ملاکهای ارزیابی (rubric)
- Boundary: explicit command boundary; adjacent Capability/CSP scope remains outside LOC-002.
- Evidence binding: runtime authority, domain authorization, actor/node/request and resource scope are not conflated.
- Negative states: DENIED/BLOCK/DEFER remain typed and are not converted to success.
- Reliability: state-changing operations have content-bound idempotency and auditable replay behavior.
- Transfer: the stale-cache operation becomes a fourth narrow command, not a widened generic dispatcher.
منابع و تازگی
مطالعهٔ موارد (case studies)
تصاویر درس
فایلهای آزمایشگاه
This is an offline synthetic lab. Implement evaluate_case in starter.py and use the supplied fixtures to build a bounded command-mediation matrix.
Keep these layers separate:
- Tauri runtime-authority exposure (origin/capability/permission),
- explicit command registration and typed input validation,
- MAKNOW domain authorization and bounded resource scope,
- idempotency/audit behavior for state-changing operations.
Run python run_checks.py for learner-visible structural checks. The evaluation oracle is intentionally not in the learner root. Do not use real credentials, production paths, privileged OS changes, or external targets.