Skip to main content

max / synckit

Vendor the regenerated MNW openapi spec
Author: Max Johnson <me@maxj.phd> · 2026-08-31 11:39 UTC
Signed with PGP, not checked
Commit: d091845bb8310617c029326c9c223da9e6357dcf
Parent: c1b11dd
1 file changed, +1 insertion, -1 deletion
@@ -654,7 +654,7 @@
654 654 "SyncKit"
655 655 ],
656 656 "summary": "Confirm that a blob upload to S3 completed successfully.",
657 - "description": "Verifies the object exists in S3, then records it in the database.\nIdempotent: returns success without creating a duplicate.\n\nContent-addressing trust model (ultra-fuzz Run 4 Storage NOTE, decision\n2026-06-23; revised 2026-07-21): the blob `hash` is treated as a\ncontent-address LABEL, confirm reads the authoritative `object_size` from S3\nbut does not re-hash the bytes to prove they match `hash`. The blast radius\nis per-user only: the key is `{app_id}/{user_id}/{hash}` and storage is\n`UNIQUE(app_id, user_id, hash)`, so a client that stores mismatched bytes can\npoison only its OWN dedup namespace, no cross-user effect, no data exposure.\n\nThis note used to say the A+ fix was binding `x-amz-checksum-sha256` into the\npresigned PUT so S3 rejects a mismatched upload at write time. That reasoning\ndoes not hold for these blobs, and the correction is worth keeping: the stored\nobject is E2E *ciphertext* sealed with random per-chunk nonces, while `hash`\nis the SHA-256 of the *plaintext*. The server never sees plaintext, so it\ncannot derive the expected ciphertext digest at presign time, any checksum it\nbinds has to come from the client, i.e. the party whose honesty was in\nquestion. Checksum binding (which the multipart path now does per part) buys\ntransport integrity, not content-address enforcement.\n\nWhat actually binds the bytes to the address is the AEAD: each chunk is sealed\nwith `(hash, chunk_index, chunk_count)` as associated data, so ciphertext that\nopens under `hash` is cryptographically tied to it, and the client re-hashes\nthe plaintext after decrypting. A client storing mismatched bytes breaks only\nits own blob. Server-side re-hashing would cost a full object download per\nconfirm to defend a client against itself, which is why it is not done.",
657 + "description": "Verifies the object exists in S3, then records it in the database.\nIdempotent: returns success without creating a duplicate.\n\nContent-addressing trust model: the blob `hash` is treated as a\ncontent-address LABEL, confirm reads the authoritative `object_size` from S3\nbut does not re-hash the bytes to prove they match `hash`. The blast radius\nis per-user only: the key is `{app_id}/{user_id}/{hash}` and storage is\n`UNIQUE(app_id, user_id, hash)`, so a client that stores mismatched bytes can\npoison only its OWN dedup namespace, no cross-user effect, no data exposure.\n\nThis note used to say the A+ fix was binding `x-amz-checksum-sha256` into the\npresigned PUT so S3 rejects a mismatched upload at write time. That reasoning\ndoes not hold for these blobs, and the correction is worth keeping: the stored\nobject is E2E *ciphertext* sealed with random per-chunk nonces, while `hash`\nis the SHA-256 of the *plaintext*. The server never sees plaintext, so it\ncannot derive the expected ciphertext digest at presign time, any checksum it\nbinds has to come from the client, i.e. the party whose honesty was in\nquestion. Checksum binding (which the multipart path now does per part) buys\ntransport integrity, not content-address enforcement.\n\nWhat actually binds the bytes to the address is the AEAD: each chunk is sealed\nwith `(hash, chunk_index, chunk_count)` as associated data, so ciphertext that\nopens under `hash` is cryptographically tied to it, and the client re-hashes\nthe plaintext after decrypting. A client storing mismatched bytes breaks only\nits own blob. Server-side re-hashing would cost a full object download per\nconfirm to defend a client against itself, which is why it is not done.",
658 658 "operationId": "blob_confirm_upload",
659 659 "requestBody": {
660 660 "content": {