chore: unify credentials shape for v5

This commit is contained in:
Christian Capeans 2024-01-18 14:07:56 +01:00
parent 01dfca22b2
commit 44dbe85dfd
3 changed files with 125 additions and 49 deletions

View File

@ -16,36 +16,6 @@ const defaultOptions = {
describe('Utils', () => {
describe('Extract credentials for V4 different aws provider configurations', () => {
test('[Legacy] Credentials directly in the options', () => {
const options: InitOptions = {
accessKeyId,
secretAccessKey,
...defaultOptions,
};
const credentials = extractCredentials(options);
expect(credentials).toEqual({
accessKeyId,
secretAccessKey,
});
});
test('[Legacy] credentials directly in s3Options', () => {
const options: InitOptions = {
s3Options: {
accessKeyId,
secretAccessKey,
...defaultOptions,
},
};
const credentials = extractCredentials(options);
expect(credentials).toEqual({
accessKeyId,
secretAccessKey,
});
});
test('Credentials in credentials object inside s3Options', () => {
const options: InitOptions = {
s3Options: {

View File

@ -88,26 +88,7 @@ function getBucketFromAwsUrl(fileUrl: string): BucketInfo {
return { bucket: prefix.substring(0, prefix.length - 1) };
}
// TODO Remove this in V5 since we will only support the new config structure
export const extractCredentials = (options: InitOptions): AwsCredentialIdentity | null => {
// legacy
if (options.accessKeyId && options.secretAccessKey) {
return {
accessKeyId: options.accessKeyId,
secretAccessKey: options.secretAccessKey,
};
}
// Legacy
if (options.s3Options?.accessKeyId && options.s3Options.secretAccessKey) {
process.emitWarning(
'Credentials passed directly to s3Options is deprecated and will be removed in a future release. Please wrap them inside a credentials object.'
);
return {
accessKeyId: options.s3Options.accessKeyId,
secretAccessKey: options.s3Options.secretAccessKey,
};
}
// V5
if (options.s3Options?.credentials) {
return {
accessKeyId: options.s3Options.credentials.accessKeyId,

View File

@ -0,0 +1,125 @@
import { Transform, ASTPath, Property } from 'jscodeshift';
import path from 'node:path';
/**
* This codemod only affects users that are using the `aws-s3` provider.
* It will wrap the `accessKeyId` and `secretAccessKey` properties inside a `credentials` object.
*/
const transform: Transform = (file, api) => {
// Check if the current file is 'config/plugins.js'
const cwd = process.cwd();
const pluginsPath = path.join(cwd, 'config/plugins.js');
if (file.path !== pluginsPath) {
return file.source;
}
const { j } = api;
const root = j(file.source);
root.find(j.ArrowFunctionExpression).forEach((arrowFunctionPath: ASTPath<any>) => {
const body = arrowFunctionPath.node.body;
if (body.type === 'ObjectExpression') {
const uploadProperty = body.properties.find(
(prop: Property) => prop.key.type === 'Identifier' && prop.key.name === 'upload'
);
if (uploadProperty && uploadProperty.value.type === 'ObjectExpression') {
const configProperty = uploadProperty.value.properties.find(
(prop: Property) => prop.key.type === 'Identifier' && prop.key.name === 'config'
);
if (configProperty && configProperty.value.type === 'ObjectExpression') {
const providerProperty = configProperty.value.properties.find(
(prop: Property) =>
prop.key.type === 'Identifier' &&
prop.key.name === 'provider' &&
prop.value.type === 'Literal' &&
prop.value.value === 'aws-s3'
);
if (providerProperty) {
const providerOptions = configProperty.value.properties.find(
(prop: Property) =>
prop.key.type === 'Identifier' && prop.key.name === 'providerOptions'
);
if (providerOptions && providerOptions.value.type === 'ObjectExpression') {
let accessKeyId: Property | undefined;
let secretAccessKey: Property | undefined;
// Check for accessKeyId and secretAccessKey directly under providerOptions
const directAccessKeyId = providerOptions.value.properties.find(
(prop: Property) =>
prop.key.type === 'Identifier' && prop.key.name === 'accessKeyId'
);
const directSecretAccessKey = providerOptions.value.properties.find(
(prop: Property) =>
prop.key.type === 'Identifier' && prop.key.name === 'secretAccessKey'
);
let s3Options = providerOptions.value.properties.find(
(prop: Property) => prop.key.type === 'Identifier' && prop.key.name === 's3Options'
);
if (!s3Options) {
// Create s3Options if it doesn't exist
s3Options = j.property('init', j.identifier('s3Options'), j.objectExpression([]));
providerOptions.value.properties.push(s3Options);
}
if (directAccessKeyId && directSecretAccessKey) {
accessKeyId = directAccessKeyId;
secretAccessKey = directSecretAccessKey;
// Remove these properties from providerOptions
providerOptions.value.properties = providerOptions.value.properties.filter(
(prop: Property) =>
prop.key.type === 'Identifier' &&
prop.key.name !== 'accessKeyId' &&
prop.key.name !== 'secretAccessKey'
);
} else if (s3Options.value.type === 'ObjectExpression') {
// Look inside s3Options
accessKeyId = s3Options.value.properties.find(
(prop: Property) =>
prop.key.type === 'Identifier' && prop.key.name === 'accessKeyId'
);
secretAccessKey = s3Options.value.properties.find(
(prop: Property) =>
prop.key.type === 'Identifier' && prop.key.name === 'secretAccessKey'
);
}
if (accessKeyId && secretAccessKey && s3Options.value.type === 'ObjectExpression') {
// Create the credentials object
const credentials = j.objectExpression([
j.property('init', j.identifier('accessKeyId'), accessKeyId.value),
j.property('init', j.identifier('secretAccessKey'), secretAccessKey.value),
]);
// Remove the old properties from s3Options
s3Options.value.properties = s3Options.value.properties.filter(
(prop: Property) =>
prop.key.type === 'Identifier' &&
prop.key.name !== 'accessKeyId' &&
prop.key.name !== 'secretAccessKey'
);
// Add the new credentials object to s3Options
s3Options.value.properties.push(
j.property('init', j.identifier('credentials'), credentials)
);
}
}
}
}
}
}
});
return root.toSource();
};
export default transform;