Skip to content

python(feat): send and expose the artifact file SHA-256 - #870

Open
alexluck-sift wants to merge 6 commits into
mainfrom
al/python/feat/artifact-file-sha256
Open

alexluck-sift wants to merge 6 commits into
mainfrom
al/python/feat/artifact-file-sha256

Conversation

@alexluck-sift

@alexluck-sift alexluck-sift commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Artifact uploads now send the SHA-256 of the file, and ArtifactVersion.file_sha256 returns it. A caller can compare a local file with the latest version's hash and skip an upload when the file has not changed.

  • ArtifactVersion.file_sha256: the lowercase hex SHA-256 that the upload sent, or None for a version uploaded without one
  • ArtifactsAPI.create and ArtifactsAPI.update send the hash as the sha256 form field of the upload. The hash covers the whole file: a path, bytes, or a seekable file object.
  • UploadLowLevelClient.upload_attachment takes sha256=True to hash the file in 1 MiB chunks and then seek back to the start. Only the artifact path sets it, so other attachment uploads do not read their files a second time.

Fix: every upload now seeks a file object to its start and sends the whole file. Before, MultipartEncoder sent an io.BytesIO whole from getvalue() but an open file only from its current position, so an open file that was already read uploaded empty. This keeps the hash and the uploaded bytes the same.

Verification

  • Against the development environment: created an artifact from a path, then wrote a second version from an io.BytesIO that was written to and not rewound. For both versions, file_sha256 matched the local SHA-256 of the bytes sent, and the downloaded file matched them byte for byte.

@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Python docs preview: https://sift-stack.github.io/sift/python/pr-870/

Deployed from 831ca48. The link may take up to a minute to become live as GitHub Pages propagates.

@alexluck-sift
alexluck-sift added this pull request to stack #871 November 4, 2026 23:39
Base automatically changed from al/sift/chore/update-public-protos to main November 5, 2026 00:09
@alexluck-sift
alexluck-sift force-pushed the al/python/feat/artifact-file-sha256 branch from d72a021 to a19112c Compare November 5, 2026 00:09
@alexluck-sift
alexluck-sift marked this pull request as ready for review November 5, 2026 00:32

def __init__(self, file: BinaryIO):
self._file = file
start = file.tell()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A buffer that was written to or already uploaded once is left at its end, so it now uploads as an empty file with no error. Can we seek(0) before hashing and uploading so the whole file is always sent?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, fixed in 826aa89. A file object now uploads whole from its start, whatever its position, and the hash covers the whole file. Added a test for a written BytesIO that wasn't rewound, plus open files and buffers left mid-file or at the end.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants