upgrade aws-sdk to v3 for AwsS3UrlReader

Signed-off-by: Lucas Guarisco <lucas.guarisco@gmail.com>
This commit is contained in:
Lucas Guarisco
2023-02-28 17:41:39 -03:00
committed by Lucas Guarisco
parent d06fc3f3e3
commit 87f0bbec17
5 changed files with 500 additions and 187 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-common': minor
---
AwsS3UrlReader upgraded to use aws-sdk v3
+7 -2
View File
@@ -46,6 +46,10 @@
"test:kubernetes": "backstage-cli package test -t KubernetesContainerRunner --no-watch"
},
"dependencies": {
"@aws-sdk/abort-controller": "^3.272.0",
"@aws-sdk/client-s3": "^3.276.0",
"@aws-sdk/credential-providers": "^3.276.0",
"@aws-sdk/types": "^3.272.0",
"@backstage/backend-app-api": "workspace:^",
"@backstage/backend-dev-utils": "workspace:^",
"@backstage/backend-plugin-api": "workspace:^",
@@ -54,6 +58,7 @@
"@backstage/config-loader": "workspace:^",
"@backstage/errors": "workspace:^",
"@backstage/integration": "workspace:^",
"@backstage/integration-aws-node": "workspace:^",
"@backstage/types": "workspace:^",
"@google-cloud/storage": "^6.0.0",
"@keyv/memcache": "^1.3.5",
@@ -67,7 +72,6 @@
"@types/luxon": "^3.0.0",
"@types/webpack-env": "^1.15.2",
"archiver": "^5.0.2",
"aws-sdk": "^2.840.0",
"base64-stream": "^1.0.0",
"compression": "^1.7.4",
"concat-stream": "^2.0.0",
@@ -110,6 +114,7 @@
}
},
"devDependencies": {
"@aws-sdk/util-stream-node": "^3.272.0",
"@backstage/backend-test-utils": "workspace:^",
"@backstage/cli": "workspace:^",
"@types/archiver": "^5.1.0",
@@ -128,9 +133,9 @@
"@types/tar": "^6.1.1",
"@types/webpack-env": "^1.15.2",
"@types/yauzl": "^2.10.0",
"aws-sdk-client-mock": "^2.0.1",
"aws-sdk-mock": "^5.2.1",
"better-sqlite3": "^8.0.0",
"http-errors": "^2.0.0",
"mock-fs": "^5.1.0",
"msw": "^1.0.0",
"mysql2": "^2.2.5",
@@ -18,19 +18,26 @@ import { ConfigReader } from '@backstage/config';
import { JsonObject } from '@backstage/types';
import { getVoidLogger } from '../logging';
import { DefaultReadTreeResponseFactory } from './tree';
import { rest } from 'msw';
import { setupServer } from 'msw/node';
import { setupRequestMockHandlers } from '@backstage/backend-test-utils';
import { AwsS3UrlReader, parseUrl } from './AwsS3UrlReader';
import { DEFAULT_REGION, AwsS3UrlReader, parseUrl } from './AwsS3UrlReader';
import {
AwsS3Integration,
readAwsS3IntegrationConfig,
} from '@backstage/integration';
import { UrlReaderPredicateTuple } from './types';
import AWSMock from 'aws-sdk-mock';
import aws from 'aws-sdk';
import path from 'path';
import { NotModifiedError } from '@backstage/errors';
import { mockClient } from 'aws-sdk-client-mock';
import {
S3Client,
ListObjectsV2Command,
ListObjectsV2Output,
GetObjectCommand,
S3ServiceException,
} from '@aws-sdk/client-s3';
import { sdkStreamMixin } from '@aws-sdk/util-stream-node';
import fs from 'fs';
const treeResponseFactory = DefaultReadTreeResponseFactory.create({
config: new ConfigReader({}),
@@ -97,7 +104,7 @@ describe('parseUrl', () => {
).toEqual({
path: 'a/puppy.jpg',
bucket: 'my.bucket-3',
region: '',
region: DEFAULT_REGION,
});
expect(
parseUrl('https://my.bucket-3.my-host.com/a/puppy.jpg', {
@@ -106,7 +113,7 @@ describe('parseUrl', () => {
).toEqual({
path: 'a/puppy.jpg',
bucket: 'my.bucket-3',
region: '',
region: DEFAULT_REGION,
});
expect(
parseUrl('https://ignored.my-host.com/my.bucket-3/a/puppy.jpg', {
@@ -116,12 +123,13 @@ describe('parseUrl', () => {
).toEqual({
path: 'a/puppy.jpg',
bucket: 'my.bucket-3',
region: '',
region: DEFAULT_REGION,
});
});
});
describe('AwsS3UrlReader', () => {
const s3Client = mockClient(S3Client);
const worker = setupServer();
setupRequestMockHandlers(worker);
@@ -232,17 +240,19 @@ describe('AwsS3UrlReader', () => {
});
beforeEach(() => {
worker.use(
rest.get(
'https://test-bucket.s3.amazonaws.com/awsS3-mock-object.yaml',
(_, res, ctx) =>
res(
ctx.status(200),
ctx.set('ETag', '123abc'),
ctx.body('site_name: Test'),
s3Client.reset();
s3Client.on(GetObjectCommand).resolves({
Body: sdkStreamMixin(
fs.createReadStream(
path.resolve(
__dirname,
'__fixtures__/awsS3/awsS3-mock-object.yaml',
),
),
),
);
ETag: '123abc',
});
});
it('returns contents of an object in a bucket', async () => {
@@ -280,17 +290,19 @@ describe('AwsS3UrlReader', () => {
});
beforeEach(() => {
worker.use(
rest.get(
'https://test-bucket.s3.amazonaws.com/awsS3-mock-object.yaml',
(_, res, ctx) =>
res(
ctx.status(200),
ctx.set('ETag', '123abc'),
ctx.body('site_name: Test'),
s3Client.reset();
s3Client.on(GetObjectCommand).resolves({
Body: sdkStreamMixin(
fs.createReadStream(
path.resolve(
__dirname,
'__fixtures__/awsS3/awsS3-mock-object.yaml',
),
),
),
);
ETag: '123abc',
});
});
it('returns contents of an object in a bucket via buffer', async () => {
@@ -340,17 +352,17 @@ describe('AwsS3UrlReader', () => {
});
beforeEach(() => {
worker.use(
rest.get(
'http://localhost:4566/test-bucket/awsS3-mock-object.yaml',
(_, res, ctx) =>
res(
ctx.status(200),
ctx.set('ETag', '123abc'),
ctx.body('site_name: Test'),
s3Client.on(GetObjectCommand).resolves({
Body: sdkStreamMixin(
fs.createReadStream(
path.resolve(
__dirname,
'__fixtures__/awsS3/awsS3-mock-object.yaml',
),
),
),
);
ETag: '123abc',
});
});
it('returns contents of an object in a bucket via buffer', async () => {
@@ -377,12 +389,13 @@ describe('AwsS3UrlReader', () => {
});
beforeEach(() => {
worker.use(
rest.get(
'https://test-bucket.s3.amazonaws.com/awsS3-mock-object.yaml',
(_, res, ctx) => res(ctx.status(304)),
),
);
s3Client.reset();
const t = new S3ServiceException({
name: '304',
$fault: 'client',
$metadata: { httpStatusCode: 304 },
});
s3Client.on(GetObjectCommand).rejects(t);
});
it('returns contents of an object in a bucket', async () => {
@@ -400,44 +413,41 @@ describe('AwsS3UrlReader', () => {
describe('readTree', () => {
let awsS3UrlReader: AwsS3UrlReader;
beforeAll(() => {
const object: aws.S3.Types.Object = {
beforeEach(() => {
s3Client.reset();
const object: Object = {
Key: 'awsS3-mock-object.yaml',
};
const objectList: aws.S3.ObjectList = [object];
const output: aws.S3.Types.ListObjectsV2Output = {
const objectList: Object[] = [object];
const output: ListObjectsV2Output = {
Contents: objectList,
};
AWSMock.setSDKInstance(aws);
AWSMock.mock('S3', 'listObjectsV2', output);
s3Client.on(ListObjectsV2Command).resolves(output);
AWSMock.mock(
'S3',
'getObject',
Buffer.from(
require('fs').readFileSync(
s3Client.on(GetObjectCommand).resolves({
Body: sdkStreamMixin(
fs.createReadStream(
path.resolve(
__dirname,
'__fixtures__/awsS3/awsS3-mock-object.yaml',
),
),
),
);
});
const config = new ConfigReader({
host: '.amazonaws.com',
accessKeyId: 'fake-access-key',
secretAccessKey: 'fake-secret-key',
});
const s3 = new aws.S3();
awsS3UrlReader = new AwsS3UrlReader(
new AwsS3Integration(
readAwsS3IntegrationConfig(
new ConfigReader({
host: '.amazonaws.com',
accessKeyId: 'fake-access-key',
secretAccessKey: 'fake-secret-key',
}),
),
),
{ s3, treeResponseFactory },
config,
new AwsS3Integration(readAwsS3IntegrationConfig(config)),
{ treeResponseFactory },
);
});
@@ -14,10 +14,6 @@
* limitations under the License.
*/
// note: We do the import like this so that we don't get issues destructuring
// and it not being mocked by the aws-sdk-mock package which is unfortunate.
import aws from 'aws-sdk';
import { CredentialsOptions } from 'aws-sdk/lib/credentials';
import {
ReaderFactory,
ReadTreeOptions,
@@ -28,16 +24,30 @@ import {
SearchResponse,
UrlReader,
} from './types';
import {
AwsCredentialsManager,
DefaultAwsCredentialsManager,
} from '@backstage/integration-aws-node';
import {
AwsS3Integration,
ScmIntegrations,
AwsS3IntegrationConfig,
} from '@backstage/integration';
import { Config } from '@backstage/config';
import { ForwardedError, NotModifiedError } from '@backstage/errors';
import { ListObjectsV2Output, ObjectList } from 'aws-sdk/clients/s3';
import { fromTemporaryCredentials } from '@aws-sdk/credential-providers';
import { AwsCredentialIdentityProvider } from '@aws-sdk/types';
import {
S3Client,
ListObjectsV2Command,
ListObjectsV2CommandOutput,
GetObjectCommand,
} from '@aws-sdk/client-s3';
import { AbortController } from '@aws-sdk/abort-controller';
import { ReadUrlResponseFactory } from './ReadUrlResponseFactory';
import { Readable } from 'stream';
const DEFAULT_REGION = 'us-east-1';
export const DEFAULT_REGION = 'us-east-1';
/**
* Path style URLs: https://s3.(region).amazonaws.com/(bucket)/(key)
@@ -105,14 +115,14 @@ export function parseUrl(
return {
path: pathname.substring(slashIndex + 1),
bucket: pathname.substring(0, slashIndex),
region: '',
region: DEFAULT_REGION,
};
}
return {
path: pathname,
bucket: host.substring(0, host.length - config.host.length - 1),
region: '',
region: DEFAULT_REGION,
};
}
@@ -126,16 +136,7 @@ export class AwsS3UrlReader implements UrlReader {
const integrations = ScmIntegrations.fromConfig(config);
return integrations.awsS3.list().map(integration => {
const credentials = AwsS3UrlReader.buildCredentials(integration);
const s3 = new aws.S3({
apiVersion: '2006-03-01',
credentials,
endpoint: integration.config.endpoint,
s3ForcePathStyle: integration.config.s3ForcePathStyle,
});
const reader = new AwsS3UrlReader(integration, {
s3,
const reader = new AwsS3UrlReader(config, integration, {
treeResponseFactory,
});
const predicate = (url: URL) =>
@@ -145,9 +146,9 @@ export class AwsS3UrlReader implements UrlReader {
};
constructor(
private readonly defaultConfig: Config,
private readonly integration: AwsS3Integration,
private readonly deps: {
s3: aws.S3;
treeResponseFactory: ReadTreeResponseFactory;
},
) {}
@@ -156,39 +157,95 @@ export class AwsS3UrlReader implements UrlReader {
* If accessKeyId and secretAccessKey are missing, the standard credentials provider chain will be used:
* https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/DefaultAWSCredentialsProviderChain.html
*/
private static buildCredentials(
integration?: AwsS3Integration,
): aws.Credentials | CredentialsOptions | undefined {
if (!integration) {
return undefined;
}
const accessKeyId = integration.config.accessKeyId;
const secretAccessKey = integration.config.secretAccessKey;
let explicitCredentials: aws.Credentials | undefined;
if (accessKeyId && secretAccessKey) {
explicitCredentials = new aws.Credentials({
private static buildStaticCredentials(
accessKeyId: string,
secretAccessKey: string,
): AwsCredentialIdentityProvider {
return async () => {
return Promise.resolve({
accessKeyId,
secretAccessKey,
});
};
}
private static async buildCredentials(
credsManager: AwsCredentialsManager,
region: string,
integration?: AwsS3Integration,
): Promise<AwsCredentialIdentityProvider> {
// Fall back to the default credential chain if neither account ID
// nor explicit credentials are provided
if (!integration) {
return (await credsManager.getCredentialProvider()).sdkCredentialProvider;
}
// Pull credentials from the techdocs config section (deprecated)
const accessKeyId = integration.config.accessKeyId;
const secretAccessKey = integration.config.secretAccessKey;
let explicitCredentials: AwsCredentialIdentityProvider;
if (accessKeyId && secretAccessKey) {
explicitCredentials = AwsS3UrlReader.buildStaticCredentials(
accessKeyId,
secretAccessKey,
);
} else {
explicitCredentials = (await credsManager.getCredentialProvider())
.sdkCredentialProvider;
}
const roleArn = integration.config.roleArn;
if (roleArn) {
return new aws.ChainableTemporaryCredentials({
return fromTemporaryCredentials({
masterCredentials: explicitCredentials,
params: {
RoleSessionName: 'backstage-aws-s3-url-reader',
RoleArn: roleArn,
ExternalId: integration.config.externalId,
},
clientConfig: { region },
});
}
return explicitCredentials;
}
async buildS3Client(
defaultConfig: Config,
region: string,
integration: AwsS3Integration,
): Promise<S3Client> {
const credsManager = DefaultAwsCredentialsManager.fromConfig(defaultConfig);
const credentials = await AwsS3UrlReader.buildCredentials(
credsManager,
region,
integration,
);
const s3 = new S3Client({
region: region,
credentials: credentials,
endpoint: integration.config.endpoint,
forcePathStyle: integration.config.s3ForcePathStyle,
});
return s3;
}
async retrieveS3ObjectData(stream: Readable): Promise<Readable> {
return new Promise((resolve, reject) => {
try {
const chunks: any[] = [];
stream.on('data', chunk => chunks.push(chunk));
stream.on('error', (e: Error) =>
reject(new ForwardedError('Unable to read stream', e)),
);
stream.on('end', () => resolve(Readable.from(Buffer.concat(chunks))));
} catch (e) {
throw new ForwardedError('Unable to parse the response data', e);
}
});
}
async read(url: string): Promise<Buffer> {
const response = await this.readUrl(url);
return response.buffer();
@@ -200,7 +257,12 @@ export class AwsS3UrlReader implements UrlReader {
): Promise<ReadUrlResponse> {
try {
const { path, bucket, region } = parseUrl(url, this.integration.config);
aws.config.update({ region: region });
const s3Client = await this.buildS3Client(
this.defaultConfig,
region,
this.integration,
);
const abortController = new AbortController();
let params;
if (options?.etag) {
@@ -215,44 +277,22 @@ export class AwsS3UrlReader implements UrlReader {
Key: path,
};
}
const request = this.deps.s3.getObject(params);
options?.signal?.addEventListener('abort', () => request.abort());
// Since we're consuming the read stream we need to consume headers and errors via events.
const etagPromise = new Promise<string | undefined>((resolve, reject) => {
request.on('httpHeaders', (status, headers) => {
if (status < 400) {
if (status === 200) {
resolve(headers.etag);
} else if (status !== 304 /* not modified */) {
reject(
new Error(
`S3 readUrl request received unexpected status '${status}' in response`,
),
);
}
}
});
request.on('error', error => reject(error));
request.on('complete', () =>
reject(
new Error('S3 readUrl request completed without receiving headers'),
),
);
options?.signal?.addEventListener('abort', () => abortController.abort());
const getObjectCommand = new GetObjectCommand(params);
const response = await s3Client.send(getObjectCommand, {
abortSignal: abortController.signal,
});
const stream = request.createReadStream();
stream.on('error', () => {
// The AWS SDK forwards request errors to the stream, so we need to
// ignore those errors here or the process will crash.
});
const s3ObjectData = await this.retrieveS3ObjectData(
response.Body as Readable,
);
const etag = response.ETag;
return ReadUrlResponseFactory.fromReadable(stream, {
etag: await etagPromise,
return ReadUrlResponseFactory.fromReadable(s3ObjectData, {
etag: etag,
});
} catch (e) {
if (e.statusCode === 304) {
if (e.$metadata && e.$metadata.httpStatusCode === 304) {
throw new NotModifiedError();
}
@@ -266,35 +306,49 @@ export class AwsS3UrlReader implements UrlReader {
): Promise<ReadTreeResponse> {
try {
const { path, bucket, region } = parseUrl(url, this.integration.config);
const allObjects: ObjectList = [];
const s3Client = await this.buildS3Client(
this.defaultConfig,
region,
this.integration,
);
const abortController = new AbortController();
const allObjects: String[] = [];
const responses = [];
let continuationToken: string | undefined;
let output: ListObjectsV2Output;
let output: ListObjectsV2CommandOutput;
do {
aws.config.update({ region: region });
const request = this.deps.s3.listObjectsV2({
const listObjectsV2Command = new ListObjectsV2Command({
Bucket: bucket,
ContinuationToken: continuationToken,
Prefix: path,
});
options?.signal?.addEventListener('abort', () => request.abort());
output = await request.promise();
options?.signal?.addEventListener('abort', () =>
abortController.abort(),
);
output = await s3Client.send(listObjectsV2Command, {
abortSignal: abortController.signal,
});
if (output.Contents) {
output.Contents.forEach(contents => {
allObjects.push(contents);
allObjects.push(contents.Key!);
});
}
continuationToken = output.NextContinuationToken;
} while (continuationToken);
for (let i = 0; i < allObjects.length; i++) {
const object = this.deps.s3.getObject({
const getObjectCommand = new GetObjectCommand({
Bucket: bucket,
Key: String(allObjects[i].Key),
Key: String(allObjects[i]),
});
const response = await s3Client.send(getObjectCommand);
const s3ObjectData = await this.retrieveS3ObjectData(
response.Body as Readable,
);
responses.push({
data: object.createReadStream(),
path: String(allObjects[i].Key),
data: s3ObjectData,
path: String(allObjects[i]),
});
}
+283 -44
View File
@@ -373,7 +373,7 @@ __metadata:
languageName: node
linkType: hard
"@aws-sdk/abort-controller@npm:3.272.0":
"@aws-sdk/abort-controller@npm:3.272.0, @aws-sdk/abort-controller@npm:^3.272.0":
version: 3.272.0
resolution: "@aws-sdk/abort-controller@npm:3.272.0"
dependencies:
@@ -402,21 +402,21 @@ __metadata:
languageName: node
linkType: hard
"@aws-sdk/client-cognito-identity@npm:3.276.0":
version: 3.276.0
resolution: "@aws-sdk/client-cognito-identity@npm:3.276.0"
"@aws-sdk/client-cognito-identity@npm:3.281.0":
version: 3.281.0
resolution: "@aws-sdk/client-cognito-identity@npm:3.281.0"
dependencies:
"@aws-crypto/sha256-browser": 3.0.0
"@aws-crypto/sha256-js": 3.0.0
"@aws-sdk/client-sts": 3.276.0
"@aws-sdk/client-sts": 3.281.0
"@aws-sdk/config-resolver": 3.272.0
"@aws-sdk/credential-provider-node": 3.272.0
"@aws-sdk/credential-provider-node": 3.281.0
"@aws-sdk/fetch-http-handler": 3.272.0
"@aws-sdk/hash-node": 3.272.0
"@aws-sdk/invalid-dependency": 3.272.0
"@aws-sdk/middleware-content-length": 3.272.0
"@aws-sdk/middleware-endpoint": 3.272.0
"@aws-sdk/middleware-host-header": 3.272.0
"@aws-sdk/middleware-host-header": 3.278.0
"@aws-sdk/middleware-logger": 3.272.0
"@aws-sdk/middleware-recursion-detection": 3.272.0
"@aws-sdk/middleware-retry": 3.272.0
@@ -427,34 +427,34 @@ __metadata:
"@aws-sdk/node-config-provider": 3.272.0
"@aws-sdk/node-http-handler": 3.272.0
"@aws-sdk/protocol-http": 3.272.0
"@aws-sdk/smithy-client": 3.272.0
"@aws-sdk/smithy-client": 3.279.0
"@aws-sdk/types": 3.272.0
"@aws-sdk/url-parser": 3.272.0
"@aws-sdk/util-base64": 3.208.0
"@aws-sdk/util-body-length-browser": 3.188.0
"@aws-sdk/util-body-length-node": 3.208.0
"@aws-sdk/util-defaults-mode-browser": 3.272.0
"@aws-sdk/util-defaults-mode-node": 3.272.0
"@aws-sdk/util-defaults-mode-browser": 3.279.0
"@aws-sdk/util-defaults-mode-node": 3.279.0
"@aws-sdk/util-endpoints": 3.272.0
"@aws-sdk/util-retry": 3.272.0
"@aws-sdk/util-user-agent-browser": 3.272.0
"@aws-sdk/util-user-agent-node": 3.272.0
"@aws-sdk/util-utf8": 3.254.0
tslib: ^2.3.1
checksum: ff79c1c727d956e03510307b001c24534d522b327871b2b0a1d39120e6d6717e17d7b9c2b7a6d28c3e5c3f41cd8ff28e5150ddd1fda9bff0c239fdfef0a78e00
checksum: 13c350badfdd7fc1df05687314ade61b407a7094d082ade35ff67c4ac870f4fb5bfda902e21c9dedf13898dbd76e74fc03707b632359fd2619a3f709bee5ac8c
languageName: node
linkType: hard
"@aws-sdk/client-s3@npm:^3.208.0":
version: 3.276.0
resolution: "@aws-sdk/client-s3@npm:3.276.0"
"@aws-sdk/client-s3@npm:^3.208.0, @aws-sdk/client-s3@npm:^3.276.0":
version: 3.281.0
resolution: "@aws-sdk/client-s3@npm:3.281.0"
dependencies:
"@aws-crypto/sha1-browser": 3.0.0
"@aws-crypto/sha256-browser": 3.0.0
"@aws-crypto/sha256-js": 3.0.0
"@aws-sdk/client-sts": 3.276.0
"@aws-sdk/client-sts": 3.281.0
"@aws-sdk/config-resolver": 3.272.0
"@aws-sdk/credential-provider-node": 3.272.0
"@aws-sdk/credential-provider-node": 3.281.0
"@aws-sdk/eventstream-serde-browser": 3.272.0
"@aws-sdk/eventstream-serde-config-resolver": 3.272.0
"@aws-sdk/eventstream-serde-node": 3.272.0
@@ -469,7 +469,7 @@ __metadata:
"@aws-sdk/middleware-endpoint": 3.272.0
"@aws-sdk/middleware-expect-continue": 3.272.0
"@aws-sdk/middleware-flexible-checksums": 3.272.0
"@aws-sdk/middleware-host-header": 3.272.0
"@aws-sdk/middleware-host-header": 3.278.0
"@aws-sdk/middleware-location-constraint": 3.272.0
"@aws-sdk/middleware-logger": 3.272.0
"@aws-sdk/middleware-recursion-detection": 3.272.0
@@ -484,14 +484,14 @@ __metadata:
"@aws-sdk/node-http-handler": 3.272.0
"@aws-sdk/protocol-http": 3.272.0
"@aws-sdk/signature-v4-multi-region": 3.272.0
"@aws-sdk/smithy-client": 3.272.0
"@aws-sdk/smithy-client": 3.279.0
"@aws-sdk/types": 3.272.0
"@aws-sdk/url-parser": 3.272.0
"@aws-sdk/util-base64": 3.208.0
"@aws-sdk/util-body-length-browser": 3.188.0
"@aws-sdk/util-body-length-node": 3.208.0
"@aws-sdk/util-defaults-mode-browser": 3.272.0
"@aws-sdk/util-defaults-mode-node": 3.272.0
"@aws-sdk/util-defaults-mode-browser": 3.279.0
"@aws-sdk/util-defaults-mode-node": 3.279.0
"@aws-sdk/util-endpoints": 3.272.0
"@aws-sdk/util-retry": 3.272.0
"@aws-sdk/util-stream-browser": 3.272.0
@@ -503,7 +503,7 @@ __metadata:
"@aws-sdk/xml-builder": 3.201.0
fast-xml-parser: 4.1.2
tslib: ^2.3.1
checksum: f7f475b92c0cff800536fb910bb6ffefcee6e650208f1791ea64c95bcbb6c63ef7a55e3f72af44e2e730a53865857ac4b974f00cb7da1e369d742cc95e33f02a
checksum: 30447fefd4fd1c98388457aab53cdb6db26a2610389912f5a389136db7a5992d358adf5116c8102eb82262b8c78864902c78437390ec7ffe7ef076dd78ab3b9a
languageName: node
linkType: hard
@@ -593,6 +593,46 @@ __metadata:
languageName: node
linkType: hard
"@aws-sdk/client-sso-oidc@npm:3.281.0":
version: 3.281.0
resolution: "@aws-sdk/client-sso-oidc@npm:3.281.0"
dependencies:
"@aws-crypto/sha256-browser": 3.0.0
"@aws-crypto/sha256-js": 3.0.0
"@aws-sdk/config-resolver": 3.272.0
"@aws-sdk/fetch-http-handler": 3.272.0
"@aws-sdk/hash-node": 3.272.0
"@aws-sdk/invalid-dependency": 3.272.0
"@aws-sdk/middleware-content-length": 3.272.0
"@aws-sdk/middleware-endpoint": 3.272.0
"@aws-sdk/middleware-host-header": 3.278.0
"@aws-sdk/middleware-logger": 3.272.0
"@aws-sdk/middleware-recursion-detection": 3.272.0
"@aws-sdk/middleware-retry": 3.272.0
"@aws-sdk/middleware-serde": 3.272.0
"@aws-sdk/middleware-stack": 3.272.0
"@aws-sdk/middleware-user-agent": 3.272.0
"@aws-sdk/node-config-provider": 3.272.0
"@aws-sdk/node-http-handler": 3.272.0
"@aws-sdk/protocol-http": 3.272.0
"@aws-sdk/smithy-client": 3.279.0
"@aws-sdk/types": 3.272.0
"@aws-sdk/url-parser": 3.272.0
"@aws-sdk/util-base64": 3.208.0
"@aws-sdk/util-body-length-browser": 3.188.0
"@aws-sdk/util-body-length-node": 3.208.0
"@aws-sdk/util-defaults-mode-browser": 3.279.0
"@aws-sdk/util-defaults-mode-node": 3.279.0
"@aws-sdk/util-endpoints": 3.272.0
"@aws-sdk/util-retry": 3.272.0
"@aws-sdk/util-user-agent-browser": 3.272.0
"@aws-sdk/util-user-agent-node": 3.272.0
"@aws-sdk/util-utf8": 3.254.0
tslib: ^2.3.1
checksum: ce0515dbdf02f82f4f301e31e9f63adfa8660e776e665f41cd59d9f1a9a4ee373c1fa489d3f2286f0da6ddb55905562d34d799d05eef8ab2f04d9a4133e3b228
languageName: node
linkType: hard
"@aws-sdk/client-sso@npm:3.272.0":
version: 3.272.0
resolution: "@aws-sdk/client-sso@npm:3.272.0"
@@ -633,7 +673,47 @@ __metadata:
languageName: node
linkType: hard
"@aws-sdk/client-sts@npm:3.276.0, @aws-sdk/client-sts@npm:^3.208.0":
"@aws-sdk/client-sso@npm:3.281.0":
version: 3.281.0
resolution: "@aws-sdk/client-sso@npm:3.281.0"
dependencies:
"@aws-crypto/sha256-browser": 3.0.0
"@aws-crypto/sha256-js": 3.0.0
"@aws-sdk/config-resolver": 3.272.0
"@aws-sdk/fetch-http-handler": 3.272.0
"@aws-sdk/hash-node": 3.272.0
"@aws-sdk/invalid-dependency": 3.272.0
"@aws-sdk/middleware-content-length": 3.272.0
"@aws-sdk/middleware-endpoint": 3.272.0
"@aws-sdk/middleware-host-header": 3.278.0
"@aws-sdk/middleware-logger": 3.272.0
"@aws-sdk/middleware-recursion-detection": 3.272.0
"@aws-sdk/middleware-retry": 3.272.0
"@aws-sdk/middleware-serde": 3.272.0
"@aws-sdk/middleware-stack": 3.272.0
"@aws-sdk/middleware-user-agent": 3.272.0
"@aws-sdk/node-config-provider": 3.272.0
"@aws-sdk/node-http-handler": 3.272.0
"@aws-sdk/protocol-http": 3.272.0
"@aws-sdk/smithy-client": 3.279.0
"@aws-sdk/types": 3.272.0
"@aws-sdk/url-parser": 3.272.0
"@aws-sdk/util-base64": 3.208.0
"@aws-sdk/util-body-length-browser": 3.188.0
"@aws-sdk/util-body-length-node": 3.208.0
"@aws-sdk/util-defaults-mode-browser": 3.279.0
"@aws-sdk/util-defaults-mode-node": 3.279.0
"@aws-sdk/util-endpoints": 3.272.0
"@aws-sdk/util-retry": 3.272.0
"@aws-sdk/util-user-agent-browser": 3.272.0
"@aws-sdk/util-user-agent-node": 3.272.0
"@aws-sdk/util-utf8": 3.254.0
tslib: ^2.3.1
checksum: 6607a853af57c435ce09c81876b1a89d7658bd60a9468f8c888273364a50d35c431e823302a7f6e5366ce6b947028a2ce6451171f5dfd869443e2569f2bb9c6d
languageName: node
linkType: hard
"@aws-sdk/client-sts@npm:3.276.0":
version: 3.276.0
resolution: "@aws-sdk/client-sts@npm:3.276.0"
dependencies:
@@ -677,6 +757,50 @@ __metadata:
languageName: node
linkType: hard
"@aws-sdk/client-sts@npm:3.281.0, @aws-sdk/client-sts@npm:^3.208.0":
version: 3.281.0
resolution: "@aws-sdk/client-sts@npm:3.281.0"
dependencies:
"@aws-crypto/sha256-browser": 3.0.0
"@aws-crypto/sha256-js": 3.0.0
"@aws-sdk/config-resolver": 3.272.0
"@aws-sdk/credential-provider-node": 3.281.0
"@aws-sdk/fetch-http-handler": 3.272.0
"@aws-sdk/hash-node": 3.272.0
"@aws-sdk/invalid-dependency": 3.272.0
"@aws-sdk/middleware-content-length": 3.272.0
"@aws-sdk/middleware-endpoint": 3.272.0
"@aws-sdk/middleware-host-header": 3.278.0
"@aws-sdk/middleware-logger": 3.272.0
"@aws-sdk/middleware-recursion-detection": 3.272.0
"@aws-sdk/middleware-retry": 3.272.0
"@aws-sdk/middleware-sdk-sts": 3.272.0
"@aws-sdk/middleware-serde": 3.272.0
"@aws-sdk/middleware-signing": 3.272.0
"@aws-sdk/middleware-stack": 3.272.0
"@aws-sdk/middleware-user-agent": 3.272.0
"@aws-sdk/node-config-provider": 3.272.0
"@aws-sdk/node-http-handler": 3.272.0
"@aws-sdk/protocol-http": 3.272.0
"@aws-sdk/smithy-client": 3.279.0
"@aws-sdk/types": 3.272.0
"@aws-sdk/url-parser": 3.272.0
"@aws-sdk/util-base64": 3.208.0
"@aws-sdk/util-body-length-browser": 3.188.0
"@aws-sdk/util-body-length-node": 3.208.0
"@aws-sdk/util-defaults-mode-browser": 3.279.0
"@aws-sdk/util-defaults-mode-node": 3.279.0
"@aws-sdk/util-endpoints": 3.272.0
"@aws-sdk/util-retry": 3.272.0
"@aws-sdk/util-user-agent-browser": 3.272.0
"@aws-sdk/util-user-agent-node": 3.272.0
"@aws-sdk/util-utf8": 3.254.0
fast-xml-parser: 4.1.2
tslib: ^2.3.1
checksum: c88b660279ca6fe56cb8ac7bb245a417b9ccd1a973b7e7c2b511b254f2eace11c92826c80f84423988d47796f1fb18b09363f867d9ffce436ae81f10695e31e5
languageName: node
linkType: hard
"@aws-sdk/config-resolver@npm:3.272.0":
version: 3.272.0
resolution: "@aws-sdk/config-resolver@npm:3.272.0"
@@ -690,15 +814,15 @@ __metadata:
languageName: node
linkType: hard
"@aws-sdk/credential-provider-cognito-identity@npm:3.276.0":
version: 3.276.0
resolution: "@aws-sdk/credential-provider-cognito-identity@npm:3.276.0"
"@aws-sdk/credential-provider-cognito-identity@npm:3.281.0":
version: 3.281.0
resolution: "@aws-sdk/credential-provider-cognito-identity@npm:3.281.0"
dependencies:
"@aws-sdk/client-cognito-identity": 3.276.0
"@aws-sdk/client-cognito-identity": 3.281.0
"@aws-sdk/property-provider": 3.272.0
"@aws-sdk/types": 3.272.0
tslib: ^2.3.1
checksum: 2d255475f08beeccd000745b2f2c46553559fd6fe15c0ea9960956655535fb927df9ec3431cf743b80f9a460d033ede7e1c47e91aff44956559a70c5f43f7bab
checksum: 35a0c2193aafd329e0ecbb66bdb5630d707a3cb2ad75969a847a72306518c8eb08cf46f6aebd461ba824fe444bdf58384cc45f3714d024d3c636913f1656932d
languageName: node
linkType: hard
@@ -743,7 +867,24 @@ __metadata:
languageName: node
linkType: hard
"@aws-sdk/credential-provider-node@npm:3.272.0, @aws-sdk/credential-provider-node@npm:^3.208.0":
"@aws-sdk/credential-provider-ini@npm:3.281.0":
version: 3.281.0
resolution: "@aws-sdk/credential-provider-ini@npm:3.281.0"
dependencies:
"@aws-sdk/credential-provider-env": 3.272.0
"@aws-sdk/credential-provider-imds": 3.272.0
"@aws-sdk/credential-provider-process": 3.272.0
"@aws-sdk/credential-provider-sso": 3.281.0
"@aws-sdk/credential-provider-web-identity": 3.272.0
"@aws-sdk/property-provider": 3.272.0
"@aws-sdk/shared-ini-file-loader": 3.272.0
"@aws-sdk/types": 3.272.0
tslib: ^2.3.1
checksum: 3be8151f2dd7a09b0f3f887e83e43eaf1bc22a7d25e5c91397dbc756ef3df53667001ef39d276e545fad7d1b9680a050fb0aad6ac65c1ee7be593b9c2d353d39
languageName: node
linkType: hard
"@aws-sdk/credential-provider-node@npm:3.272.0":
version: 3.272.0
resolution: "@aws-sdk/credential-provider-node@npm:3.272.0"
dependencies:
@@ -761,6 +902,24 @@ __metadata:
languageName: node
linkType: hard
"@aws-sdk/credential-provider-node@npm:3.281.0, @aws-sdk/credential-provider-node@npm:^3.208.0":
version: 3.281.0
resolution: "@aws-sdk/credential-provider-node@npm:3.281.0"
dependencies:
"@aws-sdk/credential-provider-env": 3.272.0
"@aws-sdk/credential-provider-imds": 3.272.0
"@aws-sdk/credential-provider-ini": 3.281.0
"@aws-sdk/credential-provider-process": 3.272.0
"@aws-sdk/credential-provider-sso": 3.281.0
"@aws-sdk/credential-provider-web-identity": 3.272.0
"@aws-sdk/property-provider": 3.272.0
"@aws-sdk/shared-ini-file-loader": 3.272.0
"@aws-sdk/types": 3.272.0
tslib: ^2.3.1
checksum: 583eaba8fac99c7c05ee35f72946b4df2da4ddc620ae8d70a1f1211a0e1ec032616971649cbd2a825d0208b8f3361a61d86a68a56a94eb4075f931988a659b6e
languageName: node
linkType: hard
"@aws-sdk/credential-provider-process@npm:3.272.0":
version: 3.272.0
resolution: "@aws-sdk/credential-provider-process@npm:3.272.0"
@@ -787,6 +946,20 @@ __metadata:
languageName: node
linkType: hard
"@aws-sdk/credential-provider-sso@npm:3.281.0":
version: 3.281.0
resolution: "@aws-sdk/credential-provider-sso@npm:3.281.0"
dependencies:
"@aws-sdk/client-sso": 3.281.0
"@aws-sdk/property-provider": 3.272.0
"@aws-sdk/shared-ini-file-loader": 3.272.0
"@aws-sdk/token-providers": 3.281.0
"@aws-sdk/types": 3.272.0
tslib: ^2.3.1
checksum: e1aa53df55352047993c2a63dece7e9f7eaab5358237ae666d6ca9f929fc650cf5a20d140d90d8fb10fdba7a9e6164a709a45ab6665b1ab862a21676d3b3b3dc
languageName: node
linkType: hard
"@aws-sdk/credential-provider-web-identity@npm:3.272.0":
version: 3.272.0
resolution: "@aws-sdk/credential-provider-web-identity@npm:3.272.0"
@@ -798,26 +971,26 @@ __metadata:
languageName: node
linkType: hard
"@aws-sdk/credential-providers@npm:^3.208.0":
version: 3.276.0
resolution: "@aws-sdk/credential-providers@npm:3.276.0"
"@aws-sdk/credential-providers@npm:^3.208.0, @aws-sdk/credential-providers@npm:^3.276.0":
version: 3.281.0
resolution: "@aws-sdk/credential-providers@npm:3.281.0"
dependencies:
"@aws-sdk/client-cognito-identity": 3.276.0
"@aws-sdk/client-sso": 3.272.0
"@aws-sdk/client-sts": 3.276.0
"@aws-sdk/credential-provider-cognito-identity": 3.276.0
"@aws-sdk/client-cognito-identity": 3.281.0
"@aws-sdk/client-sso": 3.281.0
"@aws-sdk/client-sts": 3.281.0
"@aws-sdk/credential-provider-cognito-identity": 3.281.0
"@aws-sdk/credential-provider-env": 3.272.0
"@aws-sdk/credential-provider-imds": 3.272.0
"@aws-sdk/credential-provider-ini": 3.272.0
"@aws-sdk/credential-provider-node": 3.272.0
"@aws-sdk/credential-provider-ini": 3.281.0
"@aws-sdk/credential-provider-node": 3.281.0
"@aws-sdk/credential-provider-process": 3.272.0
"@aws-sdk/credential-provider-sso": 3.272.0
"@aws-sdk/credential-provider-sso": 3.281.0
"@aws-sdk/credential-provider-web-identity": 3.272.0
"@aws-sdk/property-provider": 3.272.0
"@aws-sdk/shared-ini-file-loader": 3.272.0
"@aws-sdk/types": 3.272.0
tslib: ^2.3.1
checksum: 825fb0feda57ef98cc11ab3febc2a337161193dfa24bcc31ad2b47ecb4af564b3b5a5a0d9c17fd1a3ec118321d21fc515948980ba50c323e21ed79905c13dfe4
checksum: 48e25c96eafd9e5b8144144d4e87586f9d0be16b1d72fb006ae14b9396b43a16ec595a0d841011af41bcb55f09ed799fb7423346b7737e7a34fca56a050c71e1
languageName: node
linkType: hard
@@ -1061,6 +1234,17 @@ __metadata:
languageName: node
linkType: hard
"@aws-sdk/middleware-host-header@npm:3.278.0":
version: 3.278.0
resolution: "@aws-sdk/middleware-host-header@npm:3.278.0"
dependencies:
"@aws-sdk/protocol-http": 3.272.0
"@aws-sdk/types": 3.272.0
tslib: ^2.3.1
checksum: 5b9762f80a8b6041cbe62680e34ddfb0f9d6f687f2f39aa117b1f0a692f594312371cf109c090fe93ccf8084cee924cf3dc134c1d2c929012df4593edaf492bf
languageName: node
linkType: hard
"@aws-sdk/middleware-location-constraint@npm:3.272.0":
version: 3.272.0
resolution: "@aws-sdk/middleware-location-constraint@npm:3.272.0"
@@ -1347,6 +1531,17 @@ __metadata:
languageName: node
linkType: hard
"@aws-sdk/smithy-client@npm:3.279.0":
version: 3.279.0
resolution: "@aws-sdk/smithy-client@npm:3.279.0"
dependencies:
"@aws-sdk/middleware-stack": 3.272.0
"@aws-sdk/types": 3.272.0
tslib: ^2.3.1
checksum: 43d933b714ba7249d7f9f007e6e107d88d34e76db2cf934c43f38b6039699da450227f25bf559a3a6f12f9f62c4dec6dd5c4dda2205e6889e7d530521b879d61
languageName: node
linkType: hard
"@aws-sdk/token-providers@npm:3.272.0":
version: 3.272.0
resolution: "@aws-sdk/token-providers@npm:3.272.0"
@@ -1360,6 +1555,19 @@ __metadata:
languageName: node
linkType: hard
"@aws-sdk/token-providers@npm:3.281.0":
version: 3.281.0
resolution: "@aws-sdk/token-providers@npm:3.281.0"
dependencies:
"@aws-sdk/client-sso-oidc": 3.281.0
"@aws-sdk/property-provider": 3.272.0
"@aws-sdk/shared-ini-file-loader": 3.272.0
"@aws-sdk/types": 3.272.0
tslib: ^2.3.1
checksum: 15b7ba37cf169662f2ddd85d90b6fb5d077593e6316914b3de381b4c68a613664dc7688848512feb1aa82018345b2ce8d0a33f55878e96d461c2c87486825728
languageName: node
linkType: hard
"@aws-sdk/types@npm:3.208.0":
version: 3.208.0
resolution: "@aws-sdk/types@npm:3.208.0"
@@ -1367,7 +1575,7 @@ __metadata:
languageName: node
linkType: hard
"@aws-sdk/types@npm:3.272.0, @aws-sdk/types@npm:^3.208.0, @aws-sdk/types@npm:^3.222.0":
"@aws-sdk/types@npm:3.272.0, @aws-sdk/types@npm:^3.208.0, @aws-sdk/types@npm:^3.222.0, @aws-sdk/types@npm:^3.272.0":
version: 3.272.0
resolution: "@aws-sdk/types@npm:3.272.0"
dependencies:
@@ -1455,6 +1663,18 @@ __metadata:
languageName: node
linkType: hard
"@aws-sdk/util-defaults-mode-browser@npm:3.279.0":
version: 3.279.0
resolution: "@aws-sdk/util-defaults-mode-browser@npm:3.279.0"
dependencies:
"@aws-sdk/property-provider": 3.272.0
"@aws-sdk/types": 3.272.0
bowser: ^2.11.0
tslib: ^2.3.1
checksum: 727700ae9c741a24cb8d30991344d778ca5e9ec3ad30364a63f22af8889f03a5fedecad87c76b7022118ab2c6a3dfc48abd530502b7e1f0926bf467081189645
languageName: node
linkType: hard
"@aws-sdk/util-defaults-mode-node@npm:3.272.0":
version: 3.272.0
resolution: "@aws-sdk/util-defaults-mode-node@npm:3.272.0"
@@ -1469,6 +1689,20 @@ __metadata:
languageName: node
linkType: hard
"@aws-sdk/util-defaults-mode-node@npm:3.279.0":
version: 3.279.0
resolution: "@aws-sdk/util-defaults-mode-node@npm:3.279.0"
dependencies:
"@aws-sdk/config-resolver": 3.272.0
"@aws-sdk/credential-provider-imds": 3.272.0
"@aws-sdk/node-config-provider": 3.272.0
"@aws-sdk/property-provider": 3.272.0
"@aws-sdk/types": 3.272.0
tslib: ^2.3.1
checksum: 8b1e89a9ef092c6a25d354823ed3e172a2f6415389f7f66034a8571321b8100b909435a238097f016dceb58a4894ebebd8a52e33698f069f8a9d3c5bb6bd633a
languageName: node
linkType: hard
"@aws-sdk/util-endpoints@npm:3.272.0":
version: 3.272.0
resolution: "@aws-sdk/util-endpoints@npm:3.272.0"
@@ -1530,7 +1764,7 @@ __metadata:
languageName: node
linkType: hard
"@aws-sdk/util-stream-node@npm:3.272.0":
"@aws-sdk/util-stream-node@npm:3.272.0, @aws-sdk/util-stream-node@npm:^3.272.0":
version: 3.272.0
resolution: "@aws-sdk/util-stream-node@npm:3.272.0"
dependencies:
@@ -3422,6 +3656,11 @@ __metadata:
version: 0.0.0-use.local
resolution: "@backstage/backend-common@workspace:packages/backend-common"
dependencies:
"@aws-sdk/abort-controller": ^3.272.0
"@aws-sdk/client-s3": ^3.276.0
"@aws-sdk/credential-providers": ^3.276.0
"@aws-sdk/types": ^3.272.0
"@aws-sdk/util-stream-node": ^3.272.0
"@backstage/backend-app-api": "workspace:^"
"@backstage/backend-dev-utils": "workspace:^"
"@backstage/backend-plugin-api": "workspace:^"
@@ -3432,6 +3671,7 @@ __metadata:
"@backstage/config-loader": "workspace:^"
"@backstage/errors": "workspace:^"
"@backstage/integration": "workspace:^"
"@backstage/integration-aws-node": "workspace:^"
"@backstage/types": "workspace:^"
"@google-cloud/storage": ^6.0.0
"@keyv/memcache": ^1.3.5
@@ -3460,7 +3700,7 @@ __metadata:
"@types/webpack-env": ^1.15.2
"@types/yauzl": ^2.10.0
archiver: ^5.0.2
aws-sdk: ^2.840.0
aws-sdk-client-mock: ^2.0.1
aws-sdk-mock: ^5.2.1
base64-stream: ^1.0.0
better-sqlite3: ^8.0.0
@@ -3473,7 +3713,6 @@ __metadata:
fs-extra: 10.1.0
git-url-parse: ^13.0.0
helmet: ^6.0.0
http-errors: ^2.0.0
isomorphic-git: ^1.8.0
jose: ^4.6.0
keyv: ^4.5.2
@@ -17509,7 +17748,7 @@ __metadata:
languageName: node
linkType: hard
"aws-sdk-client-mock@npm:^2.0.0":
"aws-sdk-client-mock@npm:^2.0.0, aws-sdk-client-mock@npm:^2.0.1":
version: 2.0.1
resolution: "aws-sdk-client-mock@npm:2.0.1"
dependencies: