Guard cargo publishes against name and version collisions
- serialise publishes per crate with an advisory lock in one transaction - add a unique index on normalised name and version without build metadata - validate versions as strict SemVer 2.0 and reject an empty .crate - renumber the migration to 0005
This commit is contained in:
@@ -73,22 +73,6 @@ func (h *ProxyHandler) cargoPublish(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
existing, err := h.db.ListCargoIndexEntries(ctx, remote.Name, meta.Name)
|
||||
if err != nil {
|
||||
cargoError(w, http.StatusInternalServerError, "%v", err)
|
||||
return
|
||||
}
|
||||
for _, e := range existing {
|
||||
if e.Name != meta.Name {
|
||||
cargoError(w, http.StatusBadRequest, "crate %q already exists as %q", meta.Name, e.Name)
|
||||
return
|
||||
}
|
||||
if e.Version == meta.Vers {
|
||||
cargoError(w, http.StatusConflict, "crate version `%s@%s` already exists", meta.Name, meta.Vers)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
lineJSON, err := json.Marshal(line)
|
||||
if err != nil {
|
||||
cargoError(w, http.StatusInternalServerError, "%v", err)
|
||||
@@ -117,7 +101,14 @@ func (h *ProxyHandler) cargoPublish(w http.ResponseWriter, r *http.Request) {
|
||||
if err := h.db.InsertCargoIndexEntry(ctx, entry); err != nil {
|
||||
// Drop the file so a retry is not rejected as a duplicate.
|
||||
_ = h.db.DeleteLocalFile(ctx, remote.Name, path)
|
||||
cargoError(w, http.StatusInternalServerError, "record index: %v", err)
|
||||
switch {
|
||||
case errors.Is(err, database.ErrCargoNameTaken):
|
||||
cargoError(w, http.StatusBadRequest, "%v", err)
|
||||
case errors.Is(err, database.ErrAlreadyExists):
|
||||
cargoError(w, http.StatusConflict, "crate version `%s@%s` already exists", meta.Name, meta.Vers)
|
||||
default:
|
||||
cargoError(w, http.StatusInternalServerError, "record index: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user