From d381f73bb29b918fc4540af4b31c1c0f9f077407 Mon Sep 17 00:00:00 2001 From: Aaron S Date: Thu, 14 Nov 2024 09:37:08 -0600 Subject: [PATCH] feat: Add mis build to the data factory --- .changeset/rare-kiwis-live.md | 6 +++ package-lock.json | 47 ++++++++-------- packages/backend-data/package.json | 5 +- .../src/app_sync_policy_generator.ts | 29 +++++++--- packages/backend-data/src/factory.test.ts | 53 ++++++++++++++++++- packages/backend-data/src/factory.ts | 35 +++++++++++- 6 files changed, 140 insertions(+), 35 deletions(-) create mode 100644 .changeset/rare-kiwis-live.md diff --git a/.changeset/rare-kiwis-live.md b/.changeset/rare-kiwis-live.md new file mode 100644 index 0000000000..bb1a87462a --- /dev/null +++ b/.changeset/rare-kiwis-live.md @@ -0,0 +1,6 @@ +--- +'@aws-amplify/backend': patch +'@aws-amplify/backend-data': patch +--- + +feat: Add mis build to S3 from the data construct factory diff --git a/package-lock.json b/package-lock.json index 1ce770cf49..6110d2f2b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31840,12 +31840,12 @@ }, "packages/auth-construct": { "name": "@aws-amplify/auth-construct", - "version": "1.4.0", + "version": "1.5.0", "license": "Apache-2.0", "dependencies": { "@aws-amplify/backend-output-schemas": "^1.4.0", "@aws-amplify/backend-output-storage": "^1.1.3", - "@aws-amplify/plugin-types": "^1.3.1", + "@aws-amplify/plugin-types": "^1.4.0", "@aws-sdk/util-arn-parser": "^3.568.0" }, "peerDependencies": { @@ -31855,12 +31855,12 @@ }, "packages/backend": { "name": "@aws-amplify/backend", - "version": "1.6.2", + "version": "1.7.0", "license": "Apache-2.0", "dependencies": { - "@aws-amplify/backend-auth": "^1.3.0", - "@aws-amplify/backend-data": "^1.1.7", - "@aws-amplify/backend-function": "^1.7.4", + "@aws-amplify/backend-auth": "^1.4.0", + "@aws-amplify/backend-data": "^1.2.0", + "@aws-amplify/backend-function": "^1.7.5", "@aws-amplify/backend-output-schemas": "^1.4.0", "@aws-amplify/backend-output-storage": "^1.1.3", "@aws-amplify/backend-secret": "^1.1.4", @@ -31868,7 +31868,7 @@ "@aws-amplify/client-config": "^1.5.2", "@aws-amplify/data-schema": "^1.0.0", "@aws-amplify/platform-core": "^1.2.0", - "@aws-amplify/plugin-types": "^1.3.1", + "@aws-amplify/plugin-types": "^1.4.0", "@aws-sdk/client-amplify": "^3.624.0", "lodash.snakecase": "^4.1.1" }, @@ -31901,13 +31901,13 @@ }, "packages/backend-auth": { "name": "@aws-amplify/backend-auth", - "version": "1.3.0", + "version": "1.4.0", "license": "Apache-2.0", "dependencies": { - "@aws-amplify/auth-construct": "^1.4.0", + "@aws-amplify/auth-construct": "^1.5.0", "@aws-amplify/backend-output-schemas": "^1.4.0", "@aws-amplify/backend-output-storage": "^1.1.3", - "@aws-amplify/plugin-types": "^1.3.1" + "@aws-amplify/plugin-types": "^1.4.0" }, "devDependencies": { "@aws-amplify/backend-platform-test-stubs": "^0.3.6", @@ -31924,14 +31924,15 @@ }, "packages/backend-data": { "name": "@aws-amplify/backend-data", - "version": "1.1.7", + "version": "1.2.0", "license": "Apache-2.0", "dependencies": { "@aws-amplify/backend-output-schemas": "^1.4.0", "@aws-amplify/backend-output-storage": "^1.1.3", "@aws-amplify/data-construct": "^1.10.1", "@aws-amplify/data-schema-types": "^1.2.0", - "@aws-amplify/plugin-types": "^1.3.1" + "@aws-amplify/graphql-generator": "^0.5.0", + "@aws-amplify/plugin-types": "^1.4.0" }, "devDependencies": { "@aws-amplify/backend-platform-test-stubs": "^0.3.6", @@ -31945,11 +31946,11 @@ }, "packages/backend-deployer": { "name": "@aws-amplify/backend-deployer", - "version": "1.1.8", + "version": "1.1.9", "license": "Apache-2.0", "dependencies": { "@aws-amplify/platform-core": "^1.2.0", - "@aws-amplify/plugin-types": "^1.3.1", + "@aws-amplify/plugin-types": "^1.4.0", "execa": "^8.0.1", "tsx": "^4.6.1" }, @@ -31960,12 +31961,12 @@ }, "packages/backend-function": { "name": "@aws-amplify/backend-function", - "version": "1.7.4", + "version": "1.7.5", "license": "Apache-2.0", "dependencies": { "@aws-amplify/backend-output-schemas": "^1.4.0", "@aws-amplify/backend-output-storage": "^1.1.3", - "@aws-amplify/plugin-types": "^1.3.1", + "@aws-amplify/plugin-types": "^1.4.0", "execa": "^8.0.1" }, "devDependencies": { @@ -32061,19 +32062,19 @@ }, "packages/cli": { "name": "@aws-amplify/backend-cli", - "version": "1.4.1", + "version": "1.4.2", "license": "Apache-2.0", "dependencies": { - "@aws-amplify/backend-deployer": "^1.1.8", + "@aws-amplify/backend-deployer": "^1.1.9", "@aws-amplify/backend-output-schemas": "^1.4.0", "@aws-amplify/backend-secret": "^1.1.2", "@aws-amplify/cli-core": "^1.2.0", "@aws-amplify/client-config": "^1.5.1", "@aws-amplify/deployed-backend-client": "^1.4.1", "@aws-amplify/form-generator": "^1.0.3", - "@aws-amplify/model-generator": "^1.0.8", + "@aws-amplify/model-generator": "^1.0.9", "@aws-amplify/platform-core": "^1.2.0", - "@aws-amplify/plugin-types": "^1.3.1", + "@aws-amplify/plugin-types": "^1.4.0", "@aws-amplify/sandbox": "^1.2.5", "@aws-amplify/schema-generator": "^1.2.5", "@aws-sdk/client-amplify": "^3.624.0", @@ -32461,7 +32462,7 @@ }, "packages/model-generator": { "name": "@aws-amplify/model-generator", - "version": "1.0.8", + "version": "1.0.9", "license": "Apache-2.0", "dependencies": { "@aws-amplify/backend-output-schemas": "^1.1.0", @@ -32469,7 +32470,7 @@ "@aws-amplify/graphql-generator": "^0.5.1", "@aws-amplify/graphql-types-generator": "^3.6.0", "@aws-amplify/platform-core": "^1.0.5", - "@aws-amplify/plugin-types": "^1.3.0", + "@aws-amplify/plugin-types": "^1.4.0", "@aws-sdk/client-appsync": "^3.624.0", "@aws-sdk/client-s3": "^3.624.0", "@aws-sdk/credential-providers": "^3.624.0", @@ -32515,7 +32516,7 @@ }, "packages/plugin-types": { "name": "@aws-amplify/plugin-types", - "version": "1.3.1", + "version": "1.4.0", "license": "Apache-2.0", "devDependencies": { "execa": "^5.1.1" diff --git a/packages/backend-data/package.json b/packages/backend-data/package.json index 5e0384b04e..67e1ee3f31 100644 --- a/packages/backend-data/package.json +++ b/packages/backend-data/package.json @@ -31,7 +31,8 @@ "@aws-amplify/backend-output-storage": "^1.1.3", "@aws-amplify/backend-output-schemas": "^1.4.0", "@aws-amplify/data-construct": "^1.10.1", - "@aws-amplify/plugin-types": "^1.4.0", - "@aws-amplify/data-schema-types": "^1.2.0" + "@aws-amplify/data-schema-types": "^1.2.0", + "@aws-amplify/graphql-generator": "^0.5.1", + "@aws-amplify/plugin-types": "^1.4.0" } } diff --git a/packages/backend-data/src/app_sync_policy_generator.ts b/packages/backend-data/src/app_sync_policy_generator.ts index 9962d1922e..5db2eaea3d 100644 --- a/packages/backend-data/src/app_sync_policy_generator.ts +++ b/packages/backend-data/src/app_sync_policy_generator.ts @@ -14,7 +14,10 @@ export class AppSyncPolicyGenerator { /** * Initialize with the GraphqlAPI that the policies will be scoped to */ - constructor(private readonly graphqlApi: IGraphqlApi) { + constructor( + private readonly graphqlApi: IGraphqlApi, + private readonly modelIntrospectionSchemaArn?: string + ) { this.stack = Stack.of(graphqlApi); } /** @@ -29,13 +32,25 @@ export class AppSyncPolicyGenerator { .map((action) => actionToTypeMap[action]) // convert Type to resourceName .map((type) => [this.graphqlApi.arn, 'types', type, '*'].join('/')); - return new Policy(this.stack, `${this.policyPrefix}${this.policyCount++}`, { - statements: [ + + const statements = [ + new PolicyStatement({ + actions: ['appsync:GraphQL'], + resources, + }), + ]; + + if (this.modelIntrospectionSchemaArn) { + statements.push( new PolicyStatement({ - actions: ['appsync:GraphQL'], - resources, - }), - ], + actions: ['s3:GetObject'], + resources: [this.modelIntrospectionSchemaArn], + }) + ); + } + + return new Policy(this.stack, `${this.policyPrefix}${this.policyCount++}`, { + statements, }); } } diff --git a/packages/backend-data/src/factory.test.ts b/packages/backend-data/src/factory.test.ts index 51e2aabf45..91e1fdeff6 100644 --- a/packages/backend-data/src/factory.test.ts +++ b/packages/backend-data/src/factory.test.ts @@ -85,7 +85,6 @@ const createConstructContainerWithUserPoolAuthRegistered = ( authenticatedUserIamRole: new Role(stack, 'testAuthRole', { assumedBy: new ServicePrincipal('test.amazon.com'), }), - identityPoolId: 'identityPoolId', cfnResources: { cfnUserPool: new CfnUserPool(stack, 'CfnUserPool', {}), cfnUserPoolClient: new CfnUserPoolClient(stack, 'CfnUserPoolClient', { @@ -101,6 +100,7 @@ const createConstructContainerWithUserPoolAuthRegistered = ( ), }, groups: {}, + identityPoolId: 'identityPool', }, }), }); @@ -567,6 +567,23 @@ void describe('DataFactory', () => { }, ], }, + { + Action: 's3:GetObject', + Resource: { + 'Fn::Join': [ + '', + [ + { + 'Fn::GetAtt': [ + 'modelIntrospectionSchemaBucketF566B665', + 'Arn', + ], + }, + '/modelIntrospectionSchema.json', + ], + ], + }, + }, ], }, Roles: [ @@ -675,6 +692,23 @@ void describe('DataFactory', () => { ], }, }, + { + Action: 's3:GetObject', + Resource: { + 'Fn::Join': [ + '', + [ + { + 'Fn::GetAtt': [ + 'modelIntrospectionSchemaBucketF566B665', + 'Arn', + ], + }, + '/modelIntrospectionSchema.json', + ], + ], + }, + }, ], }, Roles: [ @@ -701,6 +735,23 @@ void describe('DataFactory', () => { ], }, }, + { + Action: 's3:GetObject', + Resource: { + 'Fn::Join': [ + '', + [ + { + 'Fn::GetAtt': [ + 'modelIntrospectionSchemaBucketF566B665', + 'Arn', + ], + }, + '/modelIntrospectionSchema.json', + ], + ], + }, + }, ], }, Roles: [ diff --git a/packages/backend-data/src/factory.ts b/packages/backend-data/src/factory.ts index 578d0cbcbc..ebdacff555 100644 --- a/packages/backend-data/src/factory.ts +++ b/packages/backend-data/src/factory.ts @@ -17,6 +17,7 @@ import { TranslationBehavior, } from '@aws-amplify/data-construct'; import { GraphqlOutput } from '@aws-amplify/backend-output-schemas'; +import { generateModelsSync } from '@aws-amplify/graphql-generator'; import * as path from 'path'; import { AmplifyDataError, DataProps } from './types.js'; import { @@ -46,6 +47,10 @@ import { FunctionSchemaAccess, JsResolver, } from '@aws-amplify/data-schema-types'; +import { Bucket } from 'aws-cdk-lib/aws-s3'; +import { BucketDeployment, Source } from 'aws-cdk-lib/aws-s3-deployment'; + +const modelIntrospectionSchemaKey = 'modelIntrospectionSchema.json'; /** * Singleton factory for AmplifyGraphqlApi constructs that can be used in Amplify project files. @@ -232,14 +237,21 @@ class DataGenerator implements ConstructContainerEntryGenerator { ...schemasLambdaFunctions, }); let amplifyApi = undefined; + let modelIntrospectionSchema: string | undefined = undefined; const isSandboxDeployment = scope.node.tryGetContext(CDKContextKey.DEPLOYMENT_TYPE) === 'sandbox'; try { + const combinedSchema = combineCDKSchemas(amplifyGraphqlDefinitions); + modelIntrospectionSchema = generateModelsSync({ + schema: combinedSchema.schema, + target: 'introspection', + })['model-introspection.json']; + amplifyApi = new AmplifyData(scope, this.name, { apiName: this.name, - definition: combineCDKSchemas(amplifyGraphqlDefinitions), + definition: combinedSchema, authorizationModes, outputStorageStrategy: this.outputStorageStrategy, functionNameMap, @@ -264,6 +276,20 @@ class DataGenerator implements ConstructContainerEntryGenerator { ); } + const modelIntrospectionSchemaBucket = new Bucket( + scope, + 'modelIntrospectionSchemaBucket', + { enforceSSL: true } + ); + new BucketDeployment(scope, 'modelIntrospectionSchemaBucketDeployment', { + // See https://github.com/aws-amplify/amplify-category-api/pull/1939 + memoryLimit: 1536, + destinationBucket: modelIntrospectionSchemaBucket, + sources: [ + Source.data(modelIntrospectionSchemaKey, modelIntrospectionSchema), + ], + }); + Tags.of(amplifyApi).add(TagName.FRIENDLY_NAME, this.name); /**; @@ -280,10 +306,15 @@ class DataGenerator implements ConstructContainerEntryGenerator { ssmEnvironmentEntriesGenerator.generateSsmEnvironmentEntries({ [`${this.name}_GRAPHQL_ENDPOINT`]: amplifyApi.resources.cfnResources.cfnGraphqlApi.attrGraphQlUrl, + [`${this.name}_MODEL_INTROSPECTION_SCHEMA_BUCKET_NAME`]: + modelIntrospectionSchemaBucket.bucketName, + [`${this.name}_MODEL_INTROSPECTION_SCHEMA_KEY`]: + modelIntrospectionSchemaKey, }); const policyGenerator = new AppSyncPolicyGenerator( - amplifyApi.resources.graphqlApi + amplifyApi.resources.graphqlApi, + `${modelIntrospectionSchemaBucket.bucketArn}/${modelIntrospectionSchemaKey}` ); schemasFunctionSchemaAccess.forEach((accessDefinition) => {