diff --git a/lib/api/apiUtils/authorization/permissionChecks.js b/lib/api/apiUtils/authorization/permissionChecks.js index 76ad9f0e70..6b0ba64f49 100644 --- a/lib/api/apiUtils/authorization/permissionChecks.js +++ b/lib/api/apiUtils/authorization/permissionChecks.js @@ -274,11 +274,11 @@ function _checkPrincipals(canonicalID, arn, principal) { return false; } -function checkBucketPolicy(policy, requestType, canonicalID, arn, bucketOwner, log, request) { +function checkBucketPolicy(policy, requestType, canonicalID, arn, bucketOwner, log, request, actionImplicitDenies) { let permission = 'defaultDeny'; // if requester is user within bucket owner account, actions should be // allowed unless explicitly denied (assumes allowed by IAM policy) - if (bucketOwner === canonicalID) { + if (bucketOwner === canonicalID && actionImplicitDenies[requestType] === false) { permission = 'allow'; } let copiedStatement = JSON.parse(JSON.stringify(policy.Statement)); @@ -308,7 +308,7 @@ function processBucketPolicy(requestType, bucket, canonicalID, arn, bucketOwner, processedResult = actionImplicitDenies[requestType] === false && aclPermission; } else { const bucketPolicyPermission = checkBucketPolicy(bucketPolicy, requestType, canonicalID, arn, - bucketOwner, log, request); + bucketOwner, log, request, actionImplicitDenies); if (bucketPolicyPermission === 'explicitDeny') { processedResult = false; diff --git a/lib/api/apiUtils/bucket/bucketDeletion.js b/lib/api/apiUtils/bucket/bucketDeletion.js index 9c5fe60fe5..5b8225c136 100644 --- a/lib/api/apiUtils/bucket/bucketDeletion.js +++ b/lib/api/apiUtils/bucket/bucketDeletion.js @@ -24,7 +24,7 @@ function _deleteMPUbucket(destinationBucketName, log, cb) { }); } -function _deleteOngoingMPUs(authInfo, bucketName, bucketMD, mpus, log, cb) { +function _deleteOngoingMPUs(authInfo, bucketName, bucketMD, mpus, request, log, cb) { async.mapLimit(mpus, 1, (mpu, next) => { const splitterChar = mpu.key.includes(oldSplitter) ? oldSplitter : splitter; @@ -40,7 +40,7 @@ function _deleteOngoingMPUs(authInfo, bucketName, bucketMD, mpus, log, cb) { byteLength: partSizeSum, }); next(err); - }); + }, request); }, cb); } /** @@ -49,11 +49,13 @@ function _deleteOngoingMPUs(authInfo, bucketName, bucketMD, mpus, log, cb) { * @param {object} bucketMD - bucket attributes/metadata * @param {string} bucketName - bucket in which objectMetadata is stored * @param {string} canonicalID - account canonicalID of requester + * @param {object} request - request object given by router + * including normalized headers * @param {object} log - Werelogs logger * @param {function} cb - callback from async.waterfall in bucketDelete * @return {undefined} */ -function deleteBucket(authInfo, bucketMD, bucketName, canonicalID, log, cb) { +function deleteBucket(authInfo, bucketMD, bucketName, canonicalID, request, log, cb) { log.trace('deleting bucket from metadata'); assert.strictEqual(typeof bucketName, 'string'); assert.strictEqual(typeof canonicalID, 'string'); @@ -100,7 +102,7 @@ function deleteBucket(authInfo, bucketMD, bucketName, canonicalID, log, cb) { } if (objectsListRes.Contents.length) { return _deleteOngoingMPUs(authInfo, bucketName, - bucketMD, objectsListRes.Contents, log, err => { + bucketMD, objectsListRes.Contents, request, log, err => { if (err) { return next(err); } diff --git a/lib/api/apiUtils/object/abortMultipartUpload.js b/lib/api/apiUtils/object/abortMultipartUpload.js index 8112c7e47d..9b63b73c53 100644 --- a/lib/api/apiUtils/object/abortMultipartUpload.js +++ b/lib/api/apiUtils/object/abortMultipartUpload.js @@ -3,7 +3,7 @@ const async = require('async'); const constants = require('../../../../constants'); const { data } = require('../../../data/wrapper'); const locationConstraintCheck = require('../object/locationConstraintCheck'); -const { metadataValidateBucketAndObj } = +const { standardMetadataValidateBucketAndObj } = require('../../../metadata/metadataUtils'); const services = require('../../../services'); @@ -22,10 +22,11 @@ function abortMultipartUpload(authInfo, bucketName, objectKey, uploadId, log, // but the requestType is the more general 'objectDelete' const metadataValParams = Object.assign({}, metadataValMPUparams); metadataValParams.requestType = 'objectPut'; + const authzIdentityResult = request ? request.actionImplicitDenies : false; async.waterfall([ function checkDestBucketVal(next) { - metadataValidateBucketAndObj(metadataValParams, log, + standardMetadataValidateBucketAndObj(metadataValParams, authzIdentityResult, log, (err, destinationBucket) => { if (err) { return next(err, destinationBucket); @@ -56,9 +57,14 @@ function abortMultipartUpload(authInfo, bucketName, objectKey, uploadId, log, function abortExternalMpu(mpuBucket, mpuOverviewObj, destBucket, next) { const location = mpuOverviewObj.controllingLocationConstraint; + const originalIdentityAuthzResults = request.actionImplicitDenies; + // eslint-disable-next-line no-param-reassign + delete request.actionImplicitDenies; return data.abortMPU(objectKey, uploadId, location, bucketName, request, destBucket, locationConstraintCheck, log, (err, skipDataDelete) => { + // eslint-disable-next-line no-param-reassign + request.actionImplicitDenies = originalIdentityAuthzResults; if (err) { return next(err, destBucket); } diff --git a/lib/api/apiUtils/object/objectLockHelpers.js b/lib/api/apiUtils/object/objectLockHelpers.js index d9d69bedc5..f2126f0cf2 100644 --- a/lib/api/apiUtils/object/objectLockHelpers.js +++ b/lib/api/apiUtils/object/objectLockHelpers.js @@ -3,6 +3,7 @@ const moment = require('moment'); const { config } = require('../../../Config'); const vault = require('../../../auth/vault'); +const { evaluateBucketPolicyWithIAM } = require('../authorization/permissionChecks'); /** * Calculates retain until date for the locked object version @@ -302,7 +303,9 @@ function checkUserGovernanceBypass(request, authInfo, bucketMD, objectKey, log, if (err) { return cb(err); } - if (authorizationResults[0].isAllowed !== true) { + const explicitDenyExists = authorizationResults.some( + authzResult => authzResult.isAllowed === false && authzResult.isImplicit === false); + if (explicitDenyExists) { log.trace('authorization check failed for user', { 'method': 'checkUserPolicyGovernanceBypass', @@ -310,7 +313,25 @@ function checkUserGovernanceBypass(request, authInfo, bucketMD, objectKey, log, }); return cb(errors.AccessDenied); } - return cb(null); + // Convert authorization results into an easier to handle format + const actionImplicitDenies = authorizationResults.reduce((acc, curr, idx) => { + const apiMethod = authorizationResults[idx].action; + // eslint-disable-next-line no-param-reassign + acc[apiMethod] = curr.isImplicit; + return acc; + }, {}); + + // Evaluate against the bucket policies + const areAllActionsAllowed = evaluateBucketPolicyWithIAM( + bucketMD, + Object.keys(actionImplicitDenies), + authInfo.getCanonicalID(), + authInfo, + actionImplicitDenies, + log, + request); + + return cb(areAllActionsAllowed === true ? null : errors.AccessDenied); }); } diff --git a/lib/api/bucketDelete.js b/lib/api/bucketDelete.js index 289a665b68..0e3d32235f 100644 --- a/lib/api/bucketDelete.js +++ b/lib/api/bucketDelete.js @@ -43,7 +43,7 @@ function bucketDelete(authInfo, request, log, cb) { log.trace('passed checks', { method: 'metadataValidateBucket' }); return deleteBucket(authInfo, bucketMD, bucketName, - authInfo.getCanonicalID(), log, err => { + authInfo.getCanonicalID(), request, log, err => { if (err) { return cb(err, corsHeaders); } diff --git a/lib/api/bucketHead.js b/lib/api/bucketHead.js index a4eb17e7d7..5ac17d6058 100644 --- a/lib/api/bucketHead.js +++ b/lib/api/bucketHead.js @@ -1,5 +1,5 @@ const collectCorsHeaders = require('../utilities/collectCorsHeaders'); -const { metadataValidateBucket } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucket } = require('../metadata/metadataUtils'); const { pushMetric } = require('../utapi/utilities'); @@ -21,7 +21,7 @@ function bucketHead(authInfo, request, log, callback) { requestType: 'bucketHead', request, }; - metadataValidateBucket(metadataValParams, log, (err, bucket) => { + standardMetadataValidateBucket(metadataValParams, request.actionImplicitDenies, log, (err, bucket) => { const corsHeaders = collectCorsHeaders(request.headers.origin, request.method, bucket); if (err) { diff --git a/lib/api/completeMultipartUpload.js b/lib/api/completeMultipartUpload.js index eb73dd53e8..ee64aea148 100644 --- a/lib/api/completeMultipartUpload.js +++ b/lib/api/completeMultipartUpload.js @@ -15,7 +15,7 @@ const constants = require('../../constants'); const { versioningPreprocessing, checkQueryVersionId } = require('./apiUtils/object/versioning'); const services = require('../services'); -const { metadataValidateBucketAndObj } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucketAndObj } = require('../metadata/metadataUtils'); const { skipMpuPartProcessing } = require('arsenal').storage.data.external.backendUtils; const locationConstraintCheck = require('./apiUtils/object/locationConstraintCheck'); @@ -120,7 +120,7 @@ function completeMultipartUpload(authInfo, request, log, callback) { // at the destinationBucket level are same as objectPut requestType: 'objectPut', }; - metadataValidateBucketAndObj(metadataValParams, log, next); + standardMetadataValidateBucketAndObj(metadataValParams, request.actionImplicitDenies, log, next); }, function validateMultipart(destBucket, objMD, next) { if (objMD) { @@ -190,9 +190,14 @@ function completeMultipartUpload(authInfo, request, log, callback) { const mdInfo = { storedParts, mpuOverviewKey, splitter }; const mpuInfo = { objectKey, uploadId, jsonList, bucketName, destBucket }; + const originalIdentityImpDenies = request.actionImplicitDenies; + // eslint-disable-next-line no-param-reassign + delete request.actionImplicitDenies; return data.completeMPU(request, mpuInfo, mdInfo, location, null, null, null, locationConstraintCheck, log, (err, completeObjData) => { + // eslint-disable-next-line no-param-reassign + request.actionImplicitDenies = originalIdentityImpDenies; if (err) { return next(err, destBucket); } diff --git a/lib/api/initiateMultipartUpload.js b/lib/api/initiateMultipartUpload.js index 7dd7c01785..cd35d31ec3 100644 --- a/lib/api/initiateMultipartUpload.js +++ b/lib/api/initiateMultipartUpload.js @@ -9,7 +9,7 @@ const { hasNonPrintables } = require('../utilities/stringChecks'); const { cleanUpBucket } = require('./apiUtils/bucket/bucketCreation'); const constants = require('../../constants'); const services = require('../services'); -const { metadataValidateBucketAndObj } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucketAndObj } = require('../metadata/metadataUtils'); const locationConstraintCheck = require('./apiUtils/object/locationConstraintCheck'); const validateWebsiteHeader = require('./apiUtils/object/websiteServing') @@ -253,7 +253,7 @@ function initiateMultipartUpload(authInfo, request, log, callback) { } async.waterfall([ - next => metadataValidateBucketAndObj(metadataValParams, log, + next => standardMetadataValidateBucketAndObj(metadataValParams, request.actionImplicitDenies, log, (error, destinationBucket) => { const corsHeaders = collectCorsHeaders(request.headers.origin, request.method, destinationBucket); diff --git a/lib/api/listMultipartUploads.js b/lib/api/listMultipartUploads.js index 502363dfb0..a32988a432 100644 --- a/lib/api/listMultipartUploads.js +++ b/lib/api/listMultipartUploads.js @@ -6,7 +6,7 @@ const convertToXml = s3middleware.convertToXml; const constants = require('../../constants'); const collectCorsHeaders = require('../utilities/collectCorsHeaders'); const services = require('../services'); -const { metadataValidateBucket } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucket } = require('../metadata/metadataUtils'); const { pushMetric } = require('../utapi/utilities'); // Sample XML response: @@ -104,7 +104,7 @@ function listMultipartUploads(authInfo, request, log, callback) { function waterfall1(next) { // Check final destination bucket for authorization rather // than multipart upload bucket - metadataValidateBucket(metadataValParams, log, + standardMetadataValidateBucket(metadataValParams, request.actionImplicitDenies, log, (err, bucket) => next(err, bucket)); }, function getMPUBucket(bucket, next) { diff --git a/lib/api/listParts.js b/lib/api/listParts.js index 44cb5c53e2..159bc89734 100644 --- a/lib/api/listParts.js +++ b/lib/api/listParts.js @@ -9,7 +9,7 @@ const collectCorsHeaders = require('../utilities/collectCorsHeaders'); const locationConstraintCheck = require('./apiUtils/object/locationConstraintCheck'); const services = require('../services'); -const { metadataValidateBucketAndObj } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucketAndObj } = require('../metadata/metadataUtils'); const escapeForXml = s3middleware.escapeForXml; const { pushMetric } = require('../utapi/utilities'); @@ -112,7 +112,7 @@ function listParts(authInfo, request, log, callback) { async.waterfall([ function checkDestBucketVal(next) { - metadataValidateBucketAndObj(metadataValParams, log, + standardMetadataValidateBucketAndObj(metadataValParams, request.actionImplicitDenies, log, (err, destinationBucket) => { if (err) { return next(err, destinationBucket, null); @@ -150,8 +150,13 @@ function listParts(authInfo, request, log, callback) { mpuOverviewObj, destBucket, }; + const originalIdentityImpDenies = request.actionImplicitDenies; + // eslint-disable-next-line no-param-reassign + delete request.actionImplicitDenies; return data.listParts(mpuInfo, request, locationConstraintCheck, log, (err, backendPartList) => { + // eslint-disable-next-line no-param-reassign + request.actionImplicitDenies = originalIdentityImpDenies; if (err) { return next(err, destBucket); } diff --git a/lib/api/objectCopy.js b/lib/api/objectCopy.js index 9e0302d46a..bb8db61f63 100644 --- a/lib/api/objectCopy.js +++ b/lib/api/objectCopy.js @@ -16,7 +16,7 @@ const logger = require('../utilities/logger'); const services = require('../services'); const { pushMetric } = require('../utapi/utilities'); const removeAWSChunked = require('./apiUtils/object/removeAWSChunked'); -const { metadataValidateBucketAndObj } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucketAndObj } = require('../metadata/metadataUtils'); const validateWebsiteHeader = require('./apiUtils/object/websiteServing') .validateWebsiteHeader; const { config } = require('../Config'); @@ -245,7 +245,7 @@ function objectCopy(authInfo, request, sourceBucket, } return async.waterfall([ function checkDestAuth(next) { - return metadataValidateBucketAndObj(valPutParams, log, + return standardMetadataValidateBucketAndObj(valPutParams, request.actionImplicitDenies, log, (err, destBucketMD, destObjMD) => { if (err) { log.debug('error validating put part of request', @@ -263,7 +263,7 @@ function objectCopy(authInfo, request, sourceBucket, }); }, function checkSourceAuthorization(destBucketMD, destObjMD, next) { - return metadataValidateBucketAndObj(valGetParams, log, + return standardMetadataValidateBucketAndObj(valGetParams, request.actionImplicitDenies, log, (err, sourceBucketMD, sourceObjMD) => { if (err) { log.debug('error validating get part of request', @@ -408,10 +408,15 @@ function objectCopy(authInfo, request, sourceBucket, return next(null, storeMetadataParams, dataLocator, destObjMD, serverSideEncryption, destBucketMD); } + const originalIdentityImpDenies = request.actionImplicitDenies; + // eslint-disable-next-line no-param-reassign + delete request.actionImplicitDenies; return data.copyObject(request, sourceLocationConstraintName, storeMetadataParams, dataLocator, dataStoreContext, backendInfoDest, sourceBucketMD, destBucketMD, serverSideEncryption, log, (err, results) => { + // eslint-disable-next-line no-param-reassign + request.actionImplicitDenies = originalIdentityImpDenies; if (err) { return next(err, destBucketMD); } diff --git a/lib/api/objectHead.js b/lib/api/objectHead.js index 738b9df259..7fe9ab54cd 100644 --- a/lib/api/objectHead.js +++ b/lib/api/objectHead.js @@ -10,7 +10,7 @@ const { getVersionIdResHeader } = require('./apiUtils/object/versioning'); const { getPartNumber, getPartSize, getPartCountFromMd5 } = require('./apiUtils/object/partInfo'); -const { metadataValidateBucketAndObj } = require('../metadata/metadataUtils'); +const { standardMetadataValidateBucketAndObj } = require('../metadata/metadataUtils'); const { maximumAllowedPartCount } = require('../../constants'); const { setExpirationHeaders } = require('./apiUtils/object/expirationHeaders'); @@ -48,7 +48,7 @@ function objectHead(authInfo, request, log, callback) { request, }; - return metadataValidateBucketAndObj(mdValParams, log, + return standardMetadataValidateBucketAndObj(mdValParams, request.actionImplicitDenies, log, (err, bucket, objMD) => { const corsHeaders = collectCorsHeaders(request.headers.origin, request.method, bucket); diff --git a/lib/api/websiteHead.js b/lib/api/websiteHead.js index 44f2f62a47..542445bca6 100644 --- a/lib/api/websiteHead.js +++ b/lib/api/websiteHead.js @@ -104,7 +104,7 @@ function websiteHead(request, log, callback) { { error: err }); let returnErr = err; const bucketAuthorized = isBucketAuthorized(bucket, - 'bucketGet', constants.publicId, null, log, request); + 'bucketGet', constants.publicId, null, log, request, request.actionImplicitDenies); // if index object does not exist and bucket is private AWS // returns 403 - AccessDenied error. if (err.is.NoSuchKey && !bucketAuthorized) { @@ -114,7 +114,7 @@ function websiteHead(request, log, callback) { reqObjectKey, corsHeaders, log, callback); } if (!isObjAuthorized(bucket, objMD, 'objectGet', - constants.publicId, null, log, request)) { + constants.publicId, null, log, request, request.actionImplicitDenies)) { const err = errors.AccessDenied; log.trace('request not authorized', { error: err }); return _errorActions(err, routingRules, reqObjectKey, diff --git a/lib/metadata/metadataUtils.js b/lib/metadata/metadataUtils.js index 7a33fb722f..1885aadf58 100644 --- a/lib/metadata/metadataUtils.js +++ b/lib/metadata/metadataUtils.js @@ -157,62 +157,6 @@ function validateBucket(bucket, params, log, actionImplicitDenies = {}) { return null; } -/** metadataValidateBucketAndObj - retrieve bucket and object md from metadata - * and check if user is authorized to access them. - * @param {object} params - function parameters - * @param {AuthInfo} params.authInfo - AuthInfo class instance, requester's info - * @param {string} params.bucketName - name of bucket - * @param {string} params.objectKey - name of object - * @param {string} [params.versionId] - version id if getting specific version - * @param {string} params.requestType - type of request - * @param {object} params.request - http request object - * @param {RequestLogger} log - request logger - * @param {function} callback - callback - * @return {undefined} - and call callback with params err, bucket md - */ -function metadataValidateBucketAndObj(params, log, callback) { - const { authInfo, bucketName, objectKey, versionId, request } = params; - let requestType = params.requestType; - if (!Array.isArray(requestType)) { - requestType = [requestType]; - } - async.waterfall([ - next => metadataGetBucketAndObject(bucketName, - objectKey, versionId, log, (err, bucket, objMD) => { - if (err) { - return next(err); - } - return next(null, bucket, objMD); - }), - (bucket, objMD, next) => { - const validationError = validateBucket(bucket, params, log); - if (validationError) { - return next(validationError, bucket); - } - if (objMD && versionId === 'null') { - return getNullVersion(objMD, bucketName, objectKey, log, - (err, nullVer) => next(err, bucket, nullVer)); - } - return next(null, bucket, objMD); - }, - (bucket, objMD, next) => { - const canonicalID = authInfo.getCanonicalID(); - if (!isObjAuthorized(bucket, objMD, requestType, canonicalID, authInfo, - log, request)) { - log.debug('access denied for user on object', { requestType }); - return next(errors.AccessDenied, bucket); - } - return next(null, bucket, objMD); - }, - ], (err, bucket, objMD) => { - if (err) { - // still return bucket for cors headers - return callback(err, bucket); - } - return callback(null, bucket, objMD); - }); -} - /** standardMetadataValidateBucketAndObj - retrieve bucket and object md from metadata * and check if user is authorized to access them. * @param {object} params - function parameters @@ -298,28 +242,6 @@ function metadataGetBucket(requestType, bucketName, log, cb) { }); } -/** metadataValidateBucket - retrieve bucket from metadata and check if user - * is authorized to access it - * @param {object} params - function parameters - * @param {AuthInfo} params.authInfo - AuthInfo class instance, requester's info - * @param {string} params.bucketName - name of bucket - * @param {string} params.requestType - type of request - * @param {string} params.request - http request object - * @param {RequestLogger} log - request logger - * @param {function} callback - callback - * @return {undefined} - and call callback with params err, bucket md - */ -function metadataValidateBucket(params, log, callback) { - const { bucketName, requestType } = params; - return metadataGetBucket(requestType, bucketName, log, (err, bucket) => { - if (err) { - return callback(err); - } - const validationError = validateBucket(bucket, params, log); - return callback(validationError, bucket); - }); -} - /** standardMetadataValidateBucket - retrieve bucket from metadata and check if user * is authorized to access it * @param {object} params - function parameters @@ -346,8 +268,6 @@ function standardMetadataValidateBucket(params, actionImplicitDenies, log, callb module.exports = { metadataGetObject, validateBucket, - metadataValidateBucketAndObj, standardMetadataValidateBucketAndObj, - metadataValidateBucket, standardMetadataValidateBucket, }; diff --git a/lib/routes/routeBackbeat.js b/lib/routes/routeBackbeat.js index 990a5d14c9..d70847014b 100644 --- a/lib/routes/routeBackbeat.js +++ b/lib/routes/routeBackbeat.js @@ -25,7 +25,7 @@ const prepareRequestContexts = require( const { decodeVersionId } = require('../api/apiUtils/object/versioning'); const locationKeysHaveChanged = require('../api/apiUtils/object/locationKeysHaveChanged'); -const { metadataValidateBucketAndObj, +const { standardMetadataValidateBucketAndObj, metadataGetObject } = require('../metadata/metadataUtils'); const { config } = require('../Config'); const constants = require('../../constants'); @@ -64,6 +64,7 @@ function _normalizeBackbeatRequest(req) { req.resourceType = pathArr[3]; req.bucketName = pathArr[4]; req.objectKey = pathArr.slice(5).join('/'); + req.actionImplicitDenies = false; /* eslint-enable no-param-reassign */ } @@ -1149,7 +1150,6 @@ function routeBackbeat(clientIP, request, response, log) { // Attach the apiMethod method to the request, so it can used by monitoring in the server // eslint-disable-next-line no-param-reassign request.apiMethod = 'routeBackbeat'; - log.debug('routing request', { method: 'routeBackbeat', url: request.url, @@ -1273,7 +1273,7 @@ function routeBackbeat(clientIP, request, response, log) { requestType: 'ReplicateObject', request, }; - return metadataValidateBucketAndObj(mdValParams, log, next); + return standardMetadataValidateBucketAndObj(mdValParams, request.actionImplicitDenies, log, next); }, (bucketInfo, objMd, next) => { if (useMultipleBackend) { diff --git a/package.json b/package.json index e8902b77be..d58891b4e3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "s3", - "version": "7.10.37", + "version": "7.10.38", "description": "S3 connector", "main": "index.js", "engines": { @@ -20,7 +20,7 @@ "homepage": "https://github.com/scality/S3#readme", "dependencies": { "@hapi/joi": "^17.1.0", - "arsenal": "git+https://github.com/scality/arsenal#7.10.49", + "arsenal": "git+https://github.com/scality/arsenal#7.10.51", "async": "~2.5.0", "aws-sdk": "2.905.0", "azure-storage": "^2.1.0", diff --git a/tests/multipleBackend/multipartUpload.js b/tests/multipleBackend/multipartUpload.js index 92511f4f0c..36f92da26e 100644 --- a/tests/multipleBackend/multipartUpload.js +++ b/tests/multipleBackend/multipartUpload.js @@ -54,6 +54,7 @@ const bucketPutRequest = { url: '/', post: '', parsedHost: 'localhost', + actionImplicitDenies: false, }; const awsETag = 'be747eb4b75517bf6b3cf7c5fbb62f3a'; @@ -73,6 +74,7 @@ const completeBody = '' + const basicParams = { bucketName, namespace, + actionImplicitDenies: false, }; function getObjectGetRequest(objectKey) { @@ -270,6 +272,7 @@ function mpuSetup(location, key, cb) { 'x-amz-meta-scal-location-constraint': location }, url: `/${key}?uploads`, parsedHost: 'localhost', + actionImplicitDenies: false, }; initiateMultipartUpload(authInfo, initiateRequest, log, (err, result) => { @@ -342,6 +345,7 @@ describe('Multipart Upload API with AWS Backend', function mpuTestSuite() { 'x-amz-meta-scal-location-constraint': `${awsLocation}` }, url: `/${objectKey}?uploads`, parsedHost: 'localhost', + actionImplicitDenies: false, }; initiateMultipartUpload(authInfo, initiateRequest, log, @@ -365,6 +369,7 @@ describe('Multipart Upload API with AWS Backend', function mpuTestSuite() { `${awsLocationMismatch}` }, url: `/${objectKey}?uploads`, parsedHost: 'localhost', + actionImplicitDenies: false, }; initiateMultipartUpload(authInfo, initiateRequest, log, @@ -389,6 +394,7 @@ describe('Multipart Upload API with AWS Backend', function mpuTestSuite() { }, url: `/${objectKey}?uploads`, parsedHost: 'localhost', + actionImplicitDenies: false, }; initiateMultipartUpload(authInfo, initiateRequest, log, @@ -612,6 +618,7 @@ describe('Multipart Upload API with AWS Backend', function mpuTestSuite() { 'x-amz-meta-scal-location-constraint': awsLocation }, url: `/${objectKey}?uploads`, parsedHost: 'localhost', + actionImplicitDenies: false, }; initiateMultipartUpload(authInfo, initiateRequest, log, err => { @@ -712,6 +719,7 @@ describe('Multipart Upload API with AWS Backend', function mpuTestSuite() { headers: { host: '/' }, url: `/${bucketName}?uploads`, query: {}, + actionImplicitDenies: false, }; listMultipartUploads(authInfo, listMpuParams, log, (err, mpuListXml) => { diff --git a/tests/unit/api/bucketHead.js b/tests/unit/api/bucketHead.js index c3cdfbf53c..0f203fcd19 100644 --- a/tests/unit/api/bucketHead.js +++ b/tests/unit/api/bucketHead.js @@ -14,6 +14,7 @@ const testRequest = { namespace, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: '/', + actionImplicitDenies: false, }; describe('bucketHead API', () => { beforeEach(() => { diff --git a/tests/unit/api/deleteMarker.js b/tests/unit/api/deleteMarker.js index 5082257e79..357475f25f 100644 --- a/tests/unit/api/deleteMarker.js +++ b/tests/unit/api/deleteMarker.js @@ -28,6 +28,7 @@ const testPutBucketRequest = new DummyRequest({ namespace, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: '/', + actionImplicitDenies: false, }); const testDeleteRequest = new DummyRequest({ bucketName, @@ -35,6 +36,7 @@ const testDeleteRequest = new DummyRequest({ objectKey: objectName, headers: {}, url: `/${bucketName}/${objectName}`, + actionImplicitDenies: false, }); function _createBucketPutVersioningReq(status) { @@ -45,6 +47,7 @@ function _createBucketPutVersioningReq(status) { }, url: '/?versioning', query: { versioning: '' }, + actionImplicitDenies: false, }; const xml = '' + @@ -62,6 +65,7 @@ function _createMultiObjectDeleteRequest(numObjects) { }, url: '/?delete', query: { delete: '' }, + actionImplicitDenies: false, }; const xml = []; xml.push(''); diff --git a/tests/unit/api/deletedFlagBucket.js b/tests/unit/api/deletedFlagBucket.js index c2bdb00088..412d936017 100644 --- a/tests/unit/api/deletedFlagBucket.js +++ b/tests/unit/api/deletedFlagBucket.js @@ -58,11 +58,13 @@ const baseTestRequest = { post: '', headers: { host: `${bucketName}.s3.amazonaws.com` }, query: {}, + actionImplicitDenies: false, }; const serviceGetRequest = { parsedHost: 's3.amazonaws.com', headers: { host: 's3.amazonaws.com' }, url: '/', + actionImplicitDenies: false, }; const userBucketOwner = 'admin'; diff --git a/tests/unit/api/listMultipartUploads.js b/tests/unit/api/listMultipartUploads.js index c655aa8b3c..e24fc13f40 100644 --- a/tests/unit/api/listMultipartUploads.js +++ b/tests/unit/api/listMultipartUploads.js @@ -32,6 +32,7 @@ describe('listMultipartUploads API', () => { namespace, headers: {}, url: `/${bucketName}`, + actionImplicitDenies: false, }; const testInitiateMPURequest1 = { bucketName, @@ -39,6 +40,7 @@ describe('listMultipartUploads API', () => { objectKey: objectName1, headers: {}, url: `/${bucketName}/${objectName1}?uploads`, + actionImplicitDenies: false, }; const testInitiateMPURequest2 = { bucketName, @@ -46,6 +48,7 @@ describe('listMultipartUploads API', () => { objectKey: objectName2, headers: {}, url: `/${bucketName}/${objectName2}?uploads`, + actionImplicitDenies: false, }; const testInitiateMPURequest3 = { bucketName, @@ -53,6 +56,7 @@ describe('listMultipartUploads API', () => { objectKey: objectName3, headers: {}, url: `/${bucketName}/${objectName3}?uploads`, + actionImplicitDenies: false, }; it('should return the name of the common prefix ' + @@ -65,6 +69,7 @@ describe('listMultipartUploads API', () => { headers: { host: '/' }, url: `/${bucketName}?uploads&delimiter=/&prefix=sub`, query: { delimiter, prefix }, + actionImplicitDenies: false, }; async.waterfall([ @@ -94,6 +99,7 @@ describe('listMultipartUploads API', () => { headers: { host: '/' }, url: `/${bucketName}?uploads`, query: {}, + actionImplicitDenies: false, }; @@ -127,6 +133,7 @@ describe('listMultipartUploads API', () => { headers: { host: '/' }, url: `/${bucketName}?uploads`, query: { 'max-uploads': '1' }, + actionImplicitDenies: false, }; async.waterfall([ @@ -163,6 +170,7 @@ describe('listMultipartUploads API', () => { headers: { host: '/' }, url: `/${bucketName}?uploads`, query: { 'encoding-type': 'url' }, + actionImplicitDenies: false, }; async.waterfall([ @@ -195,6 +203,7 @@ describe('listMultipartUploads API', () => { headers: { host: '/' }, url: `/${bucketName}?uploads`, query: { 'key-marker': objectName1 }, + actionImplicitDenies: false, }; async.waterfall([ diff --git a/tests/unit/api/listParts.js b/tests/unit/api/listParts.js index 525085838f..48a9668e11 100644 --- a/tests/unit/api/listParts.js +++ b/tests/unit/api/listParts.js @@ -114,6 +114,7 @@ describe('List Parts API', () => { url: `/${uploadKey}?uploadId=${uploadId}`, headers: { host: `${bucketName}.s3.amazonaws.com` }, query: { uploadId }, + actionImplicitDenies: false, }; listParts(authInfo, listRequest, log, (err, xml) => { @@ -160,6 +161,7 @@ describe('List Parts API', () => { uploadId, 'encoding-type': 'url', }, + actionImplicitDenies: false, }; const urlEncodedObjectKey = '%24makememulti'; @@ -185,6 +187,7 @@ describe('List Parts API', () => { uploadId, 'max-parts': '4', }, + actionImplicitDenies: false, }; listParts(authInfo, listRequest, log, (err, xml) => { @@ -226,6 +229,7 @@ describe('List Parts API', () => { uploadId, 'max-parts': '6', }, + actionImplicitDenies: false, }; listParts(authInfo, listRequest, log, (err, xml) => { @@ -267,6 +271,7 @@ describe('List Parts API', () => { uploadId, 'part-number-marker': '2', }, + actionImplicitDenies: false, }; listParts(authInfo, listRequest, log, (err, xml) => { @@ -312,6 +317,7 @@ describe('List Parts API', () => { 'part-number-marker': '2', 'max-parts': '2', }, + actionImplicitDenies: false, }; listParts(authInfo, listRequest, log, (err, xml) => { diff --git a/tests/unit/api/multipartDelete.js b/tests/unit/api/multipartDelete.js index b17c9c9e18..33bcfed19c 100644 --- a/tests/unit/api/multipartDelete.js +++ b/tests/unit/api/multipartDelete.js @@ -24,6 +24,7 @@ const bucketPutRequest = { namespace, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: '/', + actionImplicitDenies: false, }; const objectKey = 'testObject'; const initiateRequest = { @@ -32,6 +33,7 @@ const initiateRequest = { objectKey, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: `/${objectKey}?uploads`, + actionImplicitDenies: false, }; const eastLocation = 'us-east-1'; const westLocation = 'scality-internal-file'; @@ -68,6 +70,7 @@ function _createAndAbortMpu(usEastSetting, fakeUploadID, locationConstraint, partNumber: '1', uploadId, }, + actionImplicitDenies: false, }, partBody); const testUploadId = fakeUploadID ? 'nonexistinguploadid' : uploadId; @@ -78,6 +81,7 @@ function _createAndAbortMpu(usEastSetting, fakeUploadID, locationConstraint, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: `/${objectKey}?uploadId=${testUploadId}`, query: { uploadId: testUploadId }, + actionImplicitDenies: false, }; next(null, partRequest, deleteMpuRequest); }, diff --git a/tests/unit/api/multipartUpload.js b/tests/unit/api/multipartUpload.js index d21e27e112..c3ec0d7140 100644 --- a/tests/unit/api/multipartUpload.js +++ b/tests/unit/api/multipartUpload.js @@ -49,6 +49,7 @@ const bucketPutRequest = { 'xmlns="http://s3.amazonaws.com/doc/2006-03-01/">' + 'scality-internal-mem' + '', + actionImplicitDenies: false, }; const lockEnabledBucketRequest = Object.assign({}, bucketPutRequest); lockEnabledBucketRequest.bucketName = lockedBucket; @@ -62,6 +63,7 @@ const initiateRequest = { objectKey, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: `/${objectKey}?uploads`, + actionImplicitDenies: false, }; const retentionInitiateRequest = Object.assign({}, initiateRequest); retentionInitiateRequest.bucketName = lockedBucket; @@ -82,6 +84,7 @@ const getObjectLockInfoRequest = { namespace, objectKey, headers: { host: `${lockedBucket}.s3.amazonaws.com` }, + actionImplicitDenies: false, }; const expectedRetentionConfig = { $: { xmlns: 'http://s3.amazonaws.com/doc/2006-03-01/' }, @@ -106,6 +109,7 @@ function _createPutPartRequest(uploadId, partNumber, partBody) { uploadId, }, calculatedHash, + actionImplicitDenies: false, }, partBody); } @@ -128,6 +132,7 @@ function _createCompleteMpuRequest(uploadId, parts) { headers: { host: `${bucketName}.s3.amazonaws.com` }, query: { uploadId }, post: completeBody, + actionImplicitDenies: false, }; } @@ -542,6 +547,7 @@ describe('Multipart Upload API', () => { headers: { host: `${bucketName}.s3.amazonaws.com` }, query: { uploadId: testUploadId }, post: completeBody, + actionImplicitDenies: false, }; const awsVerifiedETag = '"953e9e776f285afc0bfcf1ab4668299d-1"'; @@ -630,6 +636,7 @@ describe('Multipart Upload API', () => { headers: { host: `${bucketName}.s3.amazonaws.com` }, query: { uploadId: testUploadId }, post: completeBody, + actionImplicitDenies: false, }; const awsVerifiedETag = '"953e9e776f285afc0bfcf1ab4668299d-1"'; @@ -702,6 +709,7 @@ describe('Multipart Upload API', () => { query: { uploadId: testUploadId }, post: completeBody, calculatedHash, + actionImplicitDenies: false, }; completeMultipartUpload(authInfo, completeRequest, log, err => { @@ -757,6 +765,7 @@ describe('Multipart Upload API', () => { query: { uploadId: testUploadId }, post: completeBody, calculatedHash, + actionImplicitDenies: false, }; completeMultipartUpload(authInfo, completeRequest, log, err => { assert(err.is.MalformedXML); @@ -829,6 +838,7 @@ describe('Multipart Upload API', () => { query: { uploadId: testUploadId }, post: completeBody, calculatedHash, + actionImplicitDenies: false, }; completeMultipartUpload(authInfo, completeRequest, log, err => { @@ -887,6 +897,7 @@ describe('Multipart Upload API', () => { query: { uploadId: testUploadId }, post: completeBody, calculatedHash, + actionImplicitDenies: false, }; completeMultipartUpload(authInfo, completeRequest, log, err => { assert(err.is.InvalidPart); @@ -958,6 +969,7 @@ describe('Multipart Upload API', () => { query: { uploadId: testUploadId }, post: completeBody, calculatedHash, + actionImplicitDenies: false, }; assert.strictEqual(metadata.keyMaps.get(mpuBucket).size, 3); completeMultipartUpload(authInfo, @@ -1040,6 +1052,7 @@ describe('Multipart Upload API', () => { query: { uploadId: testUploadId }, post: completeBody, calculatedHash, + actionImplicitDenies: false, }; assert.strictEqual(metadata.keyMaps.get(mpuBucket).size, 3); completeMultipartUpload(authInfo, @@ -1122,6 +1135,7 @@ describe('Multipart Upload API', () => { query: { uploadId: testUploadId }, post: completeBody, calculatedHash, + actionImplicitDenies: false, }; completeMultipartUpload(authInfo, completeRequest, log, (err, result) => { @@ -1153,6 +1167,7 @@ describe('Multipart Upload API', () => { 'x-amz-acl': 'authenticated-read', }, url: `/${objectKey}?uploads`, + actionImplicitDenies: false, }; async.waterfall([ @@ -1221,6 +1236,7 @@ describe('Multipart Upload API', () => { query: { uploadId: testUploadId }, post: completeBody, calculatedHash, + actionImplicitDenies: false, }; completeMultipartUpload(authInfo, completeRequest, log, (err, result) => { @@ -1255,6 +1271,7 @@ describe('Multipart Upload API', () => { 'x-amz-grant-read': `emailAddress="${granteeEmail}"`, }, url: `/${objectKey}?uploads`, + actionImplicitDenies: false, }; async.waterfall([ @@ -1323,6 +1340,7 @@ describe('Multipart Upload API', () => { query: { uploadId: testUploadId }, post: completeBody, calculatedHash, + actionImplicitDenies: false, }; completeMultipartUpload(authInfo, completeRequest, log, (err, result) => { @@ -1375,6 +1393,7 @@ describe('Multipart Upload API', () => { url: `/${objectKey}?uploadId=${testUploadId}`, headers: { host: `${bucketName}.s3.amazonaws.com` }, query: { uploadId: testUploadId }, + actionImplicitDenies: false, }; assert.strictEqual(metadata.keyMaps.get(mpuBucket).size, 2); multipartDelete(authInfo, deleteRequest, log, err => { @@ -1425,6 +1444,7 @@ describe('Multipart Upload API', () => { url: `/${objectKey}?uploadId=${testUploadId}`, headers: { host: `${bucketName}.s3.amazonaws.com` }, query: { uploadId: 'non-existent-upload-id' }, + actionImplicitDenies: false, }; assert.strictEqual(metadata.keyMaps.get(mpuBucket).size, 2); multipartDelete(authInfo, deleteRequest, log, err => { @@ -1504,6 +1524,7 @@ describe('Multipart Upload API', () => { headers: { host: `${bucketName}.s3.amazonaws.com` }, query: { uploadId: testUploadId }, post: completeBody, + actionImplicitDenies: false, }; completeMultipartUpload(authInfo, completeRequest, log, (err, result) => { @@ -1557,6 +1578,7 @@ describe('Multipart Upload API', () => { headers: { host: `${bucketName}.s3.amazonaws.com` }, query: { uploadId: testUploadId }, post: completeBody, + actionImplicitDenies: false, }; completeMultipartUpload(authInfo, completeRequest, log, next); }, @@ -1628,6 +1650,7 @@ describe('Multipart Upload API', () => { headers: { host: `${bucketName}.s3.amazonaws.com` }, query: { uploadId }, post: completeBody, + actionImplicitDenies: false, }; completeMultipartUpload(authInfo, completeRequest, log, next); }, @@ -1698,6 +1721,7 @@ describe('Multipart Upload API', () => { headers: { host: `${bucketName}.s3.amazonaws.com` }, query: { uploadId }, post: completeBody, + actionImplicitDenies: false, }; completeMultipartUpload(authInfo, completeRequest, log, done); }, @@ -1790,6 +1814,7 @@ describe('Multipart Upload API', () => { query: { uploadId: testUploadId }, post: completeBody, calculatedHash, + actionImplicitDenies: false, }; // show that second part data is there assert(ds[2]); diff --git a/tests/unit/api/objectHead.js b/tests/unit/api/objectHead.js index e0dab2e8c3..a917835a2a 100644 --- a/tests/unit/api/objectHead.js +++ b/tests/unit/api/objectHead.js @@ -29,6 +29,7 @@ const testPutBucketRequest = { namespace, headers: {}, url: `/${bucketName}`, + actionImplicitDenies: false, }; const userMetadataKey = 'x-amz-meta-test'; const userMetadataValue = 'some metadata'; @@ -57,6 +58,7 @@ describe('objectHead API', () => { objectKey: objectName, headers: { 'if-modified-since': laterDate }, url: `/${bucketName}/${objectName}`, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -80,6 +82,7 @@ describe('objectHead API', () => { objectKey: objectName, headers: { 'if-unmodified-since': earlierDate }, url: `/${bucketName}/${objectName}`, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -105,6 +108,7 @@ describe('objectHead API', () => { objectKey: objectName, headers: { 'if-match': incorrectMD5 }, url: `/${bucketName}/${objectName}`, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -129,6 +133,7 @@ describe('objectHead API', () => { objectKey: objectName, headers: { 'if-none-match': correctMD5 }, url: `/${bucketName}/${objectName}`, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -151,6 +156,7 @@ describe('objectHead API', () => { objectKey: objectName, headers: { range: 'bytes=1-9' }, url: `/${bucketName}/${objectName}`, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -175,6 +181,7 @@ describe('objectHead API', () => { query: { partNumber: '1', }, + actionImplicitDenies: false, }; const customizedInvalidRequestError = errors.InvalidRequest .customizeDescription('Cannot specify both Range header and ' + @@ -202,6 +209,7 @@ describe('objectHead API', () => { query: { partNumber: 'nan', }, + actionImplicitDenies: false, }; const customizedInvalidArgumentError = errors.InvalidArgument .customizeDescription('Part number must be a number.'); @@ -226,6 +234,7 @@ describe('objectHead API', () => { objectKey: objectName, headers: {}, url: `/${bucketName}/${objectName}`, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -246,6 +255,7 @@ describe('objectHead API', () => { objectKey: objectName, headers: {}, url: `/${bucketName}/${objectName}`, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequest, log, () => { @@ -269,6 +279,7 @@ describe('objectHead API', () => { namespace, headers: { 'x-amz-bucket-object-lock-enabled': 'true' }, url: `/${bucketName}`, + actionImplicitDenies: false, }; const testPutObjectRequestLock = new DummyRequest({ bucketName, @@ -288,6 +299,7 @@ describe('objectHead API', () => { objectKey: objectName, headers: {}, url: `/${bucketName}/${objectName}`, + actionImplicitDenies: false, }; bucketPut(authInfo, testPutBucketRequestLock, log, () => { diff --git a/tests/unit/api/objectReplicationMD.js b/tests/unit/api/objectReplicationMD.js index 4f0aee8efb..fa388f4875 100644 --- a/tests/unit/api/objectReplicationMD.js +++ b/tests/unit/api/objectReplicationMD.js @@ -48,6 +48,7 @@ const objectACLReq = { }, url: `/${bucketName}/${keyA}?acl`, query: { acl: '' }, + actionImplicitDenies: false, }; // Get an object request with the given key. @@ -185,6 +186,7 @@ function putMPU(key, body, cb) { headers: { host: `${bucketName}.s3.amazonaws.com` }, query: { uploadId }, post: postBody, + actionImplicitDenies: false, }; return completeMultipartUpload(authInfo, req, log, cb); } diff --git a/tests/unit/api/transientBucket.js b/tests/unit/api/transientBucket.js index c80c1de54d..134654e1ec 100644 --- a/tests/unit/api/transientBucket.js +++ b/tests/unit/api/transientBucket.js @@ -53,11 +53,13 @@ const baseTestRequest = { url: '/', post: '', headers: { host: `${bucketName}.s3.amazonaws.com` }, + actionImplicitDenies: false, }; const serviceGetRequest = { parsedHost: 's3.amazonaws.com', headers: { host: 's3.amazonaws.com' }, url: '/', + actionImplicitDenies: false, }; const userBucketOwner = 'admin'; diff --git a/tests/unit/utils/bucketEncryption.js b/tests/unit/utils/bucketEncryption.js index 7577689e42..63cb33df9a 100644 --- a/tests/unit/utils/bucketEncryption.js +++ b/tests/unit/utils/bucketEncryption.js @@ -29,6 +29,7 @@ function templateRequest(bucketName, { post }) { bucketName, headers: { host: `${bucketName}.s3.amazonaws.com` }, post, + actionImplicitDenies: false, }; } diff --git a/tests/unit/utils/lifecycleHelpers.js b/tests/unit/utils/lifecycleHelpers.js index 0cbb88d660..b9399b00ac 100644 --- a/tests/unit/utils/lifecycleHelpers.js +++ b/tests/unit/utils/lifecycleHelpers.js @@ -4,6 +4,7 @@ function getLifecycleRequest(bucketName, xml) { headers: { host: `${bucketName}.s3.amazonaws.com`, }, + actionImplicitDenies: false, }; if (xml) { request.post = xml; diff --git a/tests/unit/utils/mpuUtils.js b/tests/unit/utils/mpuUtils.js index 7fc2193eec..7100a0ccb0 100644 --- a/tests/unit/utils/mpuUtils.js +++ b/tests/unit/utils/mpuUtils.js @@ -28,6 +28,7 @@ function createinitiateMPURequest(namespace, bucketName, objectKey) { objectKey, headers: { host: `${bucketName}.s3.amazonaws.com` }, url: `/${objectKey}?uploads`, + actionImplicitDenies: false, }; return request; @@ -45,6 +46,7 @@ function createPutPartRequest(namespace, bucketName, objectKey, partNumber, test uploadId: testUploadId, }, calculatedHash, + actionImplicitDenies: false, }, partBody); return request; @@ -68,6 +70,7 @@ function createCompleteRequest(namespace, bucketName, objectKey, testUploadId) { headers: { host: `${bucketName}.s3.amazonaws.com` }, query: { uploadId: testUploadId }, post: completeBody, + actionImplicitDenies: false, }; return request; diff --git a/yarn.lock b/yarn.lock index 02cd927998..cb6d98d4de 100644 --- a/yarn.lock +++ b/yarn.lock @@ -488,9 +488,9 @@ arraybuffer.slice@~0.0.7: optionalDependencies: ioctl "^2.0.2" -"arsenal@git+https://github.com/scality/arsenal#7.10.49": - version "7.10.49" - resolved "git+https://github.com/scality/arsenal#fbf5562a1180055249745881c1a324562d7cdc8a" +"arsenal@git+https://github.com/scality/arsenal#7.10.51": + version "7.10.51" + resolved "git+https://github.com/scality/arsenal#477a574500318b183e5805e6d15ef2aef8f74d02" dependencies: "@types/async" "^3.2.12" "@types/utf8" "^3.0.1"