fix(federation): bind copy timestamps to committed writes

Return the committed object or part time on federation write responses and
capture it for CopyObject and UploadPartCopy without a follow-up read.
Keep successful writes compatible with targets that do not supply a time.

Reject authenticated raw SSE-C replica CopyObject across deployments before
forwarding. Extend the existing SSE fixtures to verify empty objects,
stored checksums, KMS contexts and multipart sources.

Refs: #169, #168, #171
Signed-off-by: Feng Ruohang <rh@vonng.com>
This commit is contained in:
Feng Ruohang
2026-09-12 01:44:22 +08:00
parent 12f631b502
commit f175e98c34
9 changed files with 603 additions and 83 deletions
@@ -5,12 +5,14 @@ package cmd
import (
"bytes"
"encoding/xml"
"net/http"
"net/url"
"strings"
"testing"
"time"
"github.com/minio/minio/internal/amztime"
"github.com/minio/minio/internal/auth"
sse "github.com/minio/minio/internal/bucket/encryption"
"github.com/minio/minio/internal/event"
@@ -69,6 +71,13 @@ func TestAPIFederatedCopyObjectVersionAndEvent(t *testing.T) {
if err != nil || info.VersionID != versionID {
t.Fatalf("response does not name the written version: %v, %q", err, info.VersionID)
}
var response CopyObjectResponse
if err := xml.Unmarshal(rec.Body.Bytes(), &response); err != nil {
t.Fatal(err)
}
if want := amztime.ISO8601Format(info.ModTime.UTC()); response.LastModified != want {
t.Errorf("copy time = %q, want written version time %q", response.LastModified, want)
}
}
select {
case evt := <-events: