forked from TrueCloudLab/frostfs-s3-gw
parent
dd534e8738
commit
5529fb914e
2 changed files with 27 additions and 75 deletions
|
@ -221,22 +221,6 @@ func (h *handler) PutObjectRetentionHandler(w http.ResponseWriter, r *http.Reque
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkLockInfo(lock *data.ObjectInfo, header http.Header) error {
|
|
||||||
if lock == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if lock.Headers[layer.AttributeComplianceMode] != "" {
|
|
||||||
return fmt.Errorf("it's forbidden to change compliance lock mode")
|
|
||||||
}
|
|
||||||
|
|
||||||
if bypass, err := strconv.ParseBool(header.Get(api.AmzBypassGovernanceRetention)); err != nil || !bypass {
|
|
||||||
return fmt.Errorf("cannot bypass governance mode")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *handler) GetObjectRetentionHandler(w http.ResponseWriter, r *http.Request) {
|
func (h *handler) GetObjectRetentionHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
reqInfo := api.GetReqInfo(r.Context())
|
reqInfo := api.GetReqInfo(r.Context())
|
||||||
|
|
||||||
|
@ -358,6 +342,16 @@ func formObjectLock(bktInfo *data.BucketInfo, defaultConfig *data.ObjectLockConf
|
||||||
objectLock.Retention.Until = retentionDate
|
objectLock.Retention.Until = retentionDate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if objectLock.Retention != nil {
|
||||||
|
if bypassStr := header.Get(api.AmzBypassGovernanceRetention); len(bypassStr) > 0 {
|
||||||
|
bypass, err := strconv.ParseBool(bypassStr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("couldn't parse bypass governance header: %w", err)
|
||||||
|
}
|
||||||
|
objectLock.Retention.ByPassedGovernance = bypass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return objectLock, nil
|
return objectLock, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -13,7 +14,6 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api"
|
"github.com/nspcc-dev/neofs-s3-gw/api"
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api/data"
|
"github.com/nspcc-dev/neofs-s3-gw/api/data"
|
||||||
apiErrors "github.com/nspcc-dev/neofs-s3-gw/api/errors"
|
apiErrors "github.com/nspcc-dev/neofs-s3-gw/api/errors"
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api/layer"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -153,57 +153,6 @@ func assertObjectLocks(t *testing.T, expected, actual *data.ObjectLock) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckLockObject(t *testing.T) {
|
|
||||||
for _, tc := range []struct {
|
|
||||||
name string
|
|
||||||
isCompliance bool
|
|
||||||
header http.Header
|
|
||||||
expectedError bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "error governance bypass",
|
|
||||||
header: map[string][]string{
|
|
||||||
api.AmzBypassGovernanceRetention: {strconv.FormatBool(false)},
|
|
||||||
},
|
|
||||||
expectedError: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "error invalid governance bypass",
|
|
||||||
header: map[string][]string{
|
|
||||||
api.AmzBypassGovernanceRetention: {"t r u e"},
|
|
||||||
},
|
|
||||||
expectedError: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "error failed change compliance mode",
|
|
||||||
isCompliance: true,
|
|
||||||
expectedError: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "valid",
|
|
||||||
header: map[string][]string{
|
|
||||||
api.AmzBypassGovernanceRetention: {strconv.FormatBool(true)},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
header := make(map[string]string)
|
|
||||||
if tc.isCompliance {
|
|
||||||
header[layer.AttributeComplianceMode] = strconv.FormatBool(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
lockInfo := &data.ObjectInfo{Headers: header}
|
|
||||||
err := checkLockInfo(lockInfo, tc.header)
|
|
||||||
if tc.expectedError {
|
|
||||||
require.Error(t, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
require.NoError(t, err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLockConfiguration(t *testing.T) {
|
func TestLockConfiguration(t *testing.T) {
|
||||||
for _, tc := range []struct {
|
for _, tc := range []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -530,25 +479,25 @@ func TestObjectRetention(t *testing.T) {
|
||||||
hc.Handler().GetObjectRetentionHandler(w, r)
|
hc.Handler().GetObjectRetentionHandler(w, r)
|
||||||
assertS3Error(t, w, apiErrors.GetAPIError(apiErrors.ErrNoSuchKey))
|
assertS3Error(t, w, apiErrors.GetAPIError(apiErrors.ErrNoSuchKey))
|
||||||
|
|
||||||
retention := &data.Retention{Mode: governanceMode, RetainUntilDate: time.Now().Format(time.RFC3339)}
|
retention := &data.Retention{Mode: governanceMode, RetainUntilDate: time.Now().UTC().Format(time.RFC3339)}
|
||||||
w, r = prepareTestRequest(t, bktName, objName, retention)
|
w, r = prepareTestRequest(t, bktName, objName, retention)
|
||||||
hc.Handler().PutObjectRetentionHandler(w, r)
|
hc.Handler().PutObjectRetentionHandler(w, r)
|
||||||
require.Equal(t, http.StatusOK, w.Code)
|
assertStatus(t, w, http.StatusOK)
|
||||||
|
|
||||||
w, r = prepareTestRequest(t, bktName, objName, nil)
|
w, r = prepareTestRequest(t, bktName, objName, nil)
|
||||||
hc.Handler().GetObjectRetentionHandler(w, r)
|
hc.Handler().GetObjectRetentionHandler(w, r)
|
||||||
assertRetention(t, w, retention)
|
assertRetention(t, w, retention)
|
||||||
|
|
||||||
retention = &data.Retention{Mode: governanceMode, RetainUntilDate: time.Now().Format(time.RFC3339)}
|
retention = &data.Retention{Mode: governanceMode, RetainUntilDate: time.Now().UTC().Format(time.RFC3339)}
|
||||||
w, r = prepareTestRequest(t, bktName, objName, retention)
|
w, r = prepareTestRequest(t, bktName, objName, retention)
|
||||||
hc.Handler().PutObjectRetentionHandler(w, r)
|
hc.Handler().PutObjectRetentionHandler(w, r)
|
||||||
assertS3Error(t, w, apiErrors.GetAPIError(apiErrors.ErrInternalError))
|
assertS3Error(t, w, apiErrors.GetAPIError(apiErrors.ErrInternalError))
|
||||||
|
|
||||||
retention = &data.Retention{Mode: complianceMode, RetainUntilDate: time.Now().Format(time.RFC3339)}
|
retention = &data.Retention{Mode: complianceMode, RetainUntilDate: time.Now().UTC().Format(time.RFC3339)}
|
||||||
w, r = prepareTestRequest(t, bktName, objName, retention)
|
w, r = prepareTestRequest(t, bktName, objName, retention)
|
||||||
r.Header.Set(api.AmzBypassGovernanceRetention, strconv.FormatBool(true))
|
r.Header.Set(api.AmzBypassGovernanceRetention, strconv.FormatBool(true))
|
||||||
hc.Handler().PutObjectRetentionHandler(w, r)
|
hc.Handler().PutObjectRetentionHandler(w, r)
|
||||||
require.Equal(t, http.StatusOK, w.Code)
|
assertStatus(t, w, http.StatusOK)
|
||||||
|
|
||||||
w, r = prepareTestRequest(t, bktName, objName, nil)
|
w, r = prepareTestRequest(t, bktName, objName, nil)
|
||||||
hc.Handler().GetObjectRetentionHandler(w, r)
|
hc.Handler().GetObjectRetentionHandler(w, r)
|
||||||
|
@ -589,7 +538,7 @@ func TestPutObjectWithLock(t *testing.T) {
|
||||||
|
|
||||||
w, r := prepareTestRequest(t, bktName, objDefault, nil)
|
w, r := prepareTestRequest(t, bktName, objDefault, nil)
|
||||||
hc.Handler().PutObjectHandler(w, r)
|
hc.Handler().PutObjectHandler(w, r)
|
||||||
require.Equal(t, http.StatusOK, w.Code)
|
assertStatus(t, w, http.StatusOK)
|
||||||
|
|
||||||
w, r = prepareTestRequest(t, bktName, objDefault, nil)
|
w, r = prepareTestRequest(t, bktName, objDefault, nil)
|
||||||
hc.Handler().GetObjectRetentionHandler(w, r)
|
hc.Handler().GetObjectRetentionHandler(w, r)
|
||||||
|
@ -607,9 +556,10 @@ func TestPutObjectWithLock(t *testing.T) {
|
||||||
w, r = prepareTestRequest(t, bktName, objOverride, nil)
|
w, r = prepareTestRequest(t, bktName, objOverride, nil)
|
||||||
r.Header.Set(api.AmzObjectLockMode, complianceMode)
|
r.Header.Set(api.AmzObjectLockMode, complianceMode)
|
||||||
r.Header.Set(api.AmzObjectLockLegalHold, legalHoldOn)
|
r.Header.Set(api.AmzObjectLockLegalHold, legalHoldOn)
|
||||||
|
r.Header.Set(api.AmzBypassGovernanceRetention, "true")
|
||||||
r.Header.Set(api.AmzObjectLockRetainUntilDate, time.Now().Add(2*24*time.Hour).Format(time.RFC3339))
|
r.Header.Set(api.AmzObjectLockRetainUntilDate, time.Now().Add(2*24*time.Hour).Format(time.RFC3339))
|
||||||
hc.Handler().PutObjectHandler(w, r)
|
hc.Handler().PutObjectHandler(w, r)
|
||||||
require.Equal(t, http.StatusOK, w.Code)
|
assertStatus(t, w, http.StatusOK)
|
||||||
|
|
||||||
w, r = prepareTestRequest(t, bktName, objOverride, nil)
|
w, r = prepareTestRequest(t, bktName, objOverride, nil)
|
||||||
hc.Handler().GetObjectRetentionHandler(w, r)
|
hc.Handler().GetObjectRetentionHandler(w, r)
|
||||||
|
@ -639,3 +589,11 @@ func assertRetentionApproximate(t *testing.T, w *httptest.ResponseRecorder, rete
|
||||||
|
|
||||||
require.InDelta(t, expectedUntil.Unix(), actualUntil.Unix(), delta)
|
require.InDelta(t, expectedUntil.Unix(), actualUntil.Unix(), delta)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func assertStatus(t *testing.T, w *httptest.ResponseRecorder, status int) {
|
||||||
|
if w.Code != status {
|
||||||
|
resp, err := io.ReadAll(w.Result().Body)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Fail(t, string(resp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue