Skip to content

feat: Add native Hugging Face push support with LFS#673

Open
iamanishx wants to merge 4 commits intodocker:mainfrom
iamanishx:hf-push
Open

feat: Add native Hugging Face push support with LFS#673
iamanishx wants to merge 4 commits intodocker:mainfrom
iamanishx:hf-push

Conversation

@iamanishx
Copy link

@iamanishx iamanishx commented Feb 14, 2026

Summery:

  • Detects hf.co/ and huggingface.co/ references in docker model push and routes them to the native Hugging Face upload API instead of OCI registry push
  • Files ≥ 10MB are uploaded via the HF LFS batch API (presigned S3 URLs), while smaller files (e.g. README) are sent inline as base64
  • Creates commits using HuggingFace's NDJSON commit API (POST /api/models/{repo}/commit/main)
  • Reads HF_TOKEN environment variable for authentication
  • Reports upload progress to the CLI
export HF_TOKEN="hf_..."
docker model tag <source-model> hf.co/<username>/<repo>:latest
docker model push hf.co/<username>/<repo>:latest

issue number : #597

video ref- https://drive.google.com/file/d/1HE7GrpqXN_BNzgffR6nBm9kOBFKdtEjl/view?usp=sharing

Signed-off-by: iamanishx <manishbiswal754@gmail.com>
Signed-off-by: Manish Biswal <manishbiswal754@gmail.com>
Signed-off-by: Manish Biswal <manishbiswal754@gmail.com>
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @iamanishx, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the docker model push command by integrating native support for Hugging Face repositories. It introduces a robust mechanism to differentiate between OCI registry and Hugging Face pushes, optimizing file transfers by utilizing the Hugging Face LFS batch API for large assets and embedding smaller files directly. This change streamlines the process of publishing models to Hugging Face, offering a more direct and authenticated workflow for users.

Highlights

  • Hugging Face Native Push Support: The docker model push command now natively supports pushing models to Hugging Face repositories by detecting hf.co/ or huggingface.co/ references.
  • Hugging Face LFS Integration: Files larger than 10MB are uploaded using the Hugging Face LFS batch API, leveraging presigned S3 URLs for efficient transfer. Smaller files, such as READMEs, are sent inline as base64 encoded content.
  • Authentication via HF_TOKEN: Authentication for Hugging Face pushes is handled by reading the HF_TOKEN environment variable, which is then passed as a bearer token.
  • NDJSON Commit API: Model changes are committed to Hugging Face repositories using their NDJSON commit API (POST /api/models/{repo}/commit/main), allowing for atomic updates.
  • CLI Progress Reporting: The CLI now reports detailed upload progress, providing feedback on file preparation, LFS batching, and file transfers.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • cmd/cli/commands/push.go
    • Updated the short description of the 'push' command to reflect support for Hugging Face.
  • cmd/cli/desktop/desktop.go
    • Modified the Push function to detect Hugging Face references and conditionally retrieve and pass the HF_TOKEN environment variable.
  • pkg/distribution/distribution/client.go
    • Added filepath and bundle imports.
    • Modified the PushModel function signature to accept an optional bearer token.
    • Introduced logic to determine if a push target is a Hugging Face reference and route it to a new pushNativeHuggingFace method.
    • Implemented pushNativeHuggingFace to orchestrate the Hugging Face specific upload process, including file collection, LFS batching, and commit creation.
  • pkg/distribution/huggingface/client.go
    • Added imports for bytes, encoding/base64.
    • Defined new Go structs (LFSBatchRequest, LFSBatchObject, LFSObjectError, LFSAction, LFSObject, LFSBatchResponse, CommitFile, LFSCommitFile, ndjsonEntry) to support Hugging Face LFS and commit APIs.
    • Implemented CreateCommit to send NDJSON formatted commit requests, handling both direct (base64) and LFS files.
    • Implemented LFSBatch to request LFS upload URLs from Hugging Face.
    • Implemented UploadLFSObject to upload large files to presigned URLs.
    • Implemented VerifyLFSObject to confirm LFS object uploads.
    • Added checkUploadResponse to handle HTTP responses specifically for upload operations.
    • Added escapePath utility function for URL path escaping.
  • pkg/distribution/huggingface/uploader.go
    • Added a new file to manage the Hugging Face upload process.
    • Defined UploadFile struct to represent files for upload.
    • Implemented uploadProgressReader to provide progress updates during file transfers.
    • Implemented CollectUploadFiles to recursively gather files from a directory and calculate total size.
    • Implemented UploadFiles to coordinate the upload of files, distinguishing between LFS and direct uploads based on size, and managing progress reporting.
    • Added safeUint64 helper function for type conversion.
    • Implemented computeFileOID to calculate SHA256 OID for LFS files.
  • pkg/inference/models/api.go
    • Defined a new ModelPushRequest struct to encapsulate an optional bearer token for push operations.
  • pkg/inference/models/http_handler.go
    • Modified the handlePushModel function to parse an incoming ModelPushRequest body for a bearer token, if provided.
  • pkg/inference/models/manager.go
    • Modified the Push method signature to accept an additional bearerToken parameter.
    • Updated the Push method to conditionally pass the bearerToken to the distributionClient.PushModel function.
Activity
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • The new PushModel signature uses a variadic bearerToken ...string but only ever reads the first element; consider switching to a single explicit parameter or a small options struct to make the call sites and intent clearer.
  • Hugging Face reference detection is now implemented both in the CLI (strings.HasPrefix(modelLower, "hf.co/")...) and in isHuggingFaceReference; centralizing this into a shared helper would reduce duplication and avoid future drift in patterns.
  • In UploadFiles, progress for small (non-LFS) files is reported via uploadProgressReader during read and then again after CreateCommit by writing a full-size update, which may double-count per-file progress; consider consolidating progress reporting so each byte is only accounted for once.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new `PushModel` signature uses a variadic `bearerToken ...string` but only ever reads the first element; consider switching to a single explicit parameter or a small options struct to make the call sites and intent clearer.
- Hugging Face reference detection is now implemented both in the CLI (`strings.HasPrefix(modelLower, "hf.co/")...`) and in `isHuggingFaceReference`; centralizing this into a shared helper would reduce duplication and avoid future drift in patterns.
- In `UploadFiles`, progress for small (non-LFS) files is reported via `uploadProgressReader` during read and then again after `CreateCommit` by writing a full-size update, which may double-count per-file progress; consider consolidating progress reporting so each byte is only accounted for once.

## Individual Comments

### Comment 1
<location> `pkg/inference/models/http_handler.go:454-456` </location>
<code_context>
 // handlePushModel handles POST <inference-prefix>/models/{name}/push requests.
 func (h *HTTPHandler) handlePushModel(w http.ResponseWriter, r *http.Request, model string) {
-	if err := h.manager.Push(model, r, w); err != nil {
+	var req ModelPushRequest
+	if r.Body != nil && r.Body != http.NoBody {
+		body, err := io.ReadAll(r.Body)
+		if err != nil {
+			http.Error(w, "invalid request body", http.StatusBadRequest)
</code_context>

<issue_to_address>
**🚨 issue (security):** Reading the entire request body without a size limit can be abused

`io.ReadAll` consumes the entire body even though only a small JSON payload is required. This allows an attacker to send a very large request and exhaust memory. Please cap the body size (e.g., wrap `r.Body` with `io.LimitReader` here, or `http.MaxBytesReader` at the router) before reading.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +454 to +456
var req ModelPushRequest
if r.Body != nil && r.Body != http.NoBody {
body, err := io.ReadAll(r.Body)
Copy link
Contributor

Choose a reason for hiding this comment

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

🚨 issue (security): Reading the entire request body without a size limit can be abused

io.ReadAll consumes the entire body even though only a small JSON payload is required. This allows an attacker to send a very large request and exhaust memory. Please cap the body size (e.g., wrap r.Body with io.LimitReader here, or http.MaxBytesReader at the router) before reading.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces native push support for Hugging Face repositories, which is a great feature. The implementation correctly detects Hugging Face URLs and routes them to a new native upload flow that uses the Hugging Face LFS and commit APIs. The changes are well-structured across the CLI, desktop client, and distribution packages. My review includes a critical fix for a compilation error, suggestions to improve consistency in error handling for progress reporting, and a recommendation to simplify some of the new HTTP handling logic.

@iamanishx
Copy link
Author

@doringeman @ericcurtin please have a look

Copy link
Contributor

@ericcurtin ericcurtin left a comment

Choose a reason for hiding this comment

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

Wow @iamanishx this is great please go through the Gemini comments and address or mark as resolved if they are not worth it

@ericcurtin
Copy link
Contributor

Lets hope you pass the build

@ericcurtin
Copy link
Contributor

Need to regenerate the docs and repush, it's just:

make docs

in the cmd/cli directory and repush the changes.

@iamanishx
Copy link
Author

@ericcurtin i have repushed the docs and gemini suggestions were invalid so i have resolved them .

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