منبع حقیقت، محتوا، انتشار و رسانه · فصل ۵ — Vault، Transfer و Provenance Round-trip · 172
Presigned Artifact Transfer
محتوا یا media تولید میکند اما provenance، rights، version، approval و release boundary را یک سیستم واحد نمیبیند. موضوع جاری: «Presigned Artifact Transfer». میتواند «Presigned Artifact Transfer» را در یک pipeline محدود با provenance، rights/version و publication gate تعریف کند.
خلاصهٔ درس
محتوا یا media تولید میکند اما provenance، rights، version، approval و release boundary را یک سیستم واحد نمیبیند. موضوع جاری: «Presigned Artifact Transfer».
میتواند «Presigned Artifact Transfer» را در یک pipeline محدود با provenance، rights/version و publication gate تعریف کند.
خروجی این درس
میتواند «Presigned Artifact Transfer» را در یک pipeline محدود با provenance، rights/version و publication gate تعریف کند.
پیشنیازها
1. مسئله: signed URL فقط «لینک دانلود» نیست
فرض کنید reviewer باید artifact ART-77 را برای ۲۰ دقیقه دریافت کند. سرویس یک GET signed URL میسازد، URL کامل را داخل debug log مینویسد، expected digest را ثبت نمیکند و signer از credential موقتی استفاده میکند که هشت دقیقهی دیگر منقضی میشود. اگر فقط بگوییم «لینک ۲۰ دقیقهای ساخته شد»، سه چیز را با هم قاطی کردهایم: capability دسترسی، هویت artifact و اثبات bytes دریافتی. CON-020 این سه را جدا میکند.
2. مرز مالکیت CON-020
این درس مالک grant و receipt verification برای انتقال presigned است. نگهداری و durability متعلق به CON-019 است؛ handoff انسانی و provenance round-trip متعلق به CON-021. اینجا نه retention policy میسازیم، نه از روی یک URL هویت recipient را اثبات میکنیم و نه HTTP 2xx را بهتنهایی completion مینامیم.
3. Grant را از Artifact Identity جدا کنید
یک transfer record باید هم artifact مورد انتظار را مشخص کند و هم capability انتقال را. artifact_id, expected_digest, expected_size هویت/انتظار محتوا را میبندند؛ operation, http_method, resource_locator, object_key, signer scope و expiry شکل request مجاز را میبندند. URL بهخودیخود digest artifact نیست.
4. Signed URL یک capability حساس است
Google Cloud Storage signed URL را دسترسی زمانمحدود به resource مشخص میداند و هر کسی که URL فعال را در اختیار داشته باشد میتواند request مجاز را انجام دهد، حتی بدون account. بنابراین در MAKNOW، URL کامل باید مثل capability secret رفتار شود: در log عمومی، ticket، analytics و screenshot بیمحافظ ثبت نشود؛ audit record فقط fingerprint/redacted form لازم را نگه میدارد.
5. Method و Resource بخشی از قرارداد هستند
Grant برای GET را permission عمومی روی object تلقی نکنید. request باید با operation و HTTP method و resource/object key مورد انتظار همخوان باشد. اگر transfer به PUT تغییر کرد، grant باید برای همان shape بازسازی شود. استفاده از grant GET برای PUT، حتی روی همان object name، یک binding failure است.
6. Signed Headers و Content-Type را جدی بگیرید
در uploadها ممکن است headerهای امضاشده یا content-type constraint جزو canonical request باشند. client نباید header لازم را حذف یا مقدار متفاوت بفرستد و بعد خطا را «مشکل storage» بنامد. record باید signed_headers و content_type_constraint را نگه دارد تا mismatch قابل تشخیص و audit باشد.
7. Expiry اسمی همیشه Effective Validity نیست
AWS S3 صریحاً میگوید presigned URL ساختهشده با temporary credentials نمیتواند از credential زیرین بیشتر معتبر بماند؛ revoke/delete/deactivate شدن credential هم میتواند URL را قبل از expiry تنظیمشده از کار بیندازد. بنابراین expires_at را با effective_valid_until یکی نگیرید. اگر credential هشت دقیقهی دیگر منقضی میشود، URL «۲۰ دقیقهای» را ۲۰ دقیقه تضمین نکنید.
8. Capability Rotation باید State را تغییر دهد
اگر signing key/credential rotate یا revoke شود، grant قدیمی باید INVALIDATED یا معادل typed آن شود. ساخت grant جدید نباید باعث شود old URL هنوز در workflow بهعنوان valid دیده شود. audit record باید grant generation و invalidation را جدا ثبت کند و هر request را به grant مشخص bind کند.
9. Expected Digest و Size قبل از Transfer مهماند
قبل از download/upload، اگر artifact مورد انتظار معلوم است، expected_digest و expected_size را ثبت کنید. بدون آنها receiver نمیتواند ثابت کند bytes رسیده همان artifact مورد انتظار بوده است. filename، object key یا 200 OK جای digest را نمیگیرد.
10. RFC 9530 چه چیزی میدهد و چه چیزی نمیدهد
RFC 9530 Content-Digest و Repr-Digest را برای integrity محتوای HTTP/representation تعریف میکند و صریحاً authentication، authorization یا privacy را تعریف نمیکند. Digest میتواند evidence integrity باشد؛ اما ثابت نمیکند چه انسانی دریافتکننده بوده، rights چه بوده یا artifact برای publication تأیید شده است.
11. Transport Success را از Verification جدا کنید
request_completed_at و http_result=200/2xx فقط میگویند transport طبق آن request نتیجهای داده است. state نباید مستقیم از 2xx به VERIFIED برود. receiver باید received_digest و received_size را محاسبه/خوانده و با expectation مقایسه کند؛ mismatch یعنی FAIL/BLOCK حتی وقتی HTTP success بوده است.
12. Receipt، Closure قابل ممیزی میسازد
receipt_id باید grant مشخص، artifact expectation، transport result و verification result را به هم وصل کند. receipt خوب اجازه میدهد بعداً بفهمیم کدام bytes، با کدام grant، در چه زمانی و با چه verificationی دریافت/ذخیره شدهاند. receipt بدون digest verification نباید completion قویتر از UNVERIFIED بدهد.
13. Stateهای منفی را پنهان نکنید
EXPIRED, INVALIDATED, LEAKED, UNBOUND, FAILED, UNVERIFIED, DEFER و BLOCK هرکدام معنای متفاوت دارند. URL لورفته با digest صحیح یک مشکل امنیتی است؛ digest mismatch با URL محرمانه یک integrity failure است؛ expected digest غایب یک evidence gap است. یک status کلی سبز این تفاوتها را نابود میکند.
14. Lab: Presigned Transfer Grant & Receipt Verification Record v1
در lab://CON-020/CON020-LAB1 هشت fixture مصنوعی دارید: baseline صحیح، credential که قبل از expiry اسمی منقضی میشود، URL لورفته، 2xx با digest اشتباه، expected digest غایب، method mismatch، signed-header/content-type mismatch و سناریوی GET→PUT همراه rotation. برای هر case هشت خروجی state/decision تولید میکنید؛ oracle داخلی 64 assertion قطعی دارد.
15. Transfer: GET را به PUT تغییر دهید، old grant را باطل کنید، receipt را verify کنید
در سناریوی انتقال، artifact جایگزین با PUT ارسال میشود. content-type و expected digest باید bind شوند و credential پیش از expiry اسمی rotate میشود. old GET grant دیگر قابل اتکا نیست. حتی وقتی PUT موفق است، state تا زمانی که receiver stored object را با digest و size مورد انتظار verify نکرده، UNVERIFIED میماند. اینجا «upload موفق» با «artifact تأییدشده» یکی نیست.
منابع رسمی و مرز ادعا
- Google Cloud Storage — Signed URLs:
https://docs.cloud.google.com/storage/docs/access-control/signed-urls - Amazon S3 — Presigned URLs:
https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-presigned-url.html - RFC 9530 — Digest Fields:
https://www.rfc-editor.org/rfc/rfc9530.html
K1 تا K3 واقعیتهای منبعیاند که در 2026-09-17 دوباره بررسی شدند. K4 — اینکه MAKNOW completion را فقط بعد از receipt-side digest/size verification به VERIFIED ببرد — قاعدهی طراحی MAKNOW است و بهعنوان الزام Google، AWS یا RFC 9530 معرفی نمیشود.
ارزیابی
پاسخنامهی این درس در بستهی آموزش وجود ندارد؛ خودت جواب بده و صادقانه علامت بزن. «نیاز به مرور» درس را به صف تکرار میفرستد.
CON-020-Q1 boundary
Why must a presigned URL grant be represented separately from the expected artifact identity?
CON-020-Q2 application
A URL has a nominal 20-minute expiry but its temporary signing credential expires in 8 minutes. What validity may the transfer record claim?
CON-020-Q3 diagnosis
HTTP 200 returns bytes whose digest differs from the expected artifact. Which state must remain non-success and why?
CON-020-Q4 security
The transfer succeeds but the full signed URL was written to an ordinary debug log. What evidence/decision changes?
CON-020-Q5 transfer
Rebuild the contract when GET becomes PUT, Content-Type is constrained, signer credentials rotate, and stored-object verification has not yet completed.
ملاکهای ارزیابی (rubric)
A sufficient artifact:
- separates artifact identity/evidence from the presigned grant;
- binds operation, HTTP method, resource/object key, nominal expiry and effective credential validity;
- treats the complete signed URL as sensitive capability state and records a redaction rule;
- records signed-header/content-type/checksum constraints when present;
- preserves credential expiry/revocation/rotation as typed invalidation rather than overclaiming URL lifetime;
- separates HTTP transport result from digest/size verification;
- blocks or defers when expected digest is missing, bytes mismatch, request shape is unbound, or capability secrecy is violated;
- identifies Google/AWS/RFC facts separately from MAKNOW's transfer state-machine design;
- rebuilds the changed GET→PUT context without copying the first decision.
منابع و تازگی
مطالعهٔ موارد (case studies)
تصاویر درس
فایلهای آزمایشگاه
Run python run_checks.py for learner-visible structural checks. Implement or inspect starter.py so each fixture yields explicit grant/request/transport/verification states. Fixtures are synthetic; no URLs are live, no credentials exist, and no network call is required.
The learner task is to keep eight dimensions separate: effective validity, grant state, capability-secret state, request binding, transport state, verification state, receipt state, and bounded decision. Never infer VERIFIED from URL issuance or HTTP 2xx.