R-31: a second off-site Save while the first still provisions is refused, not raced
Both saves used to list no sub-account and create one (a dedicated box is a second bill). Per-customer in-memory claim; the second gets 409 and nothing is saved or created. The async save + status card stays open. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -779,7 +779,12 @@ func (s *Server) handleConfigCreate(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// Offsite provisioning (fail-closed): a provisioning error must NOT save a half-enabled config.
|
||||
if err := s.applyOffsite(r.Context(), r, cfg); err != nil {
|
||||
if err := s.applyOffsite(r.Context(), r, cfg); errors.Is(err, offsite.ErrProvisionInProgress) {
|
||||
// R-31: a second Save while the first still provisions — nothing saved, nothing created.
|
||||
s.logger.Printf("[INFO] offsite provision for %s refused: one is already running (R-31)", customerID)
|
||||
http.Error(w, err.Error(), http.StatusConflict)
|
||||
return
|
||||
} else if err != nil {
|
||||
s.logger.Printf("[ERROR] offsite provision for %s: %v", customerID, err)
|
||||
http.Error(w, "Offsite provisioning failed: "+err.Error(), http.StatusBadGateway)
|
||||
return
|
||||
@@ -859,7 +864,12 @@ func (s *Server) handleConfigUpdate(w http.ResponseWriter, r *http.Request, cust
|
||||
|
||||
cfg.ConfigJSON = buildConfigJSON(r)
|
||||
|
||||
if err := s.applyOffsite(r.Context(), r, cfg); err != nil {
|
||||
if err := s.applyOffsite(r.Context(), r, cfg); errors.Is(err, offsite.ErrProvisionInProgress) {
|
||||
// R-31: a second Save while the first still provisions — nothing saved, nothing created.
|
||||
s.logger.Printf("[INFO] offsite provision for %s refused: one is already running (R-31)", customerID)
|
||||
http.Error(w, err.Error(), http.StatusConflict)
|
||||
return
|
||||
} else if err != nil {
|
||||
s.logger.Printf("[ERROR] offsite provision for %s: %v", customerID, err)
|
||||
http.Error(w, "Offsite provisioning failed: "+err.Error(), http.StatusBadGateway)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user