From 11db57a7400ec26c73ac9021cc71a4d0f36c2eb1 Mon Sep 17 00:00:00 2001 From: Jon Wire Date: Wed, 23 Apr 2025 17:44:05 -0500 Subject: [PATCH 1/4] fix: add missing aws_iam directive on custom types --- .../__tests__/iam-custom-operations.test.ts | 4 +-- .../src/graphql-auth-transformer.ts | 25 +++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/packages/amplify-graphql-auth-transformer/src/__tests__/iam-custom-operations.test.ts b/packages/amplify-graphql-auth-transformer/src/__tests__/iam-custom-operations.test.ts index 2d3d3864ec..216a77d1b1 100644 --- a/packages/amplify-graphql-auth-transformer/src/__tests__/iam-custom-operations.test.ts +++ b/packages/amplify-graphql-auth-transformer/src/__tests__/iam-custom-operations.test.ts @@ -368,7 +368,7 @@ describe('Custom operations have @aws_iam directives when enableIamAuthorization }); // TODO: Enable this test once we fix https://github.com/aws-amplify/amplify-category-api/issues/2929 - test.skip('Adds @aws_iam to non-model custom types when there is no model', () => { + test('Adds @aws_iam to non-model custom types when there is no model', () => { const strategy = makeStrategy(strategyType); const schema = /* GraphQL */ ` type Foo { @@ -404,7 +404,7 @@ describe('Custom operations have @aws_iam directives when enableIamAuthorization }); // TODO: Enable this test once we fix https://github.com/aws-amplify/amplify-category-api/issues/2929 - test.skip('Adds @aws_iam to non-model custom types when there is a model', () => { + test('Adds @aws_iam to non-model custom types when there is a model', () => { const strategy = makeStrategy(strategyType); const schema = /* GraphQL */ ` type Todo @model { diff --git a/packages/amplify-graphql-auth-transformer/src/graphql-auth-transformer.ts b/packages/amplify-graphql-auth-transformer/src/graphql-auth-transformer.ts index 04a0ed68f3..04c4dfa4f5 100644 --- a/packages/amplify-graphql-auth-transformer/src/graphql-auth-transformer.ts +++ b/packages/amplify-graphql-auth-transformer/src/graphql-auth-transformer.ts @@ -10,6 +10,7 @@ import { isBuiltInGraphqlNode, isDynamoDbModel, isModelType, + isObjectTypeDefinitionNode, isSqlModel, MappingTemplate, TransformerAuthBase, @@ -377,8 +378,32 @@ export class AuthTransformer extends TransformerAuthBase implements TransformerA }); }; + /** + * Adds the `aws_iam` directive to all custom/non-model types when IAM access is enabled. + */ + addIamAuthToCustomTypes = (ctx: TransformerTransformSchemaStepContextProvider): void => { + if (!ctx.transformParameters.sandboxModeEnabled && !ctx.synthParameters.enableIamAccess) { + return; + } + + const needsAwsIamDirective = (type: TypeDefinitionNode): boolean => { + return !type.directives?.some((dir) => dir.name.value === 'aws_iam'); + }; + + const isNonModelType = (type: TypeDefinitionNode): boolean => { + return !type.directives?.some((dir) => dir.name.value === 'model'); + }; + + ctx.inputDocument.definitions + .filter(isObjectTypeDefinitionNode) + .filter(isNonModelType) + .filter(needsAwsIamDirective) + .forEach((def) => extendTypeWithDirectives(ctx, def.name.value, [makeDirective('aws_iam', [])])); + }; + transformSchema = (context: TransformerTransformSchemaStepContextProvider): void => { this.addCustomOperationFieldsToAuthNonModelConfig(context); + this.addIamAuthToCustomTypes(context); const searchableAggregateServiceDirectives = new Set(); From 98abc63e0e82d86ba534a9cf73ee1f25645381dc Mon Sep 17 00:00:00 2001 From: Jon Wire Date: Thu, 24 Apr 2025 10:03:24 -0500 Subject: [PATCH 2/4] chore: update api extract --- packages/amplify-graphql-auth-transformer/API.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/amplify-graphql-auth-transformer/API.md b/packages/amplify-graphql-auth-transformer/API.md index bca6de7a0b..64209f6980 100644 --- a/packages/amplify-graphql-auth-transformer/API.md +++ b/packages/amplify-graphql-auth-transformer/API.md @@ -117,6 +117,8 @@ export class AuthTransformer extends TransformerAuthBase implements TransformerA // (undocumented) addFieldsToObject: (ctx: TransformerTransformSchemaStepContextProvider, modelName: string, ownerFields: Array) => void; // (undocumented) + addIamAuthToCustomTypes: (ctx: TransformerTransformSchemaStepContextProvider) => void; + // (undocumented) after: (context: TransformerContextProvider) => void; // (undocumented) before: (context: TransformerBeforeStepContextProvider) => void; From 0926b225b4d8917afbd2027aa9433072f9c59bbe Mon Sep 17 00:00:00 2001 From: Jon Wire Date: Fri, 25 Apr 2025 15:25:35 -0500 Subject: [PATCH 3/4] chore: remove todos --- .../src/__tests__/iam-custom-operations.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/amplify-graphql-auth-transformer/src/__tests__/iam-custom-operations.test.ts b/packages/amplify-graphql-auth-transformer/src/__tests__/iam-custom-operations.test.ts index 216a77d1b1..fc11a9eb8a 100644 --- a/packages/amplify-graphql-auth-transformer/src/__tests__/iam-custom-operations.test.ts +++ b/packages/amplify-graphql-auth-transformer/src/__tests__/iam-custom-operations.test.ts @@ -367,7 +367,6 @@ describe('Custom operations have @aws_iam directives when enableIamAuthorization expect(out.schema).not.toMatch(/onUpdateFooCustom: String.*@aws_iam/); }); - // TODO: Enable this test once we fix https://github.com/aws-amplify/amplify-category-api/issues/2929 test('Adds @aws_iam to non-model custom types when there is no model', () => { const strategy = makeStrategy(strategyType); const schema = /* GraphQL */ ` @@ -403,7 +402,6 @@ describe('Custom operations have @aws_iam directives when enableIamAuthorization expect(out.schema).toMatch(/type Foo.*@aws_iam/); }); - // TODO: Enable this test once we fix https://github.com/aws-amplify/amplify-category-api/issues/2929 test('Adds @aws_iam to non-model custom types when there is a model', () => { const strategy = makeStrategy(strategyType); const schema = /* GraphQL */ ` From 099c8e18ba182ae26dd0cae79f3150cdccfee654 Mon Sep 17 00:00:00 2001 From: Jon Wire Date: Fri, 25 Apr 2025 15:31:41 -0500 Subject: [PATCH 4/4] test: add iam auth test specifically for EventInvocationResponse type --- .../__tests__/iam-custom-operations.test.ts | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/packages/amplify-graphql-auth-transformer/src/__tests__/iam-custom-operations.test.ts b/packages/amplify-graphql-auth-transformer/src/__tests__/iam-custom-operations.test.ts index fc11a9eb8a..6c9d0f9ead 100644 --- a/packages/amplify-graphql-auth-transformer/src/__tests__/iam-custom-operations.test.ts +++ b/packages/amplify-graphql-auth-transformer/src/__tests__/iam-custom-operations.test.ts @@ -1,3 +1,4 @@ +import { FunctionTransformer } from '@aws-amplify/graphql-function-transformer'; import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; import { mockSqlDataSourceStrategy, testTransform } from '@aws-amplify/graphql-transformer-test-utils'; import { PrimaryKeyTransformer } from '@aws-amplify/graphql-index-transformer'; @@ -40,6 +41,7 @@ const makeTransformers = (): TransformerPluginProvider[] => [ new AuthTransformer(), new PrimaryKeyTransformer(), new SqlTransformer(), + new FunctionTransformer(), ]; const makeSqlDirectiveDataSourceStrategies = (schema: string, strategy: ModelDataSourceStrategy): SqlDirectiveDataSourceStrategy[] => @@ -476,6 +478,42 @@ describe('Custom operations have @aws_iam directives when enableIamAuthorization expect(out.schema).toMatch(/description: String.*@aws_iam/); }); + test('Adds @aws_iam to async function EventInvocationResponse type', () => { + const strategy = makeStrategy(strategyType); + const schema = /* GraphQL */ ` + type Foo { + description: String + } + type EventInvocationResponse @aws_api_key { + success: Boolean! + } + type Query { + getFooCustom: Foo + } + type Mutation { + updateFooCustom: Foo + doSomethingAsync(body: String!): EventInvocationResponse + @function(name: "FnDoSomethingAsync", invocationType: Event) + @auth(rules: [{ allow: public, provider: apiKey }]) + } + type Subscription { + onUpdateFooCustom: Foo @aws_subscribe(mutations: ["updateFooCustom"]) + } + `; + + const out = testTransform({ + schema, + dataSourceStrategies: constructDataSourceStrategies(schema, strategy), + authConfig: makeAuthConfig(), + synthParameters: makeSynthParameters(), + transformers: makeTransformers(), + sqlDirectiveDataSourceStrategies: makeSqlDirectiveDataSourceStrategies(schema, strategy), + }); + + // Also expect the custom type referenced by the custom operation to be authorized + expect(out.schema).toMatch(/type EventInvocationResponse.*@aws_iam/); + }); + test('Does not add duplicate @aws_iam directive to custom type if already present', () => { const strategy = makeStrategy(strategyType); const schema = /* GraphQL */ `