Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(storage): update s3 control model #13705

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ const listCallerAccessGrantsHappyCaseSingleGrant: ApiFunctionalTestCase<
<ListCallerAccessGrantsResult>
<NextToken>${MOCK_NEXT_TOKEN}</NextToken>
<CallerAccessGrantsList>
<AccessGrantsInstance>
<AccessGrant>
<ApplicationArn>${MOCK_APP_ARN}</ApplicationArn>
<GrantScope>${MOCK_GRANT_SCOPE}</GrantScope>
<Permission>${MOCK_PERMISSION}</Permission>
</AccessGrantsInstance>
</AccessGrant>
</CallerAccessGrantsList>
</ListCallerAccessGrantsResult>
`,
Expand Down Expand Up @@ -103,16 +103,16 @@ const listCallerAccessGrantsHappyCaseMultipleGrants: ApiFunctionalTestCase<
<ListCallerAccessGrantsResult>
<NextToken>${MOCK_NEXT_TOKEN}</NextToken>
<CallerAccessGrantsList>
<AccessGrantsInstance>
<AccessGrant>
<ApplicationArn>${MOCK_APP_ARN}</ApplicationArn>
<GrantScope>${MOCK_GRANT_SCOPE}</GrantScope>
<Permission>${MOCK_PERMISSION}</Permission>
</AccessGrantsInstance>
<AccessGrantsInstance>
</AccessGrant>
<AccessGrant>
<ApplicationArn>${MOCK_APP_ARN}</ApplicationArn>
<GrantScope>${MOCK_GRANT_SCOPE}</GrantScope>
<Permission>${MOCK_PERMISSION}</Permission>
</AccessGrantsInstance>
</AccessGrant>
</CallerAccessGrantsList>
</ListCallerAccessGrantsResult>
`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
parseXmlError,
s3TransferHandler,
} from '../utils';
import { createStringEnumDeserializer } from '../utils/deserializeHelpers';

import type {
ListCallerAccessGrantsCommandInput,
Expand Down Expand Up @@ -71,10 +72,7 @@ const listCallerAccessGrantsDeserializer = async (
CallerAccessGrantsList: [
'CallerAccessGrantsList',
value =>
emptyArrayGuard(
value.AccessGrantsInstance,
deserializeAccessGrantsList,
),
emptyArrayGuard(value.AccessGrant, deserializeAccessGrantsList),
],
NextToken: 'NextToken',
});
Expand All @@ -93,7 +91,13 @@ const deserializeCallerAccessGrant = (output: any) =>
map(output, {
ApplicationArn: 'ApplicationArn',
GrantScope: 'GrantScope',
Permission: 'Permission',
Permission: [
'Permission',
createStringEnumDeserializer(
['READ', 'READWRITE', 'WRITE'] as const,
'Permission',
),
],
});

export const listCallerAccessGrants = composeServiceApi(
Expand Down
157 changes: 80 additions & 77 deletions packages/storage/src/providers/s3/utils/client/s3control/types.ts
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The order of type change is caused by different approach of generating the types. Previously it was manully picked, this is generated by dts-bundler. Here is not type change in this file.

Original file line number Diff line number Diff line change
Expand Up @@ -26,80 +26,6 @@ declare const S3PrefixType: {
readonly Object: 'Object';
};

/**
* @public
*/
export type Permission = (typeof Permission)[keyof typeof Permission];

/**
* @public
*/
export type Privilege = (typeof Privilege)[keyof typeof Privilege];

/**
* @public
*/
export type S3PrefixType = (typeof S3PrefixType)[keyof typeof S3PrefixType];

/**
* @public
*
* The input for {@link ListCallerAccessGrantsCommand}.
*/
export type ListCallerAccessGrantsCommandInput = ListCallerAccessGrantsRequest;

/**
* @public
*
* The output of {@link ListCallerAccessGrantsCommand}.
*/
export interface ListCallerAccessGrantsCommandOutput
extends ListCallerAccessGrantsResult,
__MetadataBearer {}

/**
* @public
*/
export interface ListCallerAccessGrantsRequest {
AccountId?: string;
GrantScope?: string;
NextToken?: string;
MaxResults?: number;
}

/**
* @public
*/
export interface ListCallerAccessGrantsEntry {
Permission?: Permission | string;
GrantScope?: string;
ApplicationArn?: string;
}

/**
* @public
*/
export interface ListCallerAccessGrantsResult {
NextToken?: string;
CallerAccessGrantsList?: ListCallerAccessGrantsEntry[];
}

/**
* @public
*
* The input for {@link GetDataAccessCommand}.
*/
export type GetDataAccessCommandInput = GetDataAccessRequest;

/**
* @public
*
* The output of {@link GetDataAccessCommand}.
*/
export interface GetDataAccessCommandOutput
extends GetDataAccessResult,
__MetadataBearer {}

/**
* <p>The Amazon Web Services Security Token Service temporary credential that S3 Access Grants vends to grantees and client applications. </p>
* @public
Expand All @@ -110,26 +36,50 @@ export interface Credentials {
* @public
*/
AccessKeyId?: string;

/**
* <p>The secret access key of the Amazon Web Services STS temporary credential that S3 Access Grants vends to grantees and client applications. </p>
* @public
*/
SecretAccessKey?: string;

/**
* <p>The Amazon Web Services STS temporary credential that S3 Access Grants vends to grantees and client applications. </p>
* @public
* @public
*
* The input for {@link ListCallerAccessGrantsCommand}.
* @public
*
* The input for {@link ListCallerAccessGrantsCommand}.
*/
SessionToken?: string;

/**
* <p>The expiration date and time of the temporary credential that S3 Access Grants vends to grantees and client applications. </p>
* @public
* @public
*
* The output of {@link ListCallerAccessGrantsCommand}.
* @public
*
* The output of {@link ListCallerAccessGrantsCommand}.
*/
Expiration?: Date;
}

/**
* @public
*
* The input for {@link GetDataAccessCommand}.
*/
export type GetDataAccessCommandInput = GetDataAccessRequest;
/**
* @public
*
* The output of {@link GetDataAccessCommand}.
*/
export interface GetDataAccessCommandOutput
extends GetDataAccessResult,
__MetadataBearer {}

/**
* @public
*/
Expand Down Expand Up @@ -211,3 +161,56 @@ export interface GetDataAccessResult {
*/
MatchedGrantTarget?: string;
}

/**
* @public
*
* The input for {@link ListCallerAccessGrantsCommand}.
*/
export type ListCallerAccessGrantsCommandInput = ListCallerAccessGrantsRequest;
/**
* @public
*
* The output of {@link ListCallerAccessGrantsCommand}.
*/
export interface ListCallerAccessGrantsCommandOutput
extends ListCallerAccessGrantsResult,
__MetadataBearer {}
/**
* @public
*/
export interface ListCallerAccessGrantsEntry {
Permission?: Permission;
GrantScope?: string;
ApplicationArn?: string;
}
/**
* @public
*/
export interface ListCallerAccessGrantsRequest {
AccountId?: string;
GrantScope?: string;
NextToken?: string;
MaxResults?: number;
}
/**
* @public
*/
export interface ListCallerAccessGrantsResult {
NextToken?: string;
CallerAccessGrantsList?: ListCallerAccessGrantsEntry[];
}
/**
* @public
*/
export type Permission = (typeof Permission)[keyof typeof Permission];
/**
* @public
*/
export type Privilege = (typeof Privilege)[keyof typeof Privilege];
/**
* @public
*/
export type S3PrefixType = (typeof S3PrefixType)[keyof typeof S3PrefixType];

export {};
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,47 @@ export const deserializeTimestamp = (value: string): Date | undefined => {
return value ? new Date(value) : undefined;
};

/**
* Create a function deserializing a string to an enum value. If the string is not a valid enum value, it throws a
* StorageError.
*
* @example
* ```typescript
* const deserializeStringEnum = createStringEnumDeserializer(['a', 'b', 'c'] as const, 'FieldName');
* const deserializedArray = ['a', 'b', 'c'].map(deserializeStringEnum);
* // deserializedArray = ['a', 'b', 'c']
*
* const invalidValue = deserializeStringEnum('d');
* // Throws InvalidFieldName: Invalid FieldName: d
* ```
*
* @internal
*/
export const createStringEnumDeserializer = <T extends readonly string[]>(
enumValues: T,
fieldName: string,
) => {
const deserializeStringEnum = (
value: any,
): T extends (infer E)[] ? E : never => {
const parsedEnumValue = value
? (enumValues.find(enumValue => enumValue === value) as any)
: undefined;
if (!parsedEnumValue) {
throw new StorageError({
name: `Invalid${fieldName}`,
message: `Invalid ${fieldName}: ${value}`,
recoverySuggestion:
'This is likely to be a bug. Please reach out to library authors.',
});
}

return parsedEnumValue;
};

return deserializeStringEnum;
};

/**
* Function that makes sure the deserializer receives non-empty array.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { CredentialsProviderOptions } from '@aws-amplify/core/internals/aws-clie

import { logger } from '../../utils';
import { listCallerAccessGrants as listCallerAccessGrantsClient } from '../../providers/s3/utils/client/s3control';
import { LocationAccess, LocationType, Permission } from '../types';
import { LocationAccess, LocationType } from '../types';
import { StorageError } from '../../errors/StorageError';
import { getStorageUserAgentValue } from '../../providers/s3/utils/userAgent';

Expand Down Expand Up @@ -53,13 +53,11 @@ export const listCallerAccessGrants = async (

const accessGrants: LocationAccess[] =
CallerAccessGrantsList?.map(grant => {
// These values are correct from service mostly, but we add assertions to make TSC happy.
assertPermission(grant.Permission);
assertGrantScope(grant.GrantScope);

return {
scope: grant.GrantScope,
permission: grant.Permission,
permission: grant.Permission!,
type: parseGrantType(grant.GrantScope!),
};
}) ?? [];
Expand All @@ -86,17 +84,6 @@ const parseGrantType = (grantScope: string): LocationType => {
}
};

function assertPermission(
permissionValue: string | undefined,
): asserts permissionValue is Permission {
if (!['READ', 'READWRITE', 'WRITE'].includes(permissionValue ?? '')) {
throw new StorageError({
name: 'InvalidPermission',
message: `Invalid permission: ${permissionValue}`,
});
}
}

function assertGrantScope(value: unknown): asserts value is string {
if (typeof value !== 'string' || !value.startsWith('s3://')) {
throw new StorageError({
Expand Down
Loading