منبع حقیقت، محتوا، انتشار و رسانه · فصل ۵ — Vault، Transfer و Provenance Round-trip · 172

Presigned Artifact Transfer

Design a presigned artifact-transfer contract that separates grant creation from artifact identity, binds operation/resource/expiry and expected content evidence, treats possession of the signed URL as sensitive capability state, and closes transfer only after recipient-side digest/size verification rather than URL issuance or HTTP success alone. می‌تواند «Presigned Artifact Transfer» را در یک pipeline محدود با provenance، rights/version و publication gate تعریف کند.

Presigned Artifact Transfer — fa-IR

Lesson summary

Design a presigned artifact-transfer contract that separates grant creation from artifact identity, binds operation/resource/expiry and expected content evidence, treats possession of the signed URL as sensitive capability state, and closes transfer only after recipient-side digest/size verification rather than URL issuance or HTTP success alone.

می‌تواند «Presigned Artifact Transfer» را در یک pipeline محدود با provenance، rights/version و publication gate تعریف کند.

This lesson produces

می‌تواند «Presigned Artifact Transfer» را در یک pipeline محدود با provenance، rights/version و publication gate تعریف کند.

Who it is for

Foundation

Use a guided lesson-specific evidence matrix and one worked negative case.

Repair

Re-run only the failed owned dimension with a smaller deterministic synthetic fixture.

Experienced

Start from mixed authority/policy/evidence records; require explicit trade-offs and provenance.

Prerequisites

1. The problem: a signed URL is not just a file link

Assume a reviewer needs artifact ART-77 for twenty minutes. The service creates a GET signed URL, writes the full URL into a debug log, omits the expected digest, and signs with temporary credentials that expire in eight minutes. Saying “a 20-minute link was created” collapses three different things: an access capability, artifact identity, and proof of the bytes received. CON-020 separates them.

2. The owned CON-020 boundary

This lesson owns the presigned grant and receipt-verification boundary. Retention and durability belong to CON-019; human handoff and provenance round-trip belong to CON-021. We do not redesign vault retention, infer a recipient's human identity from a URL, or call HTTP 2xx sufficient completion.

3. Separate the grant from artifact identity

A transfer record must describe both the expected artifact and the access capability. artifact_id, expected_digest, and expected_size bind content expectation; operation, http_method, resource_locator, object_key, signer scope, and expiry bind the authorized request shape. A URL is not itself the artifact digest.

4. Treat the signed URL as a sensitive capability

Google Cloud Storage describes a signed URL as time-limited access to a specific resource and notes that anyone possessing an active URL can perform the allowed request even without an account. MAKNOW therefore treats the complete URL as capability-secret state: do not copy it into ordinary logs, tickets, analytics, or screenshots. Audit data should keep only the necessary redacted/fingerprinted representation.

5. Method and resource are part of the contract

Do not treat a GET grant as generic object permission. The request must match the expected operation, HTTP method, and resource/object key. If the workflow changes to PUT, mint a new grant for that request shape. A GET grant used as if it authorized PUT is a binding failure even when the object name is unchanged.

6. Signed headers and Content-Type matter

Uploads may bind signed headers or a content-type value into the canonical request. A client cannot silently omit a required header or send a different value and then treat the resulting failure as generic storage trouble. Record signed_headers and content_type_constraint so the mismatch is inspectable.

7. Nominal expiry is not always effective validity

Amazon S3 documents that a presigned URL created with temporary credentials cannot remain valid beyond those credentials, and revoked/deleted/deactivated credentials can end validity before the configured URL expiration. Keep expires_at distinct from effective_valid_until. If the signer credential expires in eight minutes, do not promise twenty minutes of effective access.

8. Capability rotation changes state

When a signing key or credential is rotated or revoked, the old grant needs a typed INVALIDATED state. Minting a replacement grant must not leave the old URL represented as valid in workflow state. Audit records should keep grant creation and invalidation separate and bind each request to a specific grant.

9. Bind expected digest and size before transfer

When the expected artifact is known, record expected_digest and expected_size before download/upload. Without them the receiver cannot prove that the arriving bytes are the intended artifact. A filename, object key, or HTTP 200 cannot substitute for content evidence.

10. What RFC 9530 proves—and does not

RFC 9530 defines Content-Digest and Repr-Digest as integrity fields for HTTP content or representations and explicitly does not define authentication, authorization, or privacy. Digest evidence can support integrity; it does not prove the human recipient, rights, approval, or publication fitness.

11. Separate transport success from verification

request_completed_at and http_result=200/2xx show a transport result for a request. State must not jump directly from 2xx to VERIFIED. The receiver must obtain or compute received_digest and received_size and compare them with the expectation. A mismatch is FAIL/BLOCK even when the HTTP request succeeded.

12. A receipt creates auditable closure

A receipt_id binds the specific grant, artifact expectation, transport result, and verification result. A useful receipt lets an auditor determine which bytes moved under which grant and how the receiver validated them. A receipt without content verification cannot support a completion state stronger than UNVERIFIED.

13. Preserve typed non-success states

EXPIRED, INVALIDATED, LEAKED, UNBOUND, FAILED, UNVERIFIED, DEFER, and BLOCK represent different failures. A leaked URL with matching bytes is a capability-security problem; a digest mismatch with a secret-safe URL is an integrity failure; a missing expected digest is an evidence gap. One generic green status destroys these distinctions.

14. Lab: Presigned Transfer Grant & Receipt Verification Record v1

lab://CON-020/CON020-LAB1 contains eight synthetic fixtures: a valid baseline, credential expiry before nominal URL expiry, a leaked URL, HTTP 2xx with wrong bytes, missing expected digest, method mismatch, signed-header/content-type mismatch, and a GET-to-PUT rotation scenario. Each case yields eight evidence/state outputs; the hidden evaluator contains 64 deterministic assertions.

15. Transfer: switch GET to PUT, invalidate the old grant, verify the receipt

The transfer challenge sends a replacement artifact with PUT. Bind content type and expected digest, rotate signing credentials before nominal expiry, and make the old GET grant unusable. A successful PUT still remains UNVERIFIED until the receiver verifies the stored object's digest and size. “Upload succeeded” and “expected artifact verified” are deliberately separate claims.

Official sources and claim boundary

  • 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 are sourced facts rechecked on 2026-09-17. K4 — requiring receipt-side digest/size verification before MAKNOW marks a transfer VERIFIED — is a MAKNOW design rule, not a requirement attributed to Google, AWS, or RFC 9530.

Assessment

There is no answer key in this lesson pack; answer it yourself and mark honestly. "Needs review" sends the lesson to your review queue.

CON-020-Q1 boundary

Why must a presigned URL grant be represented separately from the expected artifact identity?

lesson ✗AI ✗notes ✗

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?

lesson ✗AI ✗notes ✗

CON-020-Q3 diagnosis

HTTP 200 returns bytes whose digest differs from the expected artifact. Which state must remain non-success and why?

lesson ✗AI ✗notes ✗

CON-020-Q4 security

The transfer succeeds but the full signed URL was written to an ordinary debug log. What evidence/decision changes?

lesson ✗AI ✗notes ✗

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.

lesson ✗AI ✗notes ✗
Assessment rubric

A sufficient artifact:

  1. separates artifact identity/evidence from the presigned grant;
  2. binds operation, HTTP method, resource/object key, nominal expiry and effective credential validity;
  3. treats the complete signed URL as sensitive capability state and records a redaction rule;
  4. records signed-header/content-type/checksum constraints when present;
  5. preserves credential expiry/revocation/rotation as typed invalidation rather than overclaiming URL lifetime;
  6. separates HTTP transport result from digest/size verification;
  7. blocks or defers when expected digest is missing, bytes mismatch, request shape is unbound, or capability secrecy is violated;
  8. identifies Google/AWS/RFC facts separately from MAKNOW's transfer state-machine design;
  9. rebuilds the changed GET→PUT context without copying the first decision.

References & freshness

·
·
·

Case studies

Lesson visuals

CON-020-PRESIGNED-TRANSFER-FLOW

Lab files

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.