diff --git a/.github/actions/cleanup-and-coverage/action.yaml b/.github/actions/cleanup-and-coverage/action.yaml new file mode 100644 index 0000000000..8af4310092 --- /dev/null +++ b/.github/actions/cleanup-and-coverage/action.yaml @@ -0,0 +1,40 @@ +name: 'Cleanup and Coverage' +description: 'Stops CI services and uploads coverage reports to Codecov' + +inputs: + profiles: + description: 'Docker Compose profiles to use (space-separated)' + required: false + default: '' + codecov-token: + description: 'Codecov token for uploading reports' + required: true + flags: + description: 'Flags to identify the coverage report' + required: false + default: '${{ github.job }}' + +runs: + using: 'composite' + steps: + - name: Stop CI services + run: | + PROFILES="" + # Read from environment variable to avoid syntax issues + # related to gha templating + for profile in $INPUT_PROFILES; do + PROFILES="${PROFILES} --profile ${profile}" + done + docker compose ${PROFILES} down + shell: bash + env: + INPUT_PROFILES: ${{ inputs.profiles }} + working-directory: .github/docker + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v5 + with: + token: ${{ inputs.codecov-token }} + directory: /tmp/coverage/${{ github.job }} + flags: ${{ inputs.flags }} + if: ${{ !cancelled() }} diff --git a/.github/actions/setup-ci/action.yaml b/.github/actions/setup-ci/action.yaml index b943f7c57c..785b0295b4 100644 --- a/.github/actions/setup-ci/action.yaml +++ b/.github/actions/setup-ci/action.yaml @@ -16,6 +16,11 @@ runs: run: |- set -exu; mkdir -p /tmp/artifacts/${JOB_NAME}/; + - name: Setup coverage directory + shell: bash + run: |- + set -exu; + mkdir -p /tmp/coverage/${JOB_NAME}/; - uses: actions/setup-node@v4 with: node-version: '22' diff --git a/.github/docker/docker-compose.yaml b/.github/docker/docker-compose.yaml index f36e2b8fa1..b26fd2144b 100644 --- a/.github/docker/docker-compose.yaml +++ b/.github/docker/docker-compose.yaml @@ -1,13 +1,28 @@ services: cloudserver: image: ${CLOUDSERVER_IMAGE} - command: sh -c "yarn start > /artifacts/s3.log" + command: | + bash -c " + # Using tini to handle signals properly + tini -s -g -- npx nyc --clean --silent yarn start > /artifacts/s3.log & + PID=$$! + generate_coverage() { + echo 'Stopping NodeJS processes...' + kill -TERM $$PID 2>/dev/null || true + wait $$PID + echo 'Generating coverage report...' + npx nyc report --report-dir /coverage/test --reporter=lcov --reporter=text-summary + } + trap generate_coverage SIGTERM + wait $$PID + " network_mode: "host" volumes: - /tmp/ssl:/ssl - /tmp/ssl-kmip:/ssl-kmip - ${HOME}/.aws/credentials:/root/.aws/credentials - /tmp/artifacts/${JOB_NAME}:/artifacts + - /tmp/coverage/${JOB_NAME}:/coverage/test environment: - CI=true - ENABLE_LOCAL_CACHE=true diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index edc83d3c83..9eb81e6a7a 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -229,6 +229,7 @@ jobs: S3BACKEND: mem S3_LOCATION_FILE: /usr/src/app/tests/locationConfig/locationConfigTests.json S3DATA: multiple + S3METADATA: mongodb JOB_NAME: ${{ github.job }} steps: - name: Checkout @@ -242,7 +243,7 @@ jobs: - name: Setup CI environment uses: ./.github/actions/setup-ci - name: Setup CI services - run: docker compose --profile sproxyd up -d + run: docker compose --profile sproxyd --profile mongo up -d working-directory: .github/docker - name: Run multiple backend test run: |- @@ -252,6 +253,14 @@ jobs: yarn run multiple_backend_test | tee /tmp/artifacts/${{ github.job }}/tests.log env: S3_LOCATION_FILE: tests/locationConfig/locationConfigTests.json + - name: Cleanup and upload coverage + uses: ./.github/actions/cleanup-and-coverage + with: + profiles: > + sproxyd + mongo + codecov-token: ${{ secrets.CODECOV_TOKEN }} + if: always() - name: Upload logs to artifacts uses: scality/action-artifacts@v4 with: @@ -290,6 +299,12 @@ jobs: yarn run ft_test | tee /tmp/artifacts/${{ github.job }}/tests.log env: S3_LOCATION_FILE: tests/locationConfig/locationConfigTests.json + - name: Cleanup and upload coverage + uses: ./.github/actions/cleanup-and-coverage + with: + profiles: mongo + codecov-token: ${{ secrets.CODECOV_TOKEN }} + if: always() - name: Upload logs to artifacts uses: scality/action-artifacts@v4 with: @@ -330,6 +345,12 @@ jobs: yarn run ft_mixed_bucket_format_version | tee /tmp/artifacts/${{ github.job }}/mixed-tests.log env: S3_LOCATION_FILE: tests/locationConfig/locationConfigTests.json + - name: Cleanup and upload coverage + uses: ./.github/actions/cleanup-and-coverage + with: + profiles: mongo + codecov-token: ${{ secrets.CODECOV_TOKEN }} + if: always() - name: Upload logs to artifacts uses: scality/action-artifacts@v4 with: @@ -373,6 +394,12 @@ jobs: set -o pipefail; bash wait_for_local_port.bash 8000 40 yarn run ft_test | tee /tmp/artifacts/${{ matrix.job-name }}/tests.log + - name: Cleanup and upload coverage + uses: ./.github/actions/cleanup-and-coverage + with: + codecov-token: ${{ secrets.CODECOV_TOKEN }} + flags: ${{ matrix.job-name }} + if: always() - name: Upload logs to artifacts uses: scality/action-artifacts@v4 with: @@ -407,6 +434,11 @@ jobs: set -ex -o pipefail; bash wait_for_local_port.bash 8000 40 yarn run test_utapi_v2 | tee /tmp/artifacts/${{ github.job }}/tests.log + - name: Cleanup and upload coverage + uses: ./.github/actions/cleanup-and-coverage + with: + codecov-token: ${{ secrets.CODECOV_TOKEN }} + if: always() - name: Upload logs to artifacts uses: scality/action-artifacts@v4 with: @@ -451,6 +483,13 @@ jobs: set -ex -o pipefail; bash wait_for_local_port.bash 8000 40 yarn run test_quota | tee /tmp/artifacts/${{ github.job }}/tests.log + - name: Cleanup and upload coverage + uses: ./.github/actions/cleanup-and-coverage + with: + profiles: mongo + codecov-token: ${{ secrets.CODECOV_TOKEN }} + flags: ${{ github.job }}${{ matrix.inflights.value == 'true' && '-inflights' || '' }} + if: always() - name: Upload logs to artifacts uses: scality/action-artifacts@v4 with: @@ -489,6 +528,12 @@ jobs: bash wait_for_local_port.bash 8000 40 bash wait_for_local_port.bash 5696 40 yarn run ft_kmip | tee /tmp/artifacts/${{ github.job }}/tests.log + - name: Cleanup and upload coverage + uses: ./.github/actions/cleanup-and-coverage + with: + profiles: pykmip + codecov-token: ${{ secrets.CODECOV_TOKEN }} + if: always() - name: Upload logs to artifacts uses: scality/action-artifacts@v4 with: @@ -567,6 +612,12 @@ jobs: S3BACKEND: file S3VAULT: mem S3METADATA: mongodb + - name: Cleanup and upload coverage + uses: ./.github/actions/cleanup-and-coverage + with: + profiles: ceph + codecov-token: ${{ secrets.CODECOV_TOKEN }} + if: always() - name: Upload logs to artifacts uses: scality/action-artifacts@v4 with: diff --git a/Dockerfile b/Dockerfile index e9b9408cbf..61dce92fd0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,11 +32,6 @@ RUN yarn install --production --ignore-optional --frozen-lockfile --ignore-engin ################################################################################ FROM node:${NODE_VERSION} -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - jq \ - && rm -rf /var/lib/apt/lists/* - ENV NO_PROXY=localhost,127.0.0.1 ENV no_proxy=localhost,127.0.0.1 diff --git a/lib/auth/streamingV4/V4Transform.js b/lib/auth/streamingV4/V4Transform.js index e28d6efcfb..e18d20e14f 100644 --- a/lib/auth/streamingV4/V4Transform.js +++ b/lib/auth/streamingV4/V4Transform.js @@ -165,7 +165,7 @@ class V4Transform extends Transform { credentialScope: this.credentialScope, }, }; - return vault.authenticateV4Request(vaultParams, null, err => { + return vault.authenticateV4Request(vaultParams, null, {}, err => { if (err) { this.log.trace('err from vault on streaming v4 auth', { error: err, paramsSentToVault: vaultParams.data }); diff --git a/lib/routes/routeBackbeat.js b/lib/routes/routeBackbeat.js index f978d85a5f..172f0dc6d7 100644 --- a/lib/routes/routeBackbeat.js +++ b/lib/routes/routeBackbeat.js @@ -464,6 +464,44 @@ function putData(request, response, bucketInfo, objMd, log, callback) { }); } +/** + * @callback CanonicalIdCallback + * @param {Error|null} err - Error object if operation failed, null otherwise + * @param {Object} [result] - Result object containing account information + * @param {string} [result.accountId] - The account ID + * @param {string} [result.canonicalId] - The canonical ID associated with the account + * @param {string} [result.name] - The display name associated with the account + * @returns {undefined} + */ + +/** + * + * @param {string} accountId - account ID + * @param {Log} log - logger instance + * @param {CanonicalIdCallback} cb - callback function + * @returns {undefined} + */ +function getCanonicalIdsByAccountId(accountId, log, cb) { + return vault.getCanonicalIdsByAccountIds([accountId], log, (err, res) => { + if (err) { + log.error('error getting canonical ID by account ID', { + error: err, + accountId, + method: 'getCanonicalIdsByAccountIds', + }); + return cb(err); + } + if (res.length === 0) { + log.error('account ID not found', { + accountId, + method: 'getCanonicalIdsByAccountIds', + }); + return cb(errors.AccountNotFound); + } + return cb(null, res[0]); + }); +} + function putMetadata(request, response, bucketInfo, objMd, log, callback) { return _getRequestPayload(request, (err, payload) => { if (err) { @@ -578,6 +616,17 @@ function putMetadata(request, response, bucketInfo, objMd, log, callback) { // To prevent this, the versionId field is only included in options when it is defined. if (versionId !== undefined) { options.versionId = versionId; + // In the MongoDB metadata backend, setting the versionId option leads to the creation + // or update of the version object, the master object is only updated if its versionId + // is the same as the version. This can lead to inconsistencies when replicating objects + // in the wrong order (can happen when retrying after failures), where the master object + // might point to a non current version. To prevent this, we need to set repairMaster to + // true which will update the master to the latest version available at the time of the put. + // The update is only done when putting a new version as updating versions that already exist + // shouldn't affect the master. + if (!objMd) { + options.repairMaster = true; + } } // If the new null keys logic (S3C-7352) is not supported (compatibility mode), 'isNull' remains undefined. @@ -585,55 +634,79 @@ function putMetadata(request, response, bucketInfo, objMd, log, callback) { options.isNull = isNull; } - log.trace('putting object version', { - objectKey: request.objectKey, omVal, options }); - return metadata.putObjectMD(bucketName, objectKey, omVal, options, log, - (err, md) => { - if (err) { - log.error('error putting object metadata', { - error: err, - method: 'putMetadata', - }); - return callback(err); + return async.series([ + // Zenko's CRR delegates replacing the account + // information to the destination's Cloudserver, as + // Vault admin APIs are not exposed externally. + next => { + // Internal users of this API (other features in Zenko) will + // not provide the accountId in the request, as they only update + // the metadata of existing objects, so there is no need to + // replace the account information. + if (!request.query?.accountId) { + return next(); } - pushReplicationMetric(objMd, omVal, bucketName, objectKey, log); - if (objMd && - headers['x-scal-replication-content'] !== 'METADATA' && - versionId && - // The new data location is set to null when archiving to a Cold site. - // In that case "removing old data location key" is handled by the lifecycle - // transition processor. - omVal.location && Array.isArray(omVal.location) && - locationKeysHaveChanged(objMd.location, omVal.location)) { - log.info('removing old data locations', { - method: 'putMetadata', - bucketName, - objectKey, - }); - async.eachLimit(objMd.location, 5, - (loc, next) => dataWrapper.data.delete(loc, log, err => { + return getCanonicalIdsByAccountId(request.query.accountId, log, (err, res) => { + if (err) { + return next(err); + } + omVal['owner-display-name'] = res.name; + omVal['owner-id'] = res.canonicalId; + return next(); + }); + }, + next => { + log.trace('putting object version', { + objectKey: request.objectKey, omVal, options }); + return metadata.putObjectMD(bucketName, objectKey, omVal, options, log, + (err, md) => { if (err) { - log.warn('error removing old data location key', { + log.error('error putting object metadata', { + error: err, + method: 'putMetadata', + }); + return next(err); + } + pushReplicationMetric(objMd, omVal, bucketName, objectKey, log); + if (objMd && + headers['x-scal-replication-content'] !== 'METADATA' && + versionId && + // The new data location is set to null when archiving to a Cold site. + // In that case "removing old data location key" is handled by the lifecycle + // transition processor. + omVal.location && Array.isArray(omVal.location) && + locationKeysHaveChanged(objMd.location, omVal.location)) { + log.info('removing old data locations', { + method: 'putMetadata', bucketName, objectKey, - locationKey: loc, - error: err.message, + }); + async.eachLimit(objMd.location, 5, + (loc, nextEach) => dataWrapper.data.delete(loc, log, err => { + if (err) { + log.warn('error removing old data location key', { + bucketName, + objectKey, + locationKey: loc, + error: err.message, + }); + } + // do not forward the error to let other + // locations be deleted + nextEach(); + }), + () => { + log.debug('done removing old data locations', { + method: 'putMetadata', + bucketName, + objectKey, + }); }); } - // do not forward the error to let other - // locations be deleted - next(); - }), - () => { - log.debug('done removing old data locations', { - method: 'putMetadata', - bucketName, - objectKey, - }); + return _respond(response, md, log, next); }); - } - return _respond(response, md, log, callback); - }); + } + ], callback); }); } diff --git a/package.json b/package.json index 029915c6fa..6c4f46dfb7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@zenko/cloudserver", - "version": "9.0.5", + "version": "9.0.6", "description": "Zenko CloudServer, an open-source Node.js implementation of a server handling the Amazon S3 protocol", "main": "index.js", "engines": { @@ -21,7 +21,7 @@ "dependencies": { "@azure/storage-blob": "^12.25.0", "@hapi/joi": "^17.1.1", - "arsenal": "git+https://github.com/scality/arsenal#8.2.5", + "arsenal": "git+https://github.com/scality/arsenal#8.2.8", "async": "2.6.4", "aws-sdk": "^2.1692.0", "bucketclient": "scality/bucketclient#8.2.0", @@ -117,7 +117,7 @@ "test_legacy_location": "CI=true S3QUOTA=scuba S3_LOCATION_FILE=tests/locationConfig/locationConfigLegacy.json S3BACKEND=mem mocha --reporter mocha-multi-reporters --reporter-options configFile=$INIT_CWD/tests/reporter-config.json --recursive tests/unit --exit", "test_utapi_v2": "mocha --reporter mocha-multi-reporters --reporter-options configFile=$INIT_CWD/tests/reporter-config.json --recursive tests/utapi --exit", "test_quota": "mocha --reporter mocha-multi-reporters --reporter-options configFile=$INIT_CWD/tests/reporter-config.json --recursive tests/quota --exit", - "multiple_backend_test": "CI=true S3BACKEND=mem S3DATA=multiple mocha --reporter mocha-multi-reporters --reporter-options configFile=$INIT_CWD/tests/reporter-config.json -t 20000 --recursive tests/multipleBackend --exit", + "multiple_backend_test": "CI=true S3BACKEND=mem S3METADATA=mem S3DATA=multiple mocha --reporter mocha-multi-reporters --reporter-options configFile=$INIT_CWD/tests/reporter-config.json -t 20000 --recursive tests/multipleBackend --exit", "cover": "nyc --clean --silent yarn run", "postcover": "nyc report --report-dir ./coverage/test --reporter=lcov" } diff --git a/tests/multipleBackend/routes/routeBackbeat.js b/tests/multipleBackend/routes/routeBackbeat.js index 76496f94c0..4bb6a0b6e9 100644 --- a/tests/multipleBackend/routes/routeBackbeat.js +++ b/tests/multipleBackend/routes/routeBackbeat.js @@ -153,6 +153,7 @@ function updateStorageClass(data, storageClass) { try { const parsedBody = JSON.parse(JSON.parse(data.body).Body); parsedBody['x-amz-storage-class'] = storageClass; + parsedBody['location'] = []; result = JSON.stringify(parsedBody); } catch (err) { return { error: err }; @@ -751,7 +752,7 @@ describe('backbeat routes', () => { }); }); - it('should create a new null version if versioning suspended and delete marker null version', done => { + it.skip('should create a new null version if versioning suspended and delete marker null version', done => { let objMD; return async.series([ next => s3.putBucketVersioning({ Bucket: bucket, VersioningConfiguration: { Status: 'Suspended' } }, diff --git a/tests/multipleBackend/routes/routeBackbeatForReplication.js b/tests/multipleBackend/routes/routeBackbeatForReplication.js index adde8ed1a6..e4c717ed3f 100644 --- a/tests/multipleBackend/routes/routeBackbeatForReplication.js +++ b/tests/multipleBackend/routes/routeBackbeatForReplication.js @@ -2,57 +2,587 @@ const assert = require('assert'); const async = require('async'); const { models } = require('arsenal'); const { ObjectMD } = models; +const { v4: uuidv4 } = require('uuid'); const { makeBackbeatRequest } = require('../../functional/raw-node/utils/makeRequest'); const BucketUtility = require('../../functional/aws-node-sdk/lib/utility/bucket-util'); const { getCredentials } = require('../../functional/aws-node-sdk/test/support/credentials'); -const { accessKeyId, secretAccessKey } = getCredentials(); +const sourceCreds = getCredentials(); +const sourceAuthCredentials = { + accessKey: sourceCreds.accessKeyId, + secretKey: sourceCreds.secretAccessKey, +}; -const backbeatAuthCredentials = { - accessKey: accessKeyId, - secretKey: secretAccessKey, +const destinationCreds = getCredentials('replication'); +const destinationAuthCredentials = { + accessKey: destinationCreds.accessKeyId, + secretKey: destinationCreds.secretAccessKey, }; +const dstAccountInfo = require('../../../conf/authdata.json') + .accounts.find(acc => acc.name === 'Replication'); + const testData = 'testkey data'; -// Skip since Zenko/Artesca use cloud storage provider clients like AWS SDK -// to replicate objects/versions rather than using the get and put metadata -// functions of the Backbeat API. -describe.skip('backbeat routes for replication', () => { - const bucketUtil = new BucketUtility( - 'default', { signatureVersion: 'v4' }); - const s3 = bucketUtil.s3; +// Generate unique bucket name function +function generateUniqueBucketName(prefix) { + return `${prefix}-${uuidv4().substring(0, 8)}`; +} + +function objectMDFromRequestBody(data) { + const bodyStr = JSON.parse(data.body).Body; + return new ObjectMD(JSON.parse(bodyStr)); +} + +describe('backbeat routes for replication', () => { + const srcBucketUtil = new BucketUtility('default', { signatureVersion: 'v4' }); + const srcS3 = srcBucketUtil.s3; + + const dstBucketUtil = new BucketUtility('replication', { signatureVersion: 'v4' }); + const dstS3 = dstBucketUtil.s3; - const bucketSource = 'backbeatbucket-replication-source'; - const bucketDestination = 'backbeatbucket-replication-destination'; + let bucketSource; + let bucketDestination; const keyName = 'key0'; const storageClass = 'foo'; - beforeEach(done => - bucketUtil.emptyIfExists(bucketSource) - .then(() => s3.createBucket({ Bucket: bucketSource }).promise()) - .then(() => bucketUtil.emptyIfExists(bucketDestination)) - .then(() => s3.createBucket({ Bucket: bucketDestination }).promise()) - .then(() => done(), err => done(err)) - ); - - afterEach(done => - bucketUtil.empty(bucketSource) - .then(() => s3.deleteBucket({ Bucket: bucketSource }).promise()) - .then(() => bucketUtil.empty(bucketDestination)) - .then(() => s3.deleteBucket({ Bucket: bucketDestination }).promise()) - .then(() => done(), err => done(err)) - ); + beforeEach(async () => { + bucketSource = generateUniqueBucketName('backbeatbucket-replication-source'); + bucketDestination = generateUniqueBucketName('backbeatbucket-replication-destination'); + await srcBucketUtil.emptyIfExists(bucketSource); + await srcS3.createBucket({ Bucket: bucketSource }).promise(); + await dstBucketUtil.emptyIfExists(bucketDestination); + await dstS3.createBucket({ Bucket: bucketDestination }).promise(); + }); + + afterEach(async () => { + await srcBucketUtil.empty(bucketSource); + await srcS3.deleteBucket({ Bucket: bucketSource }).promise(); + await dstBucketUtil.empty(bucketDestination); + await dstS3.deleteBucket({ Bucket: bucketDestination }).promise(); + }); + + it('should successfully replicate a version', done => { + let objMD; + let versionId; + + async.series({ + enableVersioningSource: next => srcS3.putBucketVersioning( + { Bucket: bucketSource, VersioningConfiguration: { Status: 'Enabled' } }, next), + putObject: next => srcS3.putObject( + { Bucket: bucketSource, Key: keyName, Body: new Buffer(testData) }, (err, data) => { + if (err) { + return next(err); + } + versionId = data.VersionId; + return next(); + }), + enableVersioningDestination: next => dstS3.putBucketVersioning( + { Bucket: bucketDestination, VersioningConfiguration: { Status: 'Enabled' } }, next), + getMetadata: next => makeBackbeatRequest({ + method: 'GET', + resourceType: 'metadata', + bucket: bucketSource, + objectKey: keyName, + queryObj: { + versionId, + }, + authCredentials: sourceAuthCredentials, + }, (err, data) => { + if (err) { + return next(err); + } + // Backbeat updates account info in metadata + // to the destination account info + objMD = objectMDFromRequestBody(data) + .setOwnerDisplayName(dstAccountInfo.name) + .setOwnerId(dstAccountInfo.canonicalID) + .getSerialized(); + return next(); + }), + replicateMetadata: next => makeBackbeatRequest({ + method: 'PUT', + resourceType: 'metadata', + bucket: bucketDestination, + objectKey: keyName, + queryObj: { + versionId, + }, + authCredentials: destinationAuthCredentials, + requestBody: objMD, + }, next), + headObject: next => dstS3.headObject( + { Bucket: bucketDestination, Key: keyName, VersionId: versionId }, next), + listObjectVersions: next => dstS3.listObjectVersions({ Bucket: bucketDestination }, next), + }, (err, results) => { + if (err) { + return done(err); + } + + const headObjectRes = results.headObject; + assert.strictEqual(headObjectRes.VersionId, versionId); + + const listObjectVersionsRes = results.listObjectVersions; + const { Versions } = listObjectVersionsRes; + assert.strictEqual(Versions.length, 1); + assert.strictEqual(Versions[0].IsLatest, true); + assert.strictEqual(Versions[0].VersionId, versionId); + + return done(); + }); + }); + + it('should successfully replicate a version and update it', done => { + let objMD; + let versionId; + + async.series({ + enableVersioningSource: next => srcS3.putBucketVersioning( + { Bucket: bucketSource, VersioningConfiguration: { Status: 'Enabled' } }, next), + putObject: next => srcS3.putObject( + { Bucket: bucketSource, Key: keyName, Body: new Buffer(testData) }, (err, data) => { + if (err) { + return next(err); + } + versionId = data.VersionId; + return next(); + }), + enableVersioningDestination: next => dstS3.putBucketVersioning( + { Bucket: bucketDestination, VersioningConfiguration: { Status: 'Enabled' } }, next), + getMetadata: next => makeBackbeatRequest({ + method: 'GET', + resourceType: 'metadata', + bucket: bucketSource, + objectKey: keyName, + queryObj: { + versionId, + }, + authCredentials: sourceAuthCredentials, + }, (err, data) => { + if (err) { + return next(err); + } + // Backbeat updates account info in metadata + // to the destination account info + objMD = objectMDFromRequestBody(data) + .setOwnerDisplayName(dstAccountInfo.name) + .setOwnerId(dstAccountInfo.canonicalID) + .getSerialized(); + return next(); + }), + replicateMetadata: next => makeBackbeatRequest({ + method: 'PUT', + resourceType: 'metadata', + bucket: bucketDestination, + objectKey: keyName, + queryObj: { + versionId, + }, + authCredentials: destinationAuthCredentials, + requestBody: objMD, + }, next), + updateMetadata: next => { + const { result, error } = ObjectMD.createFromBlob(objMD); + if (error) { + return next(error); + } + result.setTags({ foo: 'bar' }); + return makeBackbeatRequest({ + method: 'PUT', + resourceType: 'metadata', + bucket: bucketDestination, + objectKey: keyName, + queryObj: { + versionId, + }, + authCredentials: destinationAuthCredentials, + requestBody: result.getSerialized(), + }, next); + }, + getObjectTagging: next => dstS3.getObjectTagging( + { Bucket: bucketDestination, Key: keyName, VersionId: versionId }, next), + listObjectVersions: next => dstS3.listObjectVersions({ Bucket: bucketDestination }, next), + }, (err, results) => { + if (err) { + return done(err); + } + + const getObjectTaggingRes = results.getObjectTagging; + assert.strictEqual(getObjectTaggingRes.VersionId, versionId); + assert.deepStrictEqual(getObjectTaggingRes.TagSet, [{ Key: 'foo', Value: 'bar' }]); + + const listObjectVersionsRes = results.listObjectVersions; + const { Versions } = listObjectVersionsRes; + assert.strictEqual(Versions.length, 1); + assert.strictEqual(Versions[0].IsLatest, true); + assert.strictEqual(Versions[0].VersionId, versionId); + + return done(); + }); + }); + + it('should successfully replicate a version and update account info', done => { + let objMD; + let versionId; + + async.series({ + enableVersioningSource: next => srcS3.putBucketVersioning( + { Bucket: bucketSource, VersioningConfiguration: { Status: 'Enabled' } }, next), + putObject: next => srcS3.putObject( + { Bucket: bucketSource, Key: keyName, Body: new Buffer(testData) }, (err, data) => { + if (err) { + return next(err); + } + versionId = data.VersionId; + return next(); + }), + enableVersioningDestination: next => dstS3.putBucketVersioning( + { Bucket: bucketDestination, VersioningConfiguration: { Status: 'Enabled' } }, next), + getMetadata: next => makeBackbeatRequest({ + method: 'GET', + resourceType: 'metadata', + bucket: bucketSource, + objectKey: keyName, + queryObj: { + versionId, + }, + authCredentials: sourceAuthCredentials, + }, (err, data) => { + if (err) { + return next(err); + } + objMD = objectMDFromRequestBody(data) + .getSerialized(); + return next(); + }), + replicateMetadata: next => makeBackbeatRequest({ + method: 'PUT', + resourceType: 'metadata', + bucket: bucketDestination, + objectKey: keyName, + queryObj: { + versionId, + // Specifying the account id in the query string + // should make it update the account info in the + // metadata to the destination account info + accountId: dstAccountInfo.shortid, + }, + authCredentials: destinationAuthCredentials, + requestBody: objMD, + }, next), + getDestinationMetadata: next => makeBackbeatRequest({ + method: 'GET', + resourceType: 'metadata', + bucket: bucketDestination, + objectKey: keyName, + queryObj: { + versionId, + }, + authCredentials: destinationAuthCredentials, + }, (err, data) => { + if (err) { + return next(err); + } + return next(null, objectMDFromRequestBody(data)); + }), + }, (err, results) => { + if (err) { + return done(err); + } + + const dstObjMD = results.getDestinationMetadata; + assert.strictEqual(dstObjMD.getOwnerDisplayName(), dstAccountInfo.name); + assert.strictEqual(dstObjMD.getOwnerId(), dstAccountInfo.canonicalID); + + return done(); + }); + }); + + it('should fail to replicate a version if the provided account is invalid', done => { + let objMD; + let versionId; + + async.series({ + enableVersioningSource: next => srcS3.putBucketVersioning( + { Bucket: bucketSource, VersioningConfiguration: { Status: 'Enabled' } }, next), + putObject: next => srcS3.putObject( + { Bucket: bucketSource, Key: keyName, Body: new Buffer(testData) }, (err, data) => { + if (err) { + return next(err); + } + versionId = data.VersionId; + return next(); + }), + enableVersioningDestination: next => dstS3.putBucketVersioning( + { Bucket: bucketDestination, VersioningConfiguration: { Status: 'Enabled' } }, next), + getMetadata: next => makeBackbeatRequest({ + method: 'GET', + resourceType: 'metadata', + bucket: bucketSource, + objectKey: keyName, + queryObj: { + versionId, + }, + authCredentials: sourceAuthCredentials, + }, (err, data) => { + if (err) { + return next(err); + } + objMD = objectMDFromRequestBody(data) + .getSerialized(); + return next(); + }), + replicateMetadata: next => makeBackbeatRequest({ + method: 'PUT', + resourceType: 'metadata', + bucket: bucketDestination, + objectKey: keyName, + queryObj: { + versionId, + accountId: 'invalid', + }, + authCredentials: destinationAuthCredentials, + requestBody: objMD, + }, next), + }, err => { + assert.strictEqual(err.code, 'AccountNotFound'); + return done(); + }); + }); + + it('should successfully replicate multiple versions and keep original order', done => { + let objMDCurrent, objMDNonCurrent; + let versionIdCurrent, versionIdNonCurrent; + + async.series({ + enableVersioningSource: next => srcS3.putBucketVersioning( + { Bucket: bucketSource, VersioningConfiguration: { Status: 'Enabled' } }, next), + putObjectNonCurrent: next => srcS3.putObject( + { Bucket: bucketSource, Key: keyName, Body: new Buffer(testData) }, (err, data) => { + if (err) { + return next(err); + } + versionIdNonCurrent = data.VersionId; + return next(); + }), + putObjectCurrent: next => srcS3.putObject( + { Bucket: bucketSource, Key: keyName, Body: new Buffer(testData) }, (err, data) => { + if (err) { + return next(err); + } + versionIdCurrent = data.VersionId; + return next(); + }), + enableVersioningDestination: next => dstS3.putBucketVersioning( + { Bucket: bucketDestination, VersioningConfiguration: { Status: 'Enabled' } }, next), + getMetadataNonCurrent: next => makeBackbeatRequest({ + method: 'GET', + resourceType: 'metadata', + bucket: bucketSource, + objectKey: keyName, + queryObj: { + versionId: versionIdNonCurrent, + }, + authCredentials: sourceAuthCredentials, + }, (err, data) => { + if (err) { + return next(err); + } + // Backbeat updates account info in metadata + // to the destination account info + objMDNonCurrent = objectMDFromRequestBody(data) + .setOwnerDisplayName(dstAccountInfo.name) + .setOwnerId(dstAccountInfo.canonicalID) + .getSerialized(); + return next(); + }), + getMetadataCurrent: next => makeBackbeatRequest({ + method: 'GET', + resourceType: 'metadata', + bucket: bucketSource, + objectKey: keyName, + queryObj: { + versionId: versionIdCurrent, + }, + authCredentials: sourceAuthCredentials, + }, (err, data) => { + if (err) { + return next(err); + } + // Backbeat updates account info in metadata + // to the destination account info + objMDCurrent = objectMDFromRequestBody(data) + .setOwnerDisplayName(dstAccountInfo.name) + .setOwnerId(dstAccountInfo.canonicalID) + .getSerialized(); + return next(); + }), + // replicating the objects in the reverse order + replicateMetadataCurrent: next => makeBackbeatRequest({ + method: 'PUT', + resourceType: 'metadata', + bucket: bucketDestination, + objectKey: keyName, + queryObj: { + versionId: versionIdCurrent, + }, + authCredentials: destinationAuthCredentials, + requestBody: objMDCurrent, + }, next), + replicateMetadataNonCurrent: next => makeBackbeatRequest({ + method: 'PUT', + resourceType: 'metadata', + bucket: bucketDestination, + objectKey: keyName, + queryObj: { + versionId: versionIdNonCurrent, + }, + authCredentials: destinationAuthCredentials, + requestBody: objMDNonCurrent, + }, next), + listObjectVersions: next => dstS3.listObjectVersions({ Bucket: bucketDestination }, next), + }, (err, results) => { + if (err) { + return done(err); + } + + const listObjectVersionsRes = results.listObjectVersions; + const { Versions } = listObjectVersionsRes; + assert.strictEqual(Versions.length, 2); + + const [currentVersion, nonCurrentVersion] = Versions; + + assert.strictEqual(currentVersion.IsLatest, true); + assert.strictEqual(currentVersion.VersionId, versionIdCurrent); + + assert.strictEqual(nonCurrentVersion.IsLatest, false); + assert.strictEqual(nonCurrentVersion.VersionId, versionIdNonCurrent); + + return done(); + }); + }); + + it('should successfully replicate a delete marker', done => { + let objMDVersion, objMDDeleteMarker; + let versionIdVersion, versionIdDeleteMarker; + + async.series({ + enableVersioningSource: next => srcS3.putBucketVersioning( + { Bucket: bucketSource, VersioningConfiguration: { Status: 'Enabled' } }, next), + putObject: next => srcS3.putObject( + { Bucket: bucketSource, Key: keyName, Body: new Buffer(testData) }, (err, data) => { + if (err) { + return next(err); + } + versionIdVersion = data.VersionId; + return next(); + }), + deleteObject: next => srcS3.deleteObject( + { Bucket: bucketSource, Key: keyName }, (err, data) => { + if (err) { + return next(err); + } + versionIdDeleteMarker = data.VersionId; + return next(); + }), + enableVersioningDestination: next => dstS3.putBucketVersioning( + { Bucket: bucketDestination, VersioningConfiguration: { Status: 'Enabled' } }, next), + getMetadataVersion: next => makeBackbeatRequest({ + method: 'GET', + resourceType: 'metadata', + bucket: bucketSource, + objectKey: keyName, + queryObj: { + versionId: versionIdVersion, + }, + authCredentials: sourceAuthCredentials, + }, (err, data) => { + if (err) { + return next(err); + } + // Backbeat updates account info in metadata + // to the destination account info + objMDVersion = objectMDFromRequestBody(data) + .setOwnerDisplayName(dstAccountInfo.name) + .setOwnerId(dstAccountInfo.canonicalID) + .getSerialized(); + return next(); + }), + replicateMetadataVersion: next => makeBackbeatRequest({ + method: 'PUT', + resourceType: 'metadata', + bucket: bucketDestination, + objectKey: keyName, + queryObj: { + versionId: versionIdVersion, + }, + authCredentials: destinationAuthCredentials, + requestBody: objMDVersion, + }, next), + getMetadataDeleteMarker: next => makeBackbeatRequest({ + method: 'GET', + resourceType: 'metadata', + bucket: bucketSource, + objectKey: keyName, + queryObj: { + versionId: versionIdDeleteMarker, + }, + authCredentials: sourceAuthCredentials, + }, (err, data) => { + if (err) { + return next(err); + } + // Backbeat updates account info in metadata + // to the destination account info + objMDDeleteMarker = objectMDFromRequestBody(data) + .setOwnerDisplayName(dstAccountInfo.name) + .setOwnerId(dstAccountInfo.canonicalID) + .getSerialized(); + return next(); + }), + replicateMetadataDeleteMarker: next => makeBackbeatRequest({ + method: 'PUT', + resourceType: 'metadata', + bucket: bucketDestination, + objectKey: keyName, + queryObj: { + versionId: versionIdDeleteMarker, + }, + authCredentials: destinationAuthCredentials, + requestBody: objMDDeleteMarker, + }, next), + listObjectVersions: next => dstS3.listObjectVersions({ Bucket: bucketDestination }, next), + }, (err, results) => { + if (err) { + return done(err); + } + + const listObjectVersionsRes = results.listObjectVersions; + const { Versions, DeleteMarkers } = listObjectVersionsRes; + + assert.strictEqual(Versions.length, 1); + assert.strictEqual(DeleteMarkers.length, 1); + + assert.strictEqual(Versions[0].IsLatest, false); + assert.strictEqual(Versions[0].VersionId, versionIdVersion); + + assert.strictEqual(DeleteMarkers[0].IsLatest, true); + assert.strictEqual(DeleteMarkers[0].VersionId, versionIdDeleteMarker); + + return done(); + }); + }); it('should successfully replicate a null version', done => { let objMD; async.series({ - putObject: next => s3.putObject({ Bucket: bucketSource, Key: keyName, Body: new Buffer(testData) }, next), - enableVersioningSource: next => s3.putBucketVersioning( + putObject: next => srcS3.putObject( + { Bucket: bucketSource, Key: keyName, Body: new Buffer(testData) }, next), + enableVersioningSource: next => srcS3.putBucketVersioning( { Bucket: bucketSource, VersioningConfiguration: { Status: 'Enabled' } }, next), - enableVersioningDestination: next => s3.putBucketVersioning( + enableVersioningDestination: next => dstS3.putBucketVersioning( { Bucket: bucketDestination, VersioningConfiguration: { Status: 'Enabled' } }, next), getMetadata: next => makeBackbeatRequest({ method: 'GET', @@ -62,12 +592,17 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId: 'null', }, - authCredentials: backbeatAuthCredentials, + authCredentials: sourceAuthCredentials, }, (err, data) => { if (err) { return next(err); } - objMD = JSON.parse(data.body).Body; + // Backbeat updates account info in metadata + // to the destination account info + objMD = objectMDFromRequestBody(data) + .setOwnerDisplayName(dstAccountInfo.name) + .setOwnerId(dstAccountInfo.canonicalID) + .getSerialized(); return next(); }), replicateMetadata: next => makeBackbeatRequest({ @@ -78,11 +613,11 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId: 'null', }, - authCredentials: backbeatAuthCredentials, + authCredentials: destinationAuthCredentials, requestBody: objMD, }, next), - headObject: next => s3.headObject({ Bucket: bucketDestination, Key: keyName, VersionId: 'null' }, next), - listObjectVersions: next => s3.listObjectVersions({ Bucket: bucketDestination }, next), + headObject: next => dstS3.headObject({ Bucket: bucketDestination, Key: keyName, VersionId: 'null' }, next), + listObjectVersions: next => dstS3.listObjectVersions({ Bucket: bucketDestination }, next), }, (err, results) => { if (err) { return done(err); @@ -108,12 +643,13 @@ describe.skip('backbeat routes for replication', () => { let objMD; async.series({ - suspendVersioningSource: next => s3.putBucketVersioning( + suspendVersioningSource: next => srcS3.putBucketVersioning( { Bucket: bucketSource, VersioningConfiguration: { Status: 'Suspended' } }, next), - putObject: next => s3.putObject({ Bucket: bucketSource, Key: keyName, Body: new Buffer(testData) }, next), - enableVersioningSource: next => s3.putBucketVersioning( + putObject: next => srcS3.putObject( + { Bucket: bucketSource, Key: keyName, Body: new Buffer(testData) }, next), + enableVersioningSource: next => srcS3.putBucketVersioning( { Bucket: bucketSource, VersioningConfiguration: { Status: 'Enabled' } }, next), - enableVersioningDestination: next => s3.putBucketVersioning( + enableVersioningDestination: next => dstS3.putBucketVersioning( { Bucket: bucketDestination, VersioningConfiguration: { Status: 'Enabled' } }, next), getMetadata: next => makeBackbeatRequest({ method: 'GET', @@ -123,12 +659,17 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId: 'null', }, - authCredentials: backbeatAuthCredentials, + authCredentials: sourceAuthCredentials, }, (err, data) => { if (err) { return next(err); } - objMD = JSON.parse(data.body).Body; + // Backbeat updates account info in metadata + // to the destination account info + objMD = objectMDFromRequestBody(data) + .setOwnerDisplayName(dstAccountInfo.name) + .setOwnerId(dstAccountInfo.canonicalID) + .getSerialized(); return next(); }), replicateMetadata: next => makeBackbeatRequest({ @@ -139,11 +680,11 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId: 'null', }, - authCredentials: backbeatAuthCredentials, + authCredentials: destinationAuthCredentials, requestBody: objMD, }, next), - headObject: next => s3.headObject({ Bucket: bucketDestination, Key: keyName, VersionId: 'null' }, next), - listObjectVersions: next => s3.listObjectVersions({ Bucket: bucketDestination }, next), + headObject: next => dstS3.headObject({ Bucket: bucketDestination, Key: keyName, VersionId: 'null' }, next), + listObjectVersions: next => dstS3.listObjectVersions({ Bucket: bucketDestination }, next), }, (err, results) => { if (err) { return done(err); @@ -169,10 +710,11 @@ describe.skip('backbeat routes for replication', () => { let objMD; async.series({ - putObject: next => s3.putObject({ Bucket: bucketSource, Key: keyName, Body: Buffer.from(testData) }, next), - enableVersioningSource: next => s3.putBucketVersioning( + putObject: next => srcS3.putObject( + { Bucket: bucketSource, Key: keyName, Body: Buffer.from(testData) }, next), + enableVersioningSource: next => srcS3.putBucketVersioning( { Bucket: bucketSource, VersioningConfiguration: { Status: 'Enabled' } }, next), - enableVersioningDestination: next => s3.putBucketVersioning( + enableVersioningDestination: next => dstS3.putBucketVersioning( { Bucket: bucketDestination, VersioningConfiguration: { Status: 'Enabled' } }, next), getMetadata: next => makeBackbeatRequest({ method: 'GET', @@ -182,12 +724,17 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId: 'null', }, - authCredentials: backbeatAuthCredentials, + authCredentials: sourceAuthCredentials, }, (err, data) => { if (err) { return next(err); } - objMD = JSON.parse(data.body).Body; + // Backbeat updates account info in metadata + // to the destination account info + objMD = objectMDFromRequestBody(data) + .setOwnerDisplayName(dstAccountInfo.name) + .setOwnerId(dstAccountInfo.canonicalID) + .getSerialized(); return next(); }), replicateMetadata: next => makeBackbeatRequest({ @@ -198,7 +745,7 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId: 'null', }, - authCredentials: backbeatAuthCredentials, + authCredentials: destinationAuthCredentials, requestBody: objMD, }, next), updateMetadata: next => { @@ -215,12 +762,12 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId: 'null', }, - authCredentials: backbeatAuthCredentials, + authCredentials: destinationAuthCredentials, requestBody: result.getSerialized(), }, next); }, - headObject: next => s3.headObject({ Bucket: bucketDestination, Key: keyName, VersionId: 'null' }, next), - listObjectVersions: next => s3.listObjectVersions({ Bucket: bucketDestination }, next), + headObject: next => dstS3.headObject({ Bucket: bucketDestination, Key: keyName, VersionId: 'null' }, next), + listObjectVersions: next => dstS3.listObjectVersions({ Bucket: bucketDestination }, next), }, (err, results) => { if (err) { return done(err); @@ -249,11 +796,11 @@ describe.skip('backbeat routes for replication', () => { let expectedVersionId; async.series({ - putObjectSource: next => s3.putObject( + putObjectSource: next => srcS3.putObject( { Bucket: bucketSource, Key: keyName, Body: Buffer.from(testData) }, next), - enableVersioningSource: next => s3.putBucketVersioning( + enableVersioningSource: next => srcS3.putBucketVersioning( { Bucket: bucketSource, VersioningConfiguration: { Status: 'Enabled' } }, next), - enableVersioningDestination: next => s3.putBucketVersioning( + enableVersioningDestination: next => dstS3.putBucketVersioning( { Bucket: bucketDestination, VersioningConfiguration: { Status: 'Enabled' } }, next), getMetadata: next => makeBackbeatRequest({ method: 'GET', @@ -263,12 +810,17 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId: 'null', }, - authCredentials: backbeatAuthCredentials, + authCredentials: sourceAuthCredentials, }, (err, data) => { if (err) { return next(err); } - objMD = JSON.parse(data.body).Body; + // Backbeat updates account info in metadata + // to the destination account info + objMD = objectMDFromRequestBody(data) + .setOwnerDisplayName(dstAccountInfo.name) + .setOwnerId(dstAccountInfo.canonicalID) + .getSerialized(); return next(); }), replicateMetadata: next => makeBackbeatRequest({ @@ -279,10 +831,10 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId: 'null', }, - authCredentials: backbeatAuthCredentials, + authCredentials: destinationAuthCredentials, requestBody: objMD, }, next), - putObjectDestination: next => s3.putObject( + putObjectDestination: next => dstS3.putObject( { Bucket: bucketDestination, Key: keyName, Body: Buffer.from(testData) }, (err, data) => { if (err) { return next(err); @@ -290,8 +842,8 @@ describe.skip('backbeat routes for replication', () => { expectedVersionId = data.VersionId; return next(); }), - headObject: next => s3.headObject({ Bucket: bucketDestination, Key: keyName, VersionId: 'null' }, next), - listObjectVersions: next => s3.listObjectVersions({ Bucket: bucketDestination }, next), + headObject: next => dstS3.headObject({ Bucket: bucketDestination, Key: keyName, VersionId: 'null' }, next), + listObjectVersions: next => dstS3.listObjectVersions({ Bucket: bucketDestination }, next), }, (err, results) => { if (err) { return done(err); @@ -319,9 +871,9 @@ describe.skip('backbeat routes for replication', () => { let secondVersionId; async.series({ - enableVersioningDestination: next => s3.putBucketVersioning( + enableVersioningDestination: next => dstS3.putBucketVersioning( { Bucket: bucketDestination, VersioningConfiguration: { Status: 'Enabled' } }, next), - putObjectDestination: next => s3.putObject( + putObjectDestination: next => dstS3.putObject( { Bucket: bucketDestination, Key: keyName, Body: Buffer.from(testData) }, (err, data) => { if (err) { return next(err); @@ -329,9 +881,9 @@ describe.skip('backbeat routes for replication', () => { firstVersionId = data.VersionId; return next(); }), - enableVersioningSource: next => s3.putBucketVersioning( + enableVersioningSource: next => srcS3.putBucketVersioning( { Bucket: bucketSource, VersioningConfiguration: { Status: 'Enabled' } }, next), - putObjectSource: next => s3.putObject( + putObjectSource: next => srcS3.putObject( { Bucket: bucketSource, Key: keyName, Body: Buffer.from(testData) }, (err, data) => { if (err) { return next(err); @@ -347,12 +899,17 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId: secondVersionId, }, - authCredentials: backbeatAuthCredentials, + authCredentials: sourceAuthCredentials, }, (err, data) => { if (err) { return next(err); } - objMD = JSON.parse(data.body).Body; + // Backbeat updates account info in metadata + // to the destination account info + objMD = objectMDFromRequestBody(data) + .setOwnerDisplayName(dstAccountInfo.name) + .setOwnerId(dstAccountInfo.canonicalID) + .getSerialized(); return next(); }), replicateMetadata: next => makeBackbeatRequest({ @@ -363,14 +920,14 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId: secondVersionId, }, - authCredentials: backbeatAuthCredentials, + authCredentials: destinationAuthCredentials, requestBody: objMD, }, next), - headObjectFirstVersion: next => s3.headObject( + headObjectFirstVersion: next => dstS3.headObject( { Bucket: bucketDestination, Key: keyName, VersionId: firstVersionId }, next), - headObjectSecondVersion: next => s3.headObject( + headObjectSecondVersion: next => dstS3.headObject( { Bucket: bucketDestination, Key: keyName, VersionId: secondVersionId }, next), - listObjectVersions: next => s3.listObjectVersions({ Bucket: bucketDestination }, next), + listObjectVersions: next => dstS3.listObjectVersions({ Bucket: bucketDestination }, next), }, (err, results) => { if (err) { return done(err); @@ -398,18 +955,18 @@ describe.skip('backbeat routes for replication', () => { }); }); - it('should replicate/put metadata to a destination that has a null version', done => { + it.skip('should replicate/put metadata to a destination that has a null version', done => { let objMD; let versionId; async.series({ - putObjectDestinationInitial: next => s3.putObject( + putObjectDestinationInitial: next => dstS3.putObject( { Bucket: bucketDestination, Key: keyName, Body: Buffer.from(testData) }, next), - enableVersioningDestination: next => s3.putBucketVersioning( + enableVersioningDestination: next => dstS3.putBucketVersioning( { Bucket: bucketDestination, VersioningConfiguration: { Status: 'Enabled' } }, next), - enableVersioningSource: next => s3.putBucketVersioning( + enableVersioningSource: next => srcS3.putBucketVersioning( { Bucket: bucketSource, VersioningConfiguration: { Status: 'Enabled' } }, next), - putObjectSource: next => s3.putObject( + putObjectSource: next => srcS3.putObject( { Bucket: bucketSource, Key: keyName, Body: Buffer.from(testData) }, (err, data) => { if (err) { return next(err); @@ -425,12 +982,17 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId, }, - authCredentials: backbeatAuthCredentials, + authCredentials: sourceAuthCredentials, }, (err, data) => { if (err) { return next(err); } - objMD = JSON.parse(data.body).Body; + // Backbeat updates account info in metadata + // to the destination account info + objMD = objectMDFromRequestBody(data) + .setOwnerDisplayName(dstAccountInfo.name) + .setOwnerId(dstAccountInfo.canonicalID) + .getSerialized(); return next(); }), replicateMetadata: next => makeBackbeatRequest({ @@ -441,12 +1003,12 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId, }, - authCredentials: backbeatAuthCredentials, + authCredentials: destinationAuthCredentials, requestBody: objMD, }, next), - headObjectNullVersion: next => s3.headObject( + headObjectNullVersion: next => dstS3.headObject( { Bucket: bucketDestination, Key: keyName, VersionId: 'null' }, next), - listObjectVersions: next => s3.listObjectVersions( + listObjectVersions: next => dstS3.listObjectVersions( { Bucket: bucketDestination }, next), }, (err, results) => { if (err) { @@ -472,20 +1034,20 @@ describe.skip('backbeat routes for replication', () => { }); }); - it('should replicate/put metadata to a destination that has a suspended null version', done => { + it.skip('should replicate/put metadata to a destination that has a suspended null version', done => { let objMD; let versionId; async.series({ - suspendVersioningDestination: next => s3.putBucketVersioning( + suspendVersioningDestination: next => dstS3.putBucketVersioning( { Bucket: bucketDestination, VersioningConfiguration: { Status: 'Suspended' } }, next), - putObjectDestinationInitial: next => s3.putObject( + putObjectDestinationInitial: next => dstS3.putObject( { Bucket: bucketDestination, Key: keyName, Body: Buffer.from(testData) }, next), - enableVersioningDestination: next => s3.putBucketVersioning( + enableVersioningDestination: next => dstS3.putBucketVersioning( { Bucket: bucketDestination, VersioningConfiguration: { Status: 'Enabled' } }, next), - enableVersioningSource: next => s3.putBucketVersioning( + enableVersioningSource: next => srcS3.putBucketVersioning( { Bucket: bucketSource, VersioningConfiguration: { Status: 'Enabled' } }, next), - putObjectSource: next => s3.putObject( + putObjectSource: next => srcS3.putObject( { Bucket: bucketSource, Key: keyName, Body: Buffer.from(testData) }, (err, data) => { if (err) { return next(err); @@ -501,12 +1063,17 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId, }, - authCredentials: backbeatAuthCredentials, + authCredentials: sourceAuthCredentials, }, (err, data) => { if (err) { return next(err); } - objMD = JSON.parse(data.body).Body; + // Backbeat updates account info in metadata + // to the destination account info + objMD = objectMDFromRequestBody(data) + .setOwnerDisplayName(dstAccountInfo.name) + .setOwnerId(dstAccountInfo.canonicalID) + .getSerialized(); return next(); }), replicateMetadata: next => makeBackbeatRequest({ @@ -517,12 +1084,12 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId, }, - authCredentials: backbeatAuthCredentials, + authCredentials: destinationAuthCredentials, requestBody: objMD, }, next), - headObjectNullVersion: next => s3.headObject( + headObjectNullVersion: next => dstS3.headObject( { Bucket: bucketDestination, Key: keyName, VersionId: 'null' }, next), - listObjectVersions: next => s3.listObjectVersions({ Bucket: bucketDestination }, next), + listObjectVersions: next => dstS3.listObjectVersions({ Bucket: bucketDestination }, next), }, (err, results) => { if (err) { return done(err); @@ -547,15 +1114,15 @@ describe.skip('backbeat routes for replication', () => { }); }); - it('should replicate/put metadata to a destination that has a previously updated null version', done => { + it.skip('should replicate/put metadata to a destination that has a previously updated null version', done => { let objMD; let objMDNull; let versionId; async.series({ - putObjectDestinationInitial: next => s3.putObject( + putObjectDestinationInitial: next => dstS3.putObject( { Bucket: bucketDestination, Key: keyName, Body: Buffer.from(testData) }, next), - enableVersioningDestination: next => s3.putBucketVersioning( + enableVersioningDestination: next => dstS3.putBucketVersioning( { Bucket: bucketDestination, VersioningConfiguration: { Status: 'Enabled' } }, next), getMetadataNullVersion: next => makeBackbeatRequest({ method: 'GET', @@ -565,7 +1132,7 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId: 'null', }, - authCredentials: backbeatAuthCredentials, + authCredentials: destinationAuthCredentials, }, (err, data) => { if (err) { return next(err); @@ -581,12 +1148,12 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId: 'null', }, - authCredentials: backbeatAuthCredentials, + authCredentials: destinationAuthCredentials, requestBody: objMDNull, }, next), - enableVersioningSource: next => s3.putBucketVersioning( + enableVersioningSource: next => srcS3.putBucketVersioning( { Bucket: bucketSource, VersioningConfiguration: { Status: 'Enabled' } }, next), - putObjectSource: next => s3.putObject( + putObjectSource: next => srcS3.putObject( { Bucket: bucketSource, Key: keyName, Body: Buffer.from(testData) }, (err, data) => { if (err) { return next(err); @@ -602,12 +1169,17 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId, }, - authCredentials: backbeatAuthCredentials, + authCredentials: sourceAuthCredentials, }, (err, data) => { if (err) { return next(err); } - objMD = JSON.parse(data.body).Body; + // Backbeat updates account info in metadata + // to the destination account info + objMD = objectMDFromRequestBody(data) + .setOwnerDisplayName(dstAccountInfo.name) + .setOwnerId(dstAccountInfo.canonicalID) + .getSerialized(); return next(); }), replicateMetadata: next => makeBackbeatRequest({ @@ -618,12 +1190,12 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId, }, - authCredentials: backbeatAuthCredentials, + authCredentials: destinationAuthCredentials, requestBody: objMD, }, next), - headObjectNullVersion: next => s3.headObject( + headObjectNullVersion: next => dstS3.headObject( { Bucket: bucketDestination, Key: keyName, VersionId: 'null' }, next), - listObjectVersions: next => s3.listObjectVersions({ Bucket: bucketDestination }, next), + listObjectVersions: next => dstS3.listObjectVersions({ Bucket: bucketDestination }, next), }, (err, results) => { if (err) { return done(err); @@ -648,7 +1220,7 @@ describe.skip('backbeat routes for replication', () => { }); }); - it('should replicate/put metadata to a destination that has a suspended null version with internal version', + it.skip('should replicate/put metadata to a destination that has a suspended null version with internal version', done => { const tagSet = [ { @@ -660,17 +1232,17 @@ describe.skip('backbeat routes for replication', () => { let versionId; async.series({ - suspendVersioningDestination: next => s3.putBucketVersioning( + suspendVersioningDestination: next => dstS3.putBucketVersioning( { Bucket: bucketDestination, VersioningConfiguration: { Status: 'Suspended' } }, next), - putObjectDestinationInitial: next => s3.putObject( + putObjectDestinationInitial: next => dstS3.putObject( { Bucket: bucketDestination, Key: keyName, Body: Buffer.from(testData) }, next), - putObjectTagging: next => s3.putObjectTagging( + putObjectTagging: next => dstS3.putObjectTagging( { Bucket: bucketDestination, Key: keyName, Tagging: { TagSet: tagSet } }, next), - enableVersioningDestination: next => s3.putBucketVersioning( + enableVersioningDestination: next => dstS3.putBucketVersioning( { Bucket: bucketDestination, VersioningConfiguration: { Status: 'Enabled' } }, next), - enableVersioningSource: next => s3.putBucketVersioning( + enableVersioningSource: next => srcS3.putBucketVersioning( { Bucket: bucketSource, VersioningConfiguration: { Status: 'Enabled' } }, next), - putObjectSource: next => s3.putObject( + putObjectSource: next => srcS3.putObject( { Bucket: bucketSource, Key: keyName, Body: Buffer.from(testData) }, (err, data) => { if (err) { return next(err); @@ -686,12 +1258,17 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId, }, - authCredentials: backbeatAuthCredentials, + authCredentials: sourceAuthCredentials, }, (err, data) => { if (err) { return next(err); } - objMD = JSON.parse(data.body).Body; + // Backbeat updates account info in metadata + // to the destination account info + objMD = objectMDFromRequestBody(data) + .setOwnerDisplayName(dstAccountInfo.name) + .setOwnerId(dstAccountInfo.canonicalID) + .getSerialized(); return next(); }), replicateMetadata: next => makeBackbeatRequest({ @@ -702,14 +1279,14 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId, }, - authCredentials: backbeatAuthCredentials, + authCredentials: destinationAuthCredentials, requestBody: objMD, }, next), - headObjectNullVersion: next => s3.headObject( + headObjectNullVersion: next => dstS3.headObject( { Bucket: bucketDestination, Key: keyName, VersionId: 'null' }, next), - getObjectTaggingNullVersion: next => s3.getObjectTagging( + getObjectTaggingNullVersion: next => dstS3.getObjectTagging( { Bucket: bucketDestination, Key: keyName, VersionId: 'null' }, next), - listObjectVersions: next => s3.listObjectVersions({ Bucket: bucketDestination }, next), + listObjectVersions: next => dstS3.listObjectVersions({ Bucket: bucketDestination }, next), }, (err, results) => { if (err) { return done(err); @@ -737,16 +1314,16 @@ describe.skip('backbeat routes for replication', () => { }); }); - it('should mimic null version replication by crrExistingObjects, then replicate version', done => { + it.skip('should mimic null version replication by crrExistingObjects, then replicate version', done => { let objMDNull; let objMDNullReplicated; let objMDVersion; let versionId; async.series({ - createNullSoloMasterKey: next => s3.putObject( + createNullSoloMasterKey: next => srcS3.putObject( { Bucket: bucketSource, Key: keyName, Body: Buffer.from(testData) }, next), - enableVersioningSource: next => s3.putBucketVersioning( + enableVersioningSource: next => srcS3.putBucketVersioning( { Bucket: bucketSource, VersioningConfiguration: { Status: 'Enabled' } }, next), simulateCrrExistingObjectsGetMetadata: next => makeBackbeatRequest({ method: 'GET', @@ -756,7 +1333,7 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId: 'null', }, - authCredentials: backbeatAuthCredentials, + authCredentials: sourceAuthCredentials, }, (err, data) => { if (err) { return next(err); @@ -773,10 +1350,10 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId: 'null', }, - authCredentials: backbeatAuthCredentials, + authCredentials: sourceAuthCredentials, requestBody: objMDNull, }, next), - enableVersioningDestination: next => s3.putBucketVersioning( + enableVersioningDestination: next => dstS3.putBucketVersioning( { Bucket: bucketDestination, VersioningConfiguration: { Status: 'Enabled' } }, next), replicateNullVersion: next => makeBackbeatRequest({ method: 'GET', @@ -786,12 +1363,17 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId: 'null', }, - authCredentials: backbeatAuthCredentials, + authCredentials: sourceAuthCredentials, }, (err, data) => { if (err) { return next(err); } - objMDNullReplicated = JSON.parse(data.body).Body; + // Backbeat updates account info in metadata + // to the destination account info + objMDNullReplicated = objectMDFromRequestBody(data) + .setOwnerDisplayName(dstAccountInfo.name) + .setOwnerId(dstAccountInfo.canonicalID) + .getSerialized(); return next(); }), putReplicatedNullVersion: next => makeBackbeatRequest({ @@ -802,10 +1384,10 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId: 'null', }, - authCredentials: backbeatAuthCredentials, + authCredentials: destinationAuthCredentials, requestBody: objMDNullReplicated, }, next), - putNewVersionSource: next => s3.putObject( + putNewVersionSource: next => srcS3.putObject( { Bucket: bucketSource, Key: keyName, Body: Buffer.from(testData) }, (err, data) => { if (err) { return next(err); @@ -821,15 +1403,20 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId, }, - authCredentials: backbeatAuthCredentials, + authCredentials: sourceAuthCredentials, }, (err, data) => { if (err) { return next(err); } - objMDVersion = JSON.parse(data.body).Body; + // Backbeat updates account info in metadata + // to the destination account info + objMDVersion = objectMDFromRequestBody(data) + .setOwnerDisplayName(dstAccountInfo.name) + .setOwnerId(dstAccountInfo.canonicalID) + .getSerialized(); return next(); }), - listObjectVersionsBeforeReplicate: next => s3.listObjectVersions({ Bucket: bucketDestination }, next), + listObjectVersionsBeforeReplicate: next => dstS3.listObjectVersions({ Bucket: bucketDestination }, next), putReplicatedVersion: next => makeBackbeatRequest({ method: 'PUT', resourceType: 'metadata', @@ -838,14 +1425,14 @@ describe.skip('backbeat routes for replication', () => { queryObj: { versionId, }, - authCredentials: backbeatAuthCredentials, + authCredentials: destinationAuthCredentials, requestBody: objMDVersion, }, next), - checkReplicatedNullVersion: next => s3.headObject( + checkReplicatedNullVersion: next => dstS3.headObject( { Bucket: bucketDestination, Key: keyName, VersionId: 'null' }, next), - checkReplicatedVersion: next => s3.headObject( + checkReplicatedVersion: next => dstS3.headObject( { Bucket: bucketDestination, Key: keyName, VersionId: versionId }, next), - listObjectVersionsAfterReplicate: next => s3.listObjectVersions({ Bucket: bucketDestination }, next), + listObjectVersionsAfterReplicate: next => dstS3.listObjectVersions({ Bucket: bucketDestination }, next), }, (err, results) => { if (err) { return done(err); @@ -879,11 +1466,11 @@ describe.skip('backbeat routes for replication', () => { let versionId; async.series({ - enableVersioningDestination: next => s3.putBucketVersioning({ + enableVersioningDestination: next => dstS3.putBucketVersioning({ Bucket: bucketDestination, VersioningConfiguration: { Status: 'Enabled' }, }, next), - putObjectDestination: next => s3.putObject({ + putObjectDestination: next => dstS3.putObject({ Bucket: bucketDestination, Key: keyName, Body: Buffer.from(testData), @@ -894,12 +1481,12 @@ describe.skip('backbeat routes for replication', () => { versionId = data.VersionId; return next(); }), - putObjectSource: next => s3.putObject({ + putObjectSource: next => srcS3.putObject({ Bucket: bucketSource, Key: keyName, Body: Buffer.from(testData), }, next), - enableVersioningSource: next => s3.putBucketVersioning({ + enableVersioningSource: next => srcS3.putBucketVersioning({ Bucket: bucketSource, VersioningConfiguration: { Status: 'Enabled' }, }, next), @@ -909,12 +1496,17 @@ describe.skip('backbeat routes for replication', () => { bucket: bucketSource, objectKey: keyName, queryObj: { versionId: 'null' }, - authCredentials: backbeatAuthCredentials, + authCredentials: sourceAuthCredentials, }, (err, data) => { if (err) { return next(err); } - objMD = JSON.parse(data.body).Body; + // Backbeat updates account info in metadata + // to the destination account info + objMD = objectMDFromRequestBody(data) + .setOwnerDisplayName(dstAccountInfo.name) + .setOwnerId(dstAccountInfo.canonicalID) + .getSerialized(); return next(); }), replicateMetadata: next => makeBackbeatRequest({ @@ -923,20 +1515,20 @@ describe.skip('backbeat routes for replication', () => { bucket: bucketDestination, objectKey: keyName, queryObj: { versionId: 'null' }, - authCredentials: backbeatAuthCredentials, + authCredentials: destinationAuthCredentials, requestBody: objMD, }, next), - headObjectByVersionId: next => s3.headObject({ + headObjectByVersionId: next => dstS3.headObject({ Bucket: bucketDestination, Key: keyName, VersionId: versionId, }, next), - headObjectByNullVersionId: next => s3.headObject({ + headObjectByNullVersionId: next => dstS3.headObject({ Bucket: bucketDestination, Key: keyName, VersionId: 'null', }, next), - listObjectVersions: next => s3.listObjectVersions({ + listObjectVersions: next => dstS3.listObjectVersions({ Bucket: bucketDestination, }, next), }, (err, results) => { @@ -970,25 +1562,25 @@ describe.skip('backbeat routes for replication', () => { let objMD; async.series({ - putObjectDestinationInitial: next => s3.putObject({ + putObjectDestinationInitial: next => dstS3.putObject({ Bucket: bucketDestination, Key: keyName, Body: Buffer.from(testData), }, next), - enableVersioningDestination: next => s3.putBucketVersioning({ + enableVersioningDestination: next => dstS3.putBucketVersioning({ Bucket: bucketDestination, VersioningConfiguration: { Status: 'Enabled' }, }, next), - putObjectSource: next => s3.putObject({ + putObjectSource: next => srcS3.putObject({ Bucket: bucketSource, Key: keyName, Body: Buffer.from(testData), }, next), - enableVersioningSource: next => s3.putBucketVersioning({ + enableVersioningSource: next => srcS3.putBucketVersioning({ Bucket: bucketSource, VersioningConfiguration: { Status: 'Enabled' }, }, next), - putObjectTaggingSource: next => s3.putObjectTagging({ + putObjectTaggingSource: next => srcS3.putObjectTagging({ Bucket: bucketSource, Key: keyName, VersionId: 'null', @@ -1000,12 +1592,17 @@ describe.skip('backbeat routes for replication', () => { bucket: bucketSource, objectKey: keyName, queryObj: { versionId: 'null' }, - authCredentials: backbeatAuthCredentials, + authCredentials: sourceAuthCredentials, }, (err, data) => { if (err) { return next(err); } - objMD = JSON.parse(data.body).Body; + // Backbeat updates account info in metadata + // to the destination account info + objMD = objectMDFromRequestBody(data) + .setOwnerDisplayName(dstAccountInfo.name) + .setOwnerId(dstAccountInfo.canonicalID) + .getSerialized(); return next(); }), replicateMetadata: next => makeBackbeatRequest({ @@ -1014,20 +1611,20 @@ describe.skip('backbeat routes for replication', () => { bucket: bucketDestination, objectKey: keyName, queryObj: { versionId: 'null' }, - authCredentials: backbeatAuthCredentials, + authCredentials: destinationAuthCredentials, requestBody: objMD, }, next), - headObjectNullVersion: next => s3.headObject({ + headObjectNullVersion: next => dstS3.headObject({ Bucket: bucketDestination, Key: keyName, VersionId: 'null', }, next), - getObjectTaggingNullVersion: next => s3.getObjectTagging({ + getObjectTaggingNullVersion: next => dstS3.getObjectTagging({ Bucket: bucketDestination, Key: keyName, VersionId: 'null', }, next), - listObjectVersions: next => s3.listObjectVersions({ + listObjectVersions: next => dstS3.listObjectVersions({ Bucket: bucketDestination, }, next), }, (err, results) => { @@ -1060,11 +1657,11 @@ describe.skip('backbeat routes for replication', () => { let versionId; async.series({ - enableVersioningDestination: next => s3.putBucketVersioning({ + enableVersioningDestination: next => dstS3.putBucketVersioning({ Bucket: bucketDestination, VersioningConfiguration: { Status: 'Enabled' }, }, next), - putObjectDestination: next => s3.putObject({ + putObjectDestination: next => dstS3.putObject({ Bucket: bucketDestination, Key: keyName, Body: Buffer.from(testData), @@ -1075,12 +1672,12 @@ describe.skip('backbeat routes for replication', () => { versionId = data.VersionId; return next(); }), - putObjectSource: next => s3.putObject({ + putObjectSource: next => srcS3.putObject({ Bucket: bucketSource, Key: keyName, Body: Buffer.from(testData), }, next), - enableVersioningSource: next => s3.putBucketVersioning({ + enableVersioningSource: next => srcS3.putBucketVersioning({ Bucket: bucketSource, VersioningConfiguration: { Status: 'Enabled' }, }, next), @@ -1090,7 +1687,7 @@ describe.skip('backbeat routes for replication', () => { bucket: bucketSource, objectKey: keyName, queryObj: { versionId: 'null' }, - authCredentials: backbeatAuthCredentials, + authCredentials: sourceAuthCredentials, }, (err, data) => { if (err) { return next(err); @@ -1104,7 +1701,7 @@ describe.skip('backbeat routes for replication', () => { bucket: bucketSource, objectKey: keyName, queryObj: { versionId: 'null' }, - authCredentials: backbeatAuthCredentials, + authCredentials: sourceAuthCredentials, requestBody: objMDUpdated, }, next), getReplicatedNullVersion: next => makeBackbeatRequest({ @@ -1113,12 +1710,17 @@ describe.skip('backbeat routes for replication', () => { bucket: bucketSource, objectKey: keyName, queryObj: { versionId: 'null' }, - authCredentials: backbeatAuthCredentials, + authCredentials: destinationAuthCredentials, }, (err, data) => { if (err) { return next(err); } - objMDReplicated = JSON.parse(data.body).Body; + // Backbeat updates account info in metadata + // to the destination account info + objMDReplicated = objectMDFromRequestBody(data) + .setOwnerDisplayName(dstAccountInfo.name) + .setOwnerId(dstAccountInfo.canonicalID) + .getSerialized(); return next(); }), putReplicatedNullVersion: next => makeBackbeatRequest({ @@ -1127,20 +1729,20 @@ describe.skip('backbeat routes for replication', () => { bucket: bucketDestination, objectKey: keyName, queryObj: { versionId: 'null' }, - authCredentials: backbeatAuthCredentials, + authCredentials: destinationAuthCredentials, requestBody: objMDReplicated, }, next), - headObjectByVersionId: next => s3.headObject({ + headObjectByVersionId: next => dstS3.headObject({ Bucket: bucketDestination, Key: keyName, VersionId: versionId, }, next), - headObjectByNullVersion: next => s3.headObject({ + headObjectByNullVersion: next => dstS3.headObject({ Bucket: bucketDestination, Key: keyName, VersionId: 'null', }, next), - listObjectVersionsDestination: next => s3.listObjectVersions({ + listObjectVersionsDestination: next => dstS3.listObjectVersions({ Bucket: bucketDestination, }, next), }, (err, results) => { diff --git a/tests/unit/management/configuration.js b/tests/unit/management/configuration.js index 550aa4d931..71134c4f3c 100644 --- a/tests/unit/management/configuration.js +++ b/tests/unit/management/configuration.js @@ -36,7 +36,7 @@ function getConfig() { // Original Config const overlayVersionOriginal = Object.assign({}, config.overlayVersion); -const authDataOriginal = Object.assign({}, config.authData); +const authDataOriginal = Object.assign({}, config.authData).accounts; const locationConstraintsOriginal = Object.assign({}, config.locationConstraints); const restEndpointsOriginal = Object.assign({}, config.restEndpoints); @@ -48,10 +48,12 @@ const publicInstanceId = crypto.createHash('sha256') function resetConfig() { config.overlayVersion = overlayVersionOriginal; - config.authData = authDataOriginal; + config.authData = { accounts: authDataOriginal }; config.locationConstraints = locationConstraintsOriginal; config.restEndpoints = restEndpointsOriginal; config.browserAccessEnabled = browserAccessEnabledOriginal; + // reset auth data inside the in-memory vault backend + config.emit('authdata-update'); } function assertConfig(actualConf, expectedConf) { @@ -70,6 +72,9 @@ describe('patchConfiguration', () => { beforeEach(() => { resetConfig(); }); + after(() => { + resetConfig(); + }); it('should modify config using the new config', done => { const newConf = { diff --git a/tests/unit/routes/routeBackbeat.js b/tests/unit/routes/routeBackbeat.js index 95635aac43..62a1bfffc3 100644 --- a/tests/unit/routes/routeBackbeat.js +++ b/tests/unit/routes/routeBackbeat.js @@ -191,7 +191,7 @@ describe('routeBackbeat', () => { assert.deepStrictEqual(mockResponse.body, [{}]); }); - it('should put metadata', async () => { + it('should put non versioned metadata', async () => { mockRequest.method = 'PUT'; mockRequest.url = '/_/backbeat/metadata/bucket0/key0'; mockRequest.headers = { @@ -220,6 +220,124 @@ describe('routeBackbeat', () => { assert.deepStrictEqual(mockResponse.body, {}); }); + it('should put metadata after updating account info', async () => { + mockRequest.method = 'PUT'; + mockRequest.url = '/_/backbeat/metadata/bucket0/key0'+ + '?accountId=123456789012'; + mockRequest.headers = { + 'x-scal-versioning-required': 'true', + }; + mockRequest.destroy = () => {}; + + sandbox.stub(metadata, 'putObjectMD').callsFake((bucketName, objectKey, omVal, options, logParam, cb) => { + assert.strictEqual(omVal['owner-display-name'], 'Bart'); + assert.strictEqual(omVal['owner-id'], '79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be'); + cb(null, {}); + }); + + metadataUtils.standardMetadataValidateBucketAndObj.callsFake((params, denies, log, callback) => { + const bucketInfo = { + getVersioningConfiguration: () => ({ Status: 'Enabled' }), + isVersioningEnabled: () => true, + }; + const objMd = {}; + callback(null, bucketInfo, objMd); + }); + + routeBackbeat('127.0.0.1', mockRequest, mockResponse, log); + + void await endPromise; + + assert.strictEqual(mockResponse.statusCode, 200); + assert.deepStrictEqual(mockResponse.body, {}); + }); + + it('should fail to put metadata when accountId is invalid', async () => { + mockRequest.method = 'PUT'; + mockRequest.url = '/_/backbeat/metadata/bucket0/key0'+ + '?accountId=invalid'; + mockRequest.headers = { + 'x-scal-versioning-required': 'true', + }; + mockRequest.destroy = () => {}; + + metadataUtils.standardMetadataValidateBucketAndObj.callsFake((params, denies, log, callback) => { + const bucketInfo = { + getVersioningConfiguration: () => ({ Status: 'Enabled' }), + isVersioningEnabled: () => true, + }; + const objMd = {}; + callback(null, bucketInfo, objMd); + }); + + routeBackbeat('127.0.0.1', mockRequest, mockResponse, log); + + void await endPromise; + + assert.strictEqual(mockResponse.statusCode, 404); + assert.deepStrictEqual(mockResponse.body.code, 'AccountNotFound'); + }); + + it('should repair master when putting metadata of a new version', async () => { + mockRequest.method = 'PUT'; + mockRequest.url = '/_/backbeat/metadata/bucket0/key0'+ + '?accountId=123456789012&versionId=aIXVkw5Tw2Pd00000000001I4j3QKsvf'; + mockRequest.headers = { + 'x-scal-versioning-required': 'true', + }; + mockRequest.destroy = () => {}; + + sandbox.stub(metadata, 'putObjectMD').callsFake((bucketName, objectKey, omVal, options, logParam, cb) => { + assert.strictEqual(options.repairMaster, true); + cb(null, {}); + }); + + metadataUtils.standardMetadataValidateBucketAndObj.callsFake((params, denies, log, callback) => { + const bucketInfo = { + getVersioningConfiguration: () => ({ Status: 'Enabled' }), + isVersioningEnabled: () => true, + }; + callback(null, bucketInfo, undefined); + }); + + routeBackbeat('127.0.0.1', mockRequest, mockResponse, log); + + void await endPromise; + + assert.strictEqual(mockResponse.statusCode, 200); + assert.deepStrictEqual(mockResponse.body, {}); + }); + + it('should not repair master when updating metadata of an existing version', async () => { + mockRequest.method = 'PUT'; + mockRequest.url = '/_/backbeat/metadata/bucket0/key0'+ + '?accountId=123456789012&versionId=aIXVkw5Tw2Pd00000000001I4j3QKsvf'; + mockRequest.headers = { + 'x-scal-versioning-required': 'true', + }; + mockRequest.destroy = () => {}; + + sandbox.stub(metadata, 'putObjectMD').callsFake((bucketName, objectKey, omVal, options, logParam, cb) => { + assert.strictEqual(options.repairMaster, undefined); + cb(null, {}); + }); + + metadataUtils.standardMetadataValidateBucketAndObj.callsFake((params, denies, log, callback) => { + const bucketInfo = { + getVersioningConfiguration: () => ({ Status: 'Enabled' }), + isVersioningEnabled: () => true, + }; + callback(null, bucketInfo, {}); + }); + + routeBackbeat('127.0.0.1', mockRequest, mockResponse, log); + + void await endPromise; + + assert.strictEqual(mockResponse.statusCode, 200); + assert.deepStrictEqual(mockResponse.body, {}); + }); + it('should handle error when putting metadata', async () => { mockRequest.method = 'PUT'; mockRequest.url = '/_/backbeat/metadata/bucket0/key0'; diff --git a/yarn.lock b/yarn.lock index 9ecae4eca9..8558b450f7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -97,7 +97,7 @@ "@azure/core-util" "^1.11.0" tslib "^2.6.2" -"@azure/core-client@^1.3.0", "@azure/core-client@^1.6.2", "@azure/core-client@^1.9.2": +"@azure/core-client@^1.3.0", "@azure/core-client@^1.6.2": version "1.9.2" resolved "https://registry.yarnpkg.com/@azure/core-client/-/core-client-1.9.2.tgz#6fc69cee2816883ab6c5cdd653ee4f2ff9774f74" integrity sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w== @@ -110,6 +110,19 @@ "@azure/logger" "^1.0.0" tslib "^2.6.2" +"@azure/core-client@^1.9.2": + version "1.9.3" + resolved "https://registry.yarnpkg.com/@azure/core-client/-/core-client-1.9.3.tgz#9ca8f3bdc730d10d58f65c9c2c9ca992bc15bb67" + integrity sha512-/wGw8fJ4mdpJ1Cum7s1S+VQyXt1ihwKLzfabS1O/RDADnmzVc01dHn44qD0BvGH6KlZNzOMW95tEpKqhkCChPA== + dependencies: + "@azure/abort-controller" "^2.0.0" + "@azure/core-auth" "^1.4.0" + "@azure/core-rest-pipeline" "^1.9.1" + "@azure/core-tracing" "^1.0.0" + "@azure/core-util" "^1.6.1" + "@azure/logger" "^1.0.0" + tslib "^2.6.2" + "@azure/core-http-compat@^2.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/@azure/core-http-compat/-/core-http-compat-2.1.2.tgz#d1585ada24ba750dc161d816169b33b35f762f0d" @@ -136,7 +149,7 @@ dependencies: tslib "^2.6.2" -"@azure/core-rest-pipeline@^1.10.1", "@azure/core-rest-pipeline@^1.17.0", "@azure/core-rest-pipeline@^1.3.0", "@azure/core-rest-pipeline@^1.9.1": +"@azure/core-rest-pipeline@^1.10.1", "@azure/core-rest-pipeline@^1.3.0": version "1.18.1" resolved "https://registry.yarnpkg.com/@azure/core-rest-pipeline/-/core-rest-pipeline-1.18.1.tgz#380e7d3f15be80de83ee414176adb32824402f38" integrity sha512-/wS73UEDrxroUEVywEm7J0p2c+IIiVxyfigCGfsKvCxxCET4V/Hef2aURqltrXMRjNmdmt5IuOgIpl8f6xdO5A== @@ -150,6 +163,20 @@ https-proxy-agent "^7.0.0" tslib "^2.6.2" +"@azure/core-rest-pipeline@^1.17.0", "@azure/core-rest-pipeline@^1.9.1": + version "1.19.1" + resolved "https://registry.yarnpkg.com/@azure/core-rest-pipeline/-/core-rest-pipeline-1.19.1.tgz#e740676444777a04dc55656d8660131dfd926924" + integrity sha512-zHeoI3NCs53lLBbWNzQycjnYKsA1CVKlnzSNuSFcUDwBp8HHVObePxrM7HaX+Ha5Ks639H7chNC9HOaIhNS03w== + dependencies: + "@azure/abort-controller" "^2.0.0" + "@azure/core-auth" "^1.8.0" + "@azure/core-tracing" "^1.0.1" + "@azure/core-util" "^1.11.0" + "@azure/logger" "^1.0.0" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.0" + tslib "^2.6.2" + "@azure/core-tracing@^1.0.0", "@azure/core-tracing@^1.0.1", "@azure/core-tracing@^1.1.2": version "1.2.0" resolved "https://registry.yarnpkg.com/@azure/core-tracing/-/core-tracing-1.2.0.tgz#7be5d53c3522d639cf19042cbcdb19f71bc35ab2" @@ -174,9 +201,9 @@ tslib "^2.6.2" "@azure/identity@^4.5.0": - version "4.5.0" - resolved "https://registry.yarnpkg.com/@azure/identity/-/identity-4.5.0.tgz#93ce3757bf761a08cfd05f56ef181435e05b9e1c" - integrity sha512-EknvVmtBuSIic47xkOqyNabAme0RYTw52BTMz8eBgU1ysTyMrD1uOoM+JdS0J/4Yfp98IBT3osqq3BfwSaNaGQ== + version "4.8.0" + resolved "https://registry.yarnpkg.com/@azure/identity/-/identity-4.8.0.tgz#686682683a470ccf4dbb2597ee234f9c5c483a40" + integrity sha512-l9ALUGHtFB/JfsqmA+9iYAp2a+cCwdNO/cyIr2y7nJLJsz1aae6qVP8XxT7Kbudg0IQRSIMXj0+iivFdbD1xPA== dependencies: "@azure/abort-controller" "^2.0.0" "@azure/core-auth" "^1.9.0" @@ -185,11 +212,11 @@ "@azure/core-tracing" "^1.0.0" "@azure/core-util" "^1.11.0" "@azure/logger" "^1.0.0" - "@azure/msal-browser" "^3.26.1" - "@azure/msal-node" "^2.15.0" + "@azure/msal-browser" "^4.2.0" + "@azure/msal-node" "^3.2.3" events "^3.0.0" jws "^4.0.0" - open "^8.0.0" + open "^10.1.0" stoppable "^1.1.0" tslib "^2.2.0" @@ -200,24 +227,24 @@ dependencies: tslib "^2.6.2" -"@azure/msal-browser@^3.26.1": - version "3.28.0" - resolved "https://registry.yarnpkg.com/@azure/msal-browser/-/msal-browser-3.28.0.tgz#faf955f1debe24ebf24cf8cbfb67246c658c3f11" - integrity sha512-1c1qUF6vB52mWlyoMem4xR1gdwiQWYEQB2uhDkbAL4wVJr8WmAcXybc1Qs33y19N4BdPI8/DHI7rPE8L5jMtWw== +"@azure/msal-browser@^4.2.0": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@azure/msal-browser/-/msal-browser-4.7.0.tgz#670da9683f1046acb36ee2d87491f3f2cb90ac01" + integrity sha512-H4AIPhIQVe1qW4+BJaitqod6UGQiXE3juj7q2ZBsOPjuZicQaqcbnBp2gCroF/icS0+TJ9rGuyCBJbjlAqVOGA== dependencies: - "@azure/msal-common" "14.16.0" + "@azure/msal-common" "15.2.1" -"@azure/msal-common@14.16.0": - version "14.16.0" - resolved "https://registry.yarnpkg.com/@azure/msal-common/-/msal-common-14.16.0.tgz#f3470fcaec788dbe50859952cd499340bda23d7a" - integrity sha512-1KOZj9IpcDSwpNiQNjt0jDYZpQvNZay7QAEi/5DLubay40iGYtLzya/jbjRPLyOTZhEKyL1MzPuw2HqBCjceYA== +"@azure/msal-common@15.2.1": + version "15.2.1" + resolved "https://registry.yarnpkg.com/@azure/msal-common/-/msal-common-15.2.1.tgz#5e05627d038b6a1193ee9c7786c58c69031eb8eb" + integrity sha512-eZHtYE5OHDN0o2NahCENkczQ6ffGc0MoUSAI3hpwGpZBHJXaEQMMZPWtIx86da2L9w7uT+Tr/xgJbGwIkvTZTQ== -"@azure/msal-node@^2.15.0": - version "2.16.2" - resolved "https://registry.yarnpkg.com/@azure/msal-node/-/msal-node-2.16.2.tgz#3eb768d36883ea6f9a939c0b5b467b518e78fffc" - integrity sha512-An7l1hEr0w1HMMh1LU+rtDtqL7/jw74ORlc9Wnh06v7TU/xpG39/Zdr1ZJu3QpjUfKJ+E0/OXMW8DRSWTlh7qQ== +"@azure/msal-node@^3.2.3": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@azure/msal-node/-/msal-node-3.3.0.tgz#996fee52ad277ae0558f7482ac2657f5164fc9f1" + integrity sha512-ulsT3EHF1RQ29X55cxBLgKsIKWni9JdbUqG7sipGVP4uhWcBpmm/vhKOMH340+27Acm9+kHGnN/5XmQ5LrIDgA== dependencies: - "@azure/msal-common" "14.16.0" + "@azure/msal-common" "15.2.1" jsonwebtoken "^9.0.0" uuid "^8.3.0" @@ -400,6 +427,13 @@ debug "^4.3.1" minimatch "^3.1.2" +"@eslint/core@^0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.12.0.tgz#5f960c3d57728be9f6c65bd84aa6aa613078798e" + integrity sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg== + dependencies: + "@types/json-schema" "^7.0.15" + "@eslint/core@^0.9.0": version "0.9.1" resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.9.1.tgz#31763847308ef6b7084a4505573ac9402c51f9d1" @@ -433,10 +467,11 @@ integrity sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ== "@eslint/plugin-kit@^0.2.3": - version "0.2.4" - resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz#2b78e7bb3755784bb13faa8932a1d994d6537792" - integrity sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg== + version "0.2.7" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz#9901d52c136fb8f375906a73dcc382646c3b6a27" + integrity sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g== dependencies: + "@eslint/core" "^0.12.0" levn "^0.4.1" "@gar/promisify@^1.0.1": @@ -517,6 +552,25 @@ resolved "https://registry.yarnpkg.com/@ioredis/commands/-/commands-1.2.0.tgz#6d61b3097470af1fdbbe622795b8921d42018e11" integrity sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg== +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + +"@isaacs/fs-minipass@^4.0.0": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz#2d59ae3ab4b38fb4270bfa23d30f8e2e86c7fe32" + integrity sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w== + dependencies: + minipass "^7.0.4" + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -577,6 +631,17 @@ dependencies: sparse-bitfield "^3.0.3" +"@npmcli/agent@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@npmcli/agent/-/agent-3.0.0.tgz#1685b1fbd4a1b7bb4f930cbb68ce801edfe7aa44" + integrity sha512-S79NdEgDQd/NGCay6TCoVzXSj74skRZIKJcpJjC5lOq34SZzyI6MqtiiWoiVWoVrTcGjNeC4ipbh1VIHlpfF5Q== + dependencies: + agent-base "^7.1.0" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.1" + lru-cache "^10.0.1" + socks-proxy-agent "^8.0.3" + "@npmcli/fs@^1.0.0": version "1.1.1" resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.1.1.tgz#72f719fe935e687c56a4faecf3c03d06ba593257" @@ -585,6 +650,13 @@ "@gar/promisify" "^1.0.1" semver "^7.3.5" +"@npmcli/fs@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-4.0.0.tgz#a1eb1aeddefd2a4a347eca0fab30bc62c0e1c0f2" + integrity sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q== + dependencies: + semver "^7.3.5" + "@npmcli/move-file@^1.0.1": version "1.1.2" resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" @@ -598,6 +670,11 @@ resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.9.0.tgz#d03eba68273dc0f7509e2a3d5cba21eae10379fe" integrity sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg== +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + "@rtsao/scc@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" @@ -871,11 +948,6 @@ resolved "https://registry.yarnpkg.com/@types/async/-/async-3.2.24.tgz#3a96351047575bbcf2340541b2d955a35339608f" integrity sha512-8iHVLHsCCOBKjCF2KwFe0p9Z3rfM9mL+sSP8btyR5vTjJRAqpBYD28/ZLgXPf0pjG1VxOvtCV/BgXkQbpSe8Hw== -"@types/cookie@^0.4.1": - version "0.4.1" - resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d" - integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q== - "@types/cors@^2.8.12": version "2.8.17" resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.17.tgz#5d718a5e494a8166f569d986794e49c48b216b2b" @@ -899,9 +971,9 @@ integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== "@types/node@*", "@types/node@>=10.0.0": - version "22.10.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.5.tgz#95af89a3fb74a2bb41ef9927f206e6472026e48b" - integrity sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ== + version "22.13.10" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.13.10.tgz#df9ea358c5ed991266becc3109dc2dc9125d77e4" + integrity sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw== dependencies: undici-types "~6.20.0" @@ -940,6 +1012,11 @@ abbrev@1.0.x: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" integrity sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q== +abbrev@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-3.0.0.tgz#c29a6337e167ac61a84b41b80461b29c5c271a27" + integrity sha512-+/kfrslGQ7TNV2ecmQwMJj/B65g5KVq1/L3SGVZ3tCYGqlzFuFCGBZJtMP99wH3NpEUyAjn0zPdPUg0D+DwrOA== + abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" @@ -1071,6 +1148,11 @@ ansi-regex@^5.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +ansi-regex@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== + ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -1085,6 +1167,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + anymatch@~3.1.2: version "3.1.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" @@ -1251,9 +1338,9 @@ arraybuffer.prototype.slice@^1.0.4: optionalDependencies: ioctl "^2.0.2" -"arsenal@git+https://github.com/scality/arsenal#8.2.5": - version "8.2.5" - resolved "git+https://github.com/scality/arsenal#3bb996c9282dd54f50004b2008fbc1675a327b69" +"arsenal@git+https://github.com/scality/arsenal#8.2.8": + version "8.2.8" + resolved "git+https://github.com/scality/arsenal#a4136e5da67cadf3cff14de0daabd019bfd5f996" dependencies: "@azure/identity" "^4.5.0" "@azure/storage-blob" "^12.25.0" @@ -1497,11 +1584,16 @@ browserslist@^4.24.0: node-releases "^2.0.19" update-browserslist-db "^1.1.1" -bson@^6.10.1, bson@^6.8.0: +bson@^6.10.1: version "6.10.1" resolved "https://registry.yarnpkg.com/bson/-/bson-6.10.1.tgz#dcd04703178f5ecf5b25de04edd2a95ec79385d3" integrity sha512-P92xmHDQjSKPLHqFxefqMxASNq/aWJMEZugpCjf+AF/pgcUpMMQCg7t7+ewko0/u8AapvF3luf/FoehddEK+sA== +bson@^6.8.0: + version "6.10.3" + resolved "https://registry.yarnpkg.com/bson/-/bson-6.10.3.tgz#5f9a463af6b83e264bedd08b236d1356a30eda47" + integrity sha512-MTxGsqgYTwfshYWTRdmZRC+M7FnG1b4y7RO7p2k3X24Wq0yv1m77Wsj0BzlPzd/IowgESfsruQCUToa7vbOpPQ== + bucketclient@scality/bucketclient#8.2.0: version "8.2.0" resolved "https://codeload.github.com/scality/bucketclient/tar.gz/17bbe441333c3fc5cbd26ade21eda3826fc51ca5" @@ -1539,6 +1631,13 @@ bufferutil@^4.0.8: dependencies: node-gyp-build "^4.3.0" +bundle-name@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bundle-name/-/bundle-name-4.1.0.tgz#f3b96b34160d6431a19d7688135af7cfb8797889" + integrity sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q== + dependencies: + run-applescript "^7.0.0" + bytes@3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" @@ -1583,6 +1682,24 @@ cacache@^15.2.0: tar "^6.0.2" unique-filename "^1.1.1" +cacache@^19.0.1: + version "19.0.1" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-19.0.1.tgz#3370cc28a758434c85c2585008bd5bdcff17d6cd" + integrity sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ== + dependencies: + "@npmcli/fs" "^4.0.0" + fs-minipass "^3.0.0" + glob "^10.2.2" + lru-cache "^10.0.1" + minipass "^7.0.3" + minipass-collect "^2.0.1" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + p-map "^7.0.2" + ssri "^12.0.0" + tar "^7.4.3" + unique-filename "^4.0.0" + caching-transform@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/caching-transform/-/caching-transform-4.0.0.tgz#00d297a4206d71e2163c39eaffa8157ac0651f0f" @@ -1593,10 +1710,10 @@ caching-transform@^4.0.0: package-hash "^4.0.0" write-file-atomic "^3.0.0" -call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz#32e5892e6361b29b0b545ba6f7763378daca2840" - integrity sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g== +call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== dependencies: es-errors "^1.3.0" function-bind "^1.1.2" @@ -1611,13 +1728,13 @@ call-bind@^1.0.7, call-bind@^1.0.8: get-intrinsic "^1.2.4" set-function-length "^1.2.2" -call-bound@^1.0.2, call-bound@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.3.tgz#41cfd032b593e39176a71533ab4f384aa04fd681" - integrity sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA== +call-bound@^1.0.2, call-bound@^1.0.3, call-bound@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a" + integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== dependencies: - call-bind-apply-helpers "^1.0.1" - get-intrinsic "^1.2.6" + call-bind-apply-helpers "^1.0.2" + get-intrinsic "^1.3.0" callsites@^3.0.0: version "3.1.0" @@ -1686,6 +1803,11 @@ chownr@^2.0.0: resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== +chownr@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-3.0.0.tgz#9855e64ecd240a9cc4267ce8a4aa5d24a1da15e4" + integrity sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g== + clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" @@ -1959,6 +2081,19 @@ deep-is@^0.1.3, deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== +default-browser-id@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/default-browser-id/-/default-browser-id-5.0.0.tgz#a1d98bf960c15082d8a3fa69e83150ccccc3af26" + integrity sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA== + +default-browser@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/default-browser/-/default-browser-5.2.1.tgz#7b7ba61204ff3e425b556869ae6d3e9d9f1712cf" + integrity sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg== + dependencies: + bundle-name "^4.1.0" + default-browser-id "^5.0.0" + default-require-extensions@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7" @@ -1997,10 +2132,10 @@ define-data-property@^1.0.1, define-data-property@^1.1.4: es-errors "^1.3.0" gopd "^1.0.1" -define-lazy-prop@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" - integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== +define-lazy-prop@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz#dbb19adfb746d7fc6d734a06b72f4a00d021255f" + integrity sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg== define-properties@^1.2.1: version "1.2.1" @@ -2070,6 +2205,11 @@ dunder-proto@^1.0.0, dunder-proto@^1.0.1: es-errors "^1.3.0" gopd "^1.2.0" +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -2100,6 +2240,11 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" @@ -2120,7 +2265,7 @@ encoding-down@^6.3.0: level-codec "^9.0.0" level-errors "^2.0.0" -encoding@^0.1.12: +encoding@^0.1.12, encoding@^0.1.13: version "0.1.13" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== @@ -2128,9 +2273,9 @@ encoding@^0.1.12: iconv-lite "^0.6.2" engine.io-client@~6.6.1: - version "6.6.2" - resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.6.2.tgz#e0a09e1c90effe5d6264da1c56d7281998f1e50b" - integrity sha512-TAr+NKeoVTjEVW8P3iHguO1LO6RlUz9O5Y8o7EY0fU+gY1NYqas7NN3slpFtbXEsLMHk0h90fJMfKjRkQ0qUIw== + version "6.6.3" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.6.3.tgz#815393fa24f30b8e6afa8f77ccca2f28146be6de" + integrity sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w== dependencies: "@socket.io/component-emitter" "~3.1.0" debug "~4.3.1" @@ -2144,11 +2289,10 @@ engine.io-parser@~5.2.1: integrity sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q== engine.io@~6.6.0: - version "6.6.2" - resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.6.2.tgz#32bd845b4db708f8c774a4edef4e5c8a98b3da72" - integrity sha512-gmNvsYi9C8iErnZdVcJnvCpSKbWTt1E8+JZo8b+daLninywUWi5NQ5STSHZ9rFjFO7imNcvb8Pc5pe/wMR5xEw== + version "6.6.4" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.6.4.tgz#0a89a3e6b6c1d4b0c2a2a637495e7c149ec8d8ee" + integrity sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g== dependencies: - "@types/cookie" "^0.4.1" "@types/cors" "^2.8.12" "@types/node" ">=10.0.0" accepts "~1.3.4" @@ -2255,10 +2399,10 @@ es-errors@^1.3.0: resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== -es-object-atoms@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" - integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== dependencies: es-errors "^1.3.0" @@ -2575,6 +2719,11 @@ events@^3.0.0: resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== +exponential-backoff@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.2.tgz#a8f26adb96bf78e8cd8ad1037928d5e5c0679d91" + integrity sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA== + express@^4.21.1: version "4.21.2" resolved "https://registry.yarnpkg.com/express/-/express-4.21.2.tgz#cf250e48362174ead6cea4a566abef0162c1ec32" @@ -2772,12 +2921,12 @@ follow-redirects@^1.0.0, follow-redirects@^1.15.6: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== -for-each@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" - integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== +for-each@^0.3.3, for-each@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.5.tgz#d650688027826920feeb0af747ee7b9421a41d47" + integrity sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg== dependencies: - is-callable "^1.1.3" + is-callable "^1.2.7" foreground-child@^2.0.0: version "2.0.0" @@ -2787,6 +2936,14 @@ foreground-child@^2.0.0: cross-spawn "^7.0.0" signal-exit "^3.0.2" +foreground-child@^3.1.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f" + integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== + dependencies: + cross-spawn "^7.0.6" + signal-exit "^4.0.1" + forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -2832,6 +2989,13 @@ fs-minipass@^2.0.0: dependencies: minipass "^3.0.0" +fs-minipass@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-3.0.3.tgz#79a85981c4dc120065e96f62086bf6f9dc26cc54" + integrity sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw== + dependencies: + minipass "^7.0.3" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -2912,7 +3076,23 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.2.7: +get-intrinsic@^1.2.4, get-intrinsic@^1.2.6, get-intrinsic@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-intrinsic@^1.2.5, get-intrinsic@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.7.tgz#dcfcb33d3272e15f445d15124bc0a216189b9044" integrity sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA== @@ -2971,6 +3151,18 @@ glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" +glob@^10.2.2, glob@^10.3.10, glob@^10.3.7: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" + glob@^5.0.15: version "5.0.15" resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" @@ -3195,7 +3387,7 @@ html-escaper@^2.0.0: resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== -http-cache-semantics@^4.1.0: +http-cache-semantics@^4.1.0, http-cache-semantics@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== @@ -3281,7 +3473,7 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" -https-proxy-agent@^7.0.0, https-proxy-agent@^7.0.5: +https-proxy-agent@^7.0.0, https-proxy-agent@^7.0.1, https-proxy-agent@^7.0.5: version "7.0.6" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz#da8dfeac7da130b05c2ba4b59c9b6cd66611a6b9" integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw== @@ -3485,7 +3677,7 @@ is-buffer@~1.1.6: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-callable@^1.1.3, is-callable@^1.2.7: +is-callable@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== @@ -3514,10 +3706,10 @@ is-date-object@^1.0.5, is-date-object@^1.1.0: call-bound "^1.0.2" has-tostringtag "^1.0.2" -is-docker@^2.0.0, is-docker@^2.1.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" - integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== +is-docker@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-3.0.0.tgz#90093aa3106277d8a77a5910dbae71747e15a200" + integrity sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ== is-extglob@^2.1.1: version "2.1.1" @@ -3553,6 +3745,13 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" +is-inside-container@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-inside-container/-/is-inside-container-1.0.0.tgz#e81fba699662eb31dbdaf26766a61d4814717ea4" + integrity sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA== + dependencies: + is-docker "^3.0.0" + is-lambda@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" @@ -3667,12 +3866,12 @@ is-windows@^1.0.2: resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== -is-wsl@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" - integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== +is-wsl@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-3.1.0.tgz#e1c657e39c10090afcbedec61720f6b924c3cbd2" + integrity sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw== dependencies: - is-docker "^2.0.0" + is-inside-container "^1.0.0" isarray@0.0.1: version "0.0.1" @@ -3694,6 +3893,11 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +isexe@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-3.1.1.tgz#4a407e2bd78ddfb14bea0c27c6f7072dde775f0d" + integrity sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ== + isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -3851,6 +4055,15 @@ istanbul@^0.4.5: which "^1.1.1" wordwrap "^1.0.0" +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + jmespath@0.16.0: version "0.16.0" resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.16.0.tgz#b15b0a85dfd4d930d43e69ed605943c802785076" @@ -4299,6 +4512,11 @@ looper@^3.0.0: resolved "https://registry.yarnpkg.com/looper/-/looper-3.0.0.tgz#2efa54c3b1cbaba9b94aee2e5914b0be57fbb749" integrity sha512-LJ9wplN/uSn72oJRsXTx+snxPet5c8XiZmOKCm906NVYu+ag6SB6vUcnJcWxgnl2NfbIyeobAn7Bwv6xRj2XJg== +lru-cache@^10.0.1, lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + lru-cache@^4.1.3: version "4.1.5" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" @@ -4358,6 +4576,23 @@ make-dir@^4.0.0: dependencies: semver "^7.5.3" +make-fetch-happen@^14.0.3: + version "14.0.3" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-14.0.3.tgz#d74c3ecb0028f08ab604011e0bc6baed483fcdcd" + integrity sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ== + dependencies: + "@npmcli/agent" "^3.0.0" + cacache "^19.0.1" + http-cache-semantics "^4.1.1" + minipass "^7.0.2" + minipass-fetch "^4.0.0" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + negotiator "^1.0.0" + proc-log "^5.0.0" + promise-retry "^2.0.1" + ssri "^12.0.0" + make-fetch-happen@^9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz#53085a09e7971433e6765f7971bf63f4e05cb968" @@ -4496,6 +4731,13 @@ minimatch@^5.0.1, minimatch@^5.1.6: dependencies: brace-expansion "^2.0.1" +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" @@ -4508,6 +4750,13 @@ minipass-collect@^1.0.2: dependencies: minipass "^3.0.0" +minipass-collect@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-2.0.1.tgz#1621bc77e12258a12c60d34e2276ec5c20680863" + integrity sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw== + dependencies: + minipass "^7.0.3" + minipass-fetch@^1.3.2: version "1.4.1" resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.4.1.tgz#d75e0091daac1b0ffd7e9d41629faff7d0c1f1b6" @@ -4519,6 +4768,17 @@ minipass-fetch@^1.3.2: optionalDependencies: encoding "^0.1.12" +minipass-fetch@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-4.0.1.tgz#f2d717d5a418ad0b1a7274f9b913515d3e78f9e5" + integrity sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ== + dependencies: + minipass "^7.0.3" + minipass-sized "^1.0.3" + minizlib "^3.0.1" + optionalDependencies: + encoding "^0.1.13" + minipass-flush@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" @@ -4552,6 +4812,11 @@ minipass@^5.0.0: resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.2, minipass@^7.0.3, minipass@^7.0.4, minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + minizlib@^2.0.0, minizlib@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" @@ -4560,6 +4825,14 @@ minizlib@^2.0.0, minizlib@^2.1.1: minipass "^3.0.0" yallist "^4.0.0" +minizlib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-3.0.1.tgz#46d5329d1eb3c83924eff1d3b858ca0a31581012" + integrity sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg== + dependencies: + minipass "^7.0.4" + rimraf "^5.0.5" + mkdirp@0.5.x: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" @@ -4572,7 +4845,7 @@ mkdirp@^1.0.3, mkdirp@^1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mkdirp@^3.0.0: +mkdirp@^3.0.0, mkdirp@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== @@ -4679,6 +4952,11 @@ negotiator@^0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.4.tgz#777948e2452651c570b712dd01c23e262713fff7" integrity sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w== +negotiator@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a" + integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg== + neo-async@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" @@ -4705,6 +4983,11 @@ nise@^5.1.1: just-extend "^6.2.0" path-to-regexp "^6.2.1" +node-addon-api@^8.3.0: + version "8.3.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-8.3.1.tgz#53bc8a4f8dbde3de787b9828059da94ba9fd4eed" + integrity sha512-lytcDEdxKjGJPTLEfW4mYMigRezMlyJY8W4wxJK8zE533Jlb8L8dRuObJFWg2P+AuOIxoCgKF+2Oq4d4Zd0OUA== + node-fetch@^2.3.0, node-fetch@^2.6.0: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" @@ -4732,6 +5015,22 @@ node-gyp-build@~4.1.0: resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.1.1.tgz#d7270b5d86717068d114cc57fff352f96d745feb" integrity sha512-dSq1xmcPDKPZ2EED2S6zw/b9NKsqzXRE6dVr8TVQnI3FJOTteUMuqF3Qqs6LZg+mLGYJWqQzMbIjMtJqTv87nQ== +node-gyp@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-11.1.0.tgz#212a1d9c167c50d727d42659410780b40e07bbd3" + integrity sha512-/+7TuHKnBpnMvUQnsYEb0JOozDZqarQbfNuSGLXIjhStMT0fbw7IdSqWgopOP5xhRZE+lsbIvAHcekddruPZgQ== + dependencies: + env-paths "^2.2.0" + exponential-backoff "^3.1.1" + glob "^10.3.10" + graceful-fs "^4.2.6" + make-fetch-happen "^14.0.3" + nopt "^8.0.0" + proc-log "^5.0.0" + semver "^7.3.5" + tar "^7.4.3" + which "^5.0.0" + node-gyp@^8.0.0: version "8.4.1" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-8.4.1.tgz#3d49308fc31f768180957d6b5746845fbd429937" @@ -4790,6 +5089,13 @@ nopt@^5.0.0: dependencies: abbrev "1" +nopt@^8.0.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-8.1.0.tgz#b11d38caf0f8643ce885818518064127f602eae3" + integrity sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A== + dependencies: + abbrev "^3.0.0" + normalize-package-data@^2.3.2: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -4938,14 +5244,15 @@ once@1.x, once@^1.3.0, once@^1.4.0: dependencies: wrappy "1" -open@^8.0.0: - version "8.4.2" - resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" - integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== +open@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/open/-/open-10.1.0.tgz#a7795e6e5d519abe4286d9937bb24b51122598e1" + integrity sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw== dependencies: - define-lazy-prop "^2.0.0" - is-docker "^2.1.1" - is-wsl "^2.2.0" + default-browser "^5.2.1" + define-lazy-prop "^3.0.0" + is-inside-container "^1.0.0" + is-wsl "^3.1.0" opencollective-postinstall@^2.0.0: version "2.0.3" @@ -5027,6 +5334,11 @@ p-map@^4.0.0: dependencies: aggregate-error "^3.0.0" +p-map@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-7.0.3.tgz#7ac210a2d36f81ec28b736134810f7ba4418cdb6" + integrity sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA== + p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" @@ -5042,6 +5354,11 @@ package-hash@^4.0.0: lodash.flattendeep "^4.4.0" release-zalgo "^1.0.0" +package-json-from-dist@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" + integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -5087,6 +5404,14 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-to-regexp@0.1.12: version "0.1.12" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.12.tgz#d5e1a12e478a976d432ef3c58d534b9923164bb7" @@ -5142,9 +5467,9 @@ pkg-dir@^4.1.0: find-up "^4.0.0" possible-typed-array-names@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" - integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== + version "1.1.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz#93e3582bc0e5426586d9d07b79ee40fc841de4ae" + integrity sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg== prelude-ls@^1.2.1: version "1.2.1" @@ -5156,6 +5481,11 @@ prelude-ls@~1.1.2: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== +proc-log@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-5.0.0.tgz#e6c93cf37aef33f835c53485f314f50ea906a9d8" + integrity sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ== + process-on-spawn@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/process-on-spawn/-/process-on-spawn-1.1.0.tgz#9d5999ba87b3bf0a8acb05322d69f2f5aa4fb763" @@ -5490,6 +5820,18 @@ rimraf@^3.0.0, rimraf@^3.0.2: dependencies: glob "^7.1.3" +rimraf@^5.0.5: + version "5.0.10" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.10.tgz#23b9843d3dc92db71f96e1a2ce92e39fd2a8221c" + integrity sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ== + dependencies: + glob "^10.3.7" + +run-applescript@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/run-applescript/-/run-applescript-7.0.0.tgz#e5a553c2bffd620e169d276c1cd8f1b64778fbeb" + integrity sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A== + safe-array-concat@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.3.tgz#c9e54ec4f603b0bbb8e7e5007a5ee7aecd1538c3" @@ -5561,7 +5903,12 @@ semver@^6.0.0, semver@^6.3.0, semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.5, semver@^7.5.3, semver@^7.5.4: +semver@^7.3.5, semver@^7.5.4: + version "7.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f" + integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== + +semver@^7.5.3: version "7.6.3" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== @@ -5722,6 +6069,11 @@ signal-exit@^3.0.2, signal-exit@^3.0.7: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + simple-glob@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/simple-glob/-/simple-glob-0.2.0.tgz#95cf6a5fb5d84843a52a58529cba31b0f5c3478c" @@ -5797,6 +6149,15 @@ socks-proxy-agent@^6.0.0: debug "^4.3.3" socks "^2.6.2" +socks-proxy-agent@^8.0.3: + version "8.0.5" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz#b9cdb4e7e998509d7659d689ce7697ac21645bee" + integrity sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw== + dependencies: + agent-base "^7.1.2" + debug "^4.3.4" + socks "^2.8.3" + socks@^2.6.2: version "2.8.3" resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.3.tgz#1ebd0f09c52ba95a09750afe3f3f9f724a800cb5" @@ -5805,6 +6166,14 @@ socks@^2.6.2: ip-address "^9.0.5" smart-buffer "^4.2.0" +socks@^2.8.3: + version "2.8.4" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.4.tgz#07109755cdd4da03269bda4725baa061ab56d5cc" + integrity sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ== + dependencies: + ip-address "^9.0.5" + smart-buffer "^4.2.0" + source-map@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -5903,6 +6272,13 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" +ssri@^12.0.0: + version "12.0.0" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-12.0.0.tgz#bcb4258417c702472f8191981d3c8a771fee6832" + integrity sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ== + dependencies: + minipass "^7.0.3" + ssri@^8.0.0, ssri@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" @@ -5933,6 +6309,15 @@ stream-to-pull-stream@^1.7.1: looper "^3.0.0" pull-stream "^3.2.3" +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -5942,6 +6327,15 @@ stream-to-pull-stream@^1.7.1: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + string.prototype.padend@^3.0.0: version "3.1.6" resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz#ba79cf8992609a91c872daa47c6bb144ee7f62a5" @@ -5996,6 +6390,13 @@ string_decoder@~0.10.x: resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -6003,6 +6404,13 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -6075,6 +6483,18 @@ tar@^6.0.2, tar@^6.1.2: mkdirp "^1.0.3" yallist "^4.0.0" +tar@^7.4.3: + version "7.4.3" + resolved "https://registry.yarnpkg.com/tar/-/tar-7.4.3.tgz#88bbe9286a3fcd900e94592cda7a22b192e80571" + integrity sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw== + dependencies: + "@isaacs/fs-minipass" "^4.0.0" + chownr "^3.0.0" + minipass "^7.1.2" + minizlib "^3.0.1" + mkdirp "^3.0.1" + yallist "^5.0.0" + tdigest@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/tdigest/-/tdigest-0.1.2.tgz#96c64bac4ff10746b910b0e23b515794e12faced" @@ -6313,6 +6733,13 @@ unique-filename@^1.1.1: dependencies: unique-slug "^2.0.0" +unique-filename@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-4.0.0.tgz#a06534d370e7c977a939cd1d11f7f0ab8f1fed13" + integrity sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ== + dependencies: + unique-slug "^5.0.0" + unique-slug@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" @@ -6320,6 +6747,13 @@ unique-slug@^2.0.0: dependencies: imurmurhash "^0.1.4" +unique-slug@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-5.0.0.tgz#ca72af03ad0dbab4dad8aa683f633878b1accda8" + integrity sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg== + dependencies: + imurmurhash "^0.1.4" + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -6458,6 +6892,7 @@ webidl-conversions@^7.0.0: "werelogs@github:scality/werelogs#8.2.2", werelogs@scality/werelogs#8.2.2: version "8.2.2" + uid e53bef5145697bf8af940dcbe59408988d64854f resolved "https://codeload.github.com/scality/werelogs/tar.gz/e53bef5145697bf8af940dcbe59408988d64854f" dependencies: fast-safe-stringify "^2.1.1" @@ -6538,7 +6973,20 @@ which-module@^2.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== -which-typed-array@^1.1.16, which-typed-array@^1.1.18, which-typed-array@^1.1.2: +which-typed-array@^1.1.16, which-typed-array@^1.1.2: + version "1.1.19" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.19.tgz#df03842e870b6b88e117524a4b364b6fc689f956" + integrity sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.4" + for-each "^0.3.5" + get-proto "^1.0.1" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + +which-typed-array@^1.1.18: version "1.1.18" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.18.tgz#df2389ebf3fbb246a71390e90730a9edb6ce17ad" integrity sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA== @@ -6564,6 +7012,13 @@ which@^2.0.1, which@^2.0.2: dependencies: isexe "^2.0.0" +which@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/which/-/which-5.0.0.tgz#d93f2d93f79834d4363c7d0c23e00d07c466c8d6" + integrity sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ== + dependencies: + isexe "^3.1.1" + wide-align@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" @@ -6586,6 +7041,15 @@ workerpool@^6.5.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" @@ -6604,6 +7068,15 @@ wrap-ansi@^7.0.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -6687,6 +7160,11 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yallist@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-5.0.0.tgz#00e2de443639ed0d78fd87de0d27469fbcffb533" + integrity sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw== + yargs-parser@^18.1.2: version "18.1.3" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0"