Skip to content

Commit

Permalink
Merge GraphQL v-next to master (aws-amplify#8287)
Browse files Browse the repository at this point in the history
* feat(cli-api): improve add and update api

* Delete sam.schema.json

* Delete cloudformation.schema.json

* remove auto apply authmode code from update api workflow

* remove unused import

* fix lint issues

* relative import

* fix dependencies

* fix lint comments

* remove unused code

* updated v2 templates

* remove unused import

* change to use executeProviderUtils

* fixed formatting

* several minor tweaks to add and update api workflow

* update conflict detection label

* remove app not deployed message

* auto apply auth mode

* auto apply authmode for v2 tranformer

* add type amplify_global to v2 schemas

* Update many-relationship-schema-v2.graphql

* Update single-object-auth-schema-v2.graphql

* Update single-object-schema-v2.graphql

* feat: add @auth (#1)

* feat: add @auth base package with Access Control

* feat: graphql auth v2 add schemaChanges, iam policy generation, and query/read resolvers

* feat: graphql auth v2 add auth on mutation and subscription resolvers

* feat(amplify-category-api): add global sandbox mode directive on schema generation (aws-amplify#8074)

* feat(amplify-category-api): add global sandbox mode directive on schema generation

* test(amplify-e2e-tests): add e2e tests for sandbox mode

* test(amplify-category-api): add unit test for generating sandbox mode directive; rm unused method

* feat(cli): add sandbox mode warning to amplify status (aws-amplify#8078)

* feat(amplify-category-api): prompt api key creation on amplify push (aws-amplify#8124)

* feat(amplify-category-api): prompt api key create when invalid with sandbox mode

* test(amplify-category-api): add unit tests for provider utils

* test(amplify-category-api): fix test for adding api key prompt

* refactor(cli): refactor api key prompt

* refactor(amplify-category-api): add api key with gql compiled

* feat: @model conflict resolution

* auth directive support for index, searchable, predictions, functions, and relational directives (aws-amplify#8146)

* feat: add support for index and updated unit and e2e tests

* feat: directive suport for functions, predictions, searchable, and relational

* test: updated unit tests for updated auth on directives

* @auth support for datastore and add has auth flag (aws-amplify#8168)

* feat: @auth v2 on datastore and updated unit tests
* feat: add hasAuthFlag

* feat(graphql-model-transformer): set up transformer for sandbox mode directive (aws-amplify#8138)

* feat(graphql-model-transformer): add sandbox mode support to model transformer

* refactor(graphql-transformer-core): do not persist sandbox mode meta data

* fix: add command to show access control and field auth evaluation in access control (aws-amplify#8174)

* fix: admin ui app state check and auth transformer index resolver name (aws-amplify#8175)

* fix: has auth typo and qref on field conditions for private rule (aws-amplify#8180)

* fix(graphql-model-transformer): use hasAuth flag when sandbox mode is disabled (aws-amplify#8179)

* fix: update hasMany to use join table name, sync config warning, updated unit test

* fix: add empty payload for sandbox mode

* fix: snapshot test for @searchable

* fix: udpated snapshot for index and relation directives

* fix: use same none datasource name as resolver manager

* fix: iam resolver check and relational payload (aws-amplify#8234)

* fix: add datastore query in config for auth (aws-amplify#8246)

* fix: auth filter expression (aws-amplify#8248)

* fix: update iam auth to include roles in before template (aws-amplify#8259)

* chore: rebase and update auth dependencies

* fix(graphql-model-transformer): iam role name does not exceed 64 characters

* fix: add base e2e tests with auth fixes

Co-authored-by: Danielle Adams <6271256+danielleadams@users.noreply.github.com>
Co-authored-by: lazpavel <85319655+lazpavel@users.noreply.github.com>

* fix: update dependency versions

* feat(amplify-provider-awscloudformation): match env directive field for sandbox mode (#3)

* fix(amplify-provider-awscloudformation): invoke api function from invoker plugin (aws-amplify#8274)

* fix(amplify-provider-awscloudformation): invoke api function from invoker plugin

* fix(graphql-index-transformer): update snapshots for tests

* test(amplify-provider-awscloudformation): fix tests for sandbox helpers

* fix(amplify-provider-awscloudformation): remove sandbox mode directive from schema before transform (aws-amplify#8272)

* chore(graphql-auth-transformer): update deps for auth transformer and api category

* fix(graphql-model-transformer): revert code to master version

* test(graphql-model-transformer): update the snapshot for the amplify/graphql-model-transformer test

* chore: remove showacm as that was for testing purposes only

* test(amplify-e2e-tests): update to use correct helpers

* test(graphql-transformers-e2e-tests): enable sandbox mode on v2 transforms

* test(amplify-e2e-tests): replace updateAPIResolution imports with new methods

* fix: get item query for @model and relational directives

* auto apply auth fix

* auto apply auth modes v2 fix (#4)

* test(amplify-e2e-tests): rm sandbox e2e test

* fix(amplify-provider-awscloudformation): fix api key creation when sandbox mode enable

* test(amplify-e2e-tests): create random app name generator for broken tests

* fix api e2e workflow

* test(amplify-e2e-core): add random app name generator, update snapshots and imports

* chore(graphql-auth-transformer): upgrade deps in auth transformer

* update e2e test to use new api workflow (#5)

* feat(graphql-model-transformer): fix default value e2e test (#6)

* test(amplify-e2e-tests): add missing helper

* e2e fix for auth tests using new api workflow  (aws-amplify#7)

* update e2e test to use new api workflow

* fix(test): update auth tests with new api workflow

* test(amplify-e2e-tests): add missing helper and fix broken test

Co-authored-by: Christopher Sundersingh <sundersc@amazon.com>
Co-authored-by: Christopher Sundersingh <83315412+sundersc@users.noreply.github.com>
Co-authored-by: Josue Ruiz <7465495+SwaySway@users.noreply.github.com>
Co-authored-by: lazpavel <85319655+lazpavel@users.noreply.github.com>
Co-authored-by: Colin Ihrig <colihrig@amazon.com>
  • Loading branch information
6 people authored Oct 14, 2021
1 parent 385c395 commit b5ba1f0
Show file tree
Hide file tree
Showing 166 changed files with 20,920 additions and 3,717 deletions.
175 changes: 111 additions & 64 deletions .circleci/config.yml

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions packages/amplify-category-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@
"@octokit/rest": "^18.0.9",
"amplify-cli-core": "1.31.1",
"amplify-headless-interface": "1.10.0",
"amplify-prompts": "1.2.0",
"amplify-provider-awscloudformation": "4.61.1",
"amplify-util-headless-input": "1.5.4",
"chalk": "^4.1.1",
"constructs": "^3.3.125",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
type Blog @model {
id: ID!
name: String!
posts: [Post] @hasMany
}

type Post @model {
id: ID!
title: String!
blog: Blog @belongsTo
comments: [Comment] @hasMany
}

type Comment @model {
id: ID!
post: Post @belongsTo
content: String!
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
type Task
@model
@auth(rules: [
{ allow: groups, groups: ["Managers"], operations: [create, update, read, delete] }
{ allow: groups, groups: ["Employees"], operations: [read] } ]) {
id: ID!
title: String!
description: String
status: String
}

type PrivateNote @model @auth(rules: [{ allow: owner }]) {
id: ID!
content: String!
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type Todo @model {
id: ID!
name: String!
description: String
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Object {
},
Object {
"apiKeyConfig": Object {
"apiKeyExpirationDate": undefined,
"apiKeyExpirationDays": undefined,
"description": undefined,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jest.mock('../../../provider-utils/awscloudformation/utils/amplify-meta-utils',

jest.mock('amplify-cli-core');

const fs_mock = (fs as unknown) as jest.Mocked<typeof fs>;
const fs_mock = fs as unknown as jest.Mocked<typeof fs>;
const writeTransformerConfiguration_mock = writeTransformerConfiguration as jest.MockedFunction<typeof writeTransformerConfiguration>;
const getAppSyncResourceName_mock = getAppSyncResourceName as jest.MockedFunction<typeof getAppSyncResourceName>;
const getAppSyncAuthConfig_mock = getAppSyncAuthConfig as jest.MockedFunction<typeof getAppSyncAuthConfig>;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { $TSContext } from 'amplify-cli-core';
import * as prompts from 'amplify-prompts';
import { promptToAddApiKey } from '../../../provider-utils/awscloudformation/prompt-to-add-api-key';
import * as walkthrough from '../../../provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough';
import * as cfnApiArtifactHandler from '../../../provider-utils/awscloudformation/cfn-api-artifact-handler';

jest.mock('../../../provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough', () => ({
askApiKeyQuestions: jest.fn(),
}));

jest.mock('../../../provider-utils/awscloudformation/cfn-api-artifact-handler', () => ({
getCfnApiArtifactHandler: jest.fn(() => {
return { updateArtifacts: jest.fn() };
}),
}));

jest.mock('amplify-prompts', () => ({
prompter: {
confirmContinue: jest.fn().mockImplementation(() => true),
},
}));

describe('prompt to add Api Key', () => {
it('runs through expected user flow: print info, update files', async () => {
const envName = 'envone';
const ctx = {
amplify: {
getEnvInfo() {
return { envName };
},
},
} as unknown as $TSContext;

jest.spyOn(prompts.prompter, 'confirmContinue');
jest.spyOn(walkthrough, 'askApiKeyQuestions');
jest.spyOn(cfnApiArtifactHandler, 'getCfnApiArtifactHandler');

await promptToAddApiKey(ctx);

expect(prompts.prompter.confirmContinue).toHaveBeenCalledWith('Would you like to create an API Key?');
expect(walkthrough.askApiKeyQuestions).toHaveBeenCalledTimes(1);
expect(cfnApiArtifactHandler.getCfnApiArtifactHandler).toHaveBeenCalledTimes(1);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
askAdditionalAuthQuestions,
} from '../../../../provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough';
import { authConfigHasApiKey, getAppSyncAuthConfig } from '../../../../provider-utils/awscloudformation/utils/amplify-meta-utils';
import { FeatureFlags, CLIEnvironmentProvider, FeatureFlagRegistration } from 'amplify-cli-core';
import { FeatureFlags } from 'amplify-cli-core';
jest.mock('../../../../provider-utils/awscloudformation/utils/amplify-meta-utils', () => ({
getAppSyncAuthConfig: jest.fn(),
authConfigHasApiKey: jest.fn(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Object {
exports[`AppSyncAuthType to authConfig maps API_KEY correctly 1`] = `
Object {
"apiKeyConfig": Object {
"apiKeyExpirationDate": undefined,
"apiKeyExpirationDays": 120,
"description": undefined,
},
Expand Down Expand Up @@ -47,6 +48,7 @@ Object {

exports[`authConfig to AppSyncAuthType maps API_KEY auth correctly 1`] = `
Object {
"apiKeyExpirationDate": undefined,
"expirationTime": 120,
"keyDescription": "api key description",
"mode": "API_KEY",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { defineGlobalSandboxMode } from '../../../../provider-utils/awscloudformation/utils/global-sandbox-mode';
import { $TSContext } from 'amplify-cli-core';

describe('global sandbox mode GraphQL directive', () => {
it('returns AMPLIFY_DIRECTIVE type with code comment, directive, and env name', () => {
const envName = 'envone';
const ctx = <$TSContext>{
amplify: {
getEnvInfo() {
return { envName };
},
},
};

expect(defineGlobalSandboxMode(ctx))
.toBe(`# This allows public create, read, update, and delete access for a limited time to all models via API Key.
# To configure PRODUCTION-READY authorization rules, review: https://docs.amplify.aws/cli/graphql-transformer/auth
type AMPLIFY_GLOBAL @allow_public_data_access_with_api_key(in: \"${envName}\") # FOR TESTING ONLY!\n
`);
});
});
33 changes: 33 additions & 0 deletions packages/amplify-category-api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import fs from 'fs-extra';
import path from 'path';
import { run } from './commands/api/console';
import { getCfnApiArtifactHandler } from './provider-utils/awscloudformation/cfn-api-artifact-handler';
import { askAuthQuestions } from './provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough';
import { getAppSyncResourceName, getAppSyncAuthConfig } from './provider-utils/awscloudformation//utils/amplify-meta-utils';
import { authConfigToAppSyncAuthType } from './provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper';

export { NETWORK_STACK_LOGICAL_ID } from './category-constants';
export { DEPLOYMENT_MECHANISM } from './provider-utils/awscloudformation/base-api-stack';
Expand All @@ -15,6 +18,7 @@ export {
processDockerConfig,
} from './provider-utils/awscloudformation/utils/containers-artifacts';
export { getContainers } from './provider-utils/awscloudformation/docker-compose';
export { promptToAddApiKey } from './provider-utils/awscloudformation/prompt-to-add-api-key';

const category = 'api';

Expand Down Expand Up @@ -217,3 +221,32 @@ export async function handleAmplifyEvent(context, args) {
context.print.info(`${category} handleAmplifyEvent to be implemented`);
context.print.info(`Received event args ${args}`);
}

export async function addGraphQLAuthorizationMode(context, args) {
const { authType, printLeadText, authSettings } = args;
const apiName = getAppSyncResourceName(context.amplify.getProjectMeta());
if (!apiName) {
return;
}

const authConfig = getAppSyncAuthConfig(context.amplify.getProjectMeta());
const addAuthConfig = await askAuthQuestions(authType, context, printLeadText, authSettings);
authConfig.additionalAuthenticationProviders.push(addAuthConfig);
await context.amplify.updateamplifyMetaAfterResourceUpdate(category, apiName, 'output', { authConfig });
await context.amplify.updateBackendConfigAfterResourceUpdate(category, apiName, 'output', { authConfig });

await getCfnApiArtifactHandler(context).updateArtifacts(
{
version: 1,
serviceModification: {
serviceName: 'AppSync',
additionalAuthTypes: authConfig.additionalAuthenticationProviders.map(authConfigToAppSyncAuthType),
},
},
{
skipCompile: false,
},
);

return addAuthConfig;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { AddApiRequest, UpdateApiRequest } from 'amplify-headless-interface';

export interface ApiArtifactHandlerOptions {
skipCompile?: boolean;
}

export interface ApiArtifactHandler {
createArtifacts(request: AddApiRequest): Promise<string>;
updateArtifacts(request: UpdateApiRequest): Promise<void>;
updateArtifacts(request: UpdateApiRequest, opts?: ApiArtifactHandlerOptions): Promise<void>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import _ from 'lodash';
import * as path from 'path';
import uuid from 'uuid';
import { category } from '../../category-constants';
import { ApiArtifactHandler } from '../api-artifact-handler';
import { ApiArtifactHandler, ApiArtifactHandlerOptions } from '../api-artifact-handler';
import { cfnParametersFilename, gqlSchemaFilename, provider, rootAssetDir } from './aws-constants';
import { authConfigHasApiKey, checkIfAuthExists, getAppSyncAuthConfig, getAppSyncResourceName } from './utils/amplify-meta-utils';
import { appSyncAuthTypeToAuthConfig } from './utils/auth-config-to-app-sync-auth-type-bi-di-mapper';
Expand Down Expand Up @@ -96,7 +96,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler {

// TODO once the AddApiRequest contains multiple services this class should depend on an ApiArtifactHandler
// for each service and delegate to the correct one
updateArtifacts = async (request: UpdateApiRequest): Promise<void> => {
updateArtifacts = async (request: UpdateApiRequest, opts?: ApiArtifactHandlerOptions): Promise<void> => {
const updates = request.serviceModification;
const apiName = getAppSyncResourceName(this.context.amplify.getProjectMeta());
if (!apiName) {
Expand All @@ -118,11 +118,14 @@ class CfnApiArtifactHandler implements ApiArtifactHandler {
if (updates.additionalAuthTypes) {
authConfig.additionalAuthenticationProviders = updates.additionalAuthTypes.map(appSyncAuthTypeToAuthConfig);
}
await this.context.amplify.executeProviderUtils(this.context, 'awscloudformation', 'compileSchema', {
resourceDir,
parameters: this.getCfnParameters(apiName, authConfig, resourceDir),
authConfig,
});

if (!opts?.skipCompile) {
await this.context.amplify.executeProviderUtils(this.context, 'awscloudformation', 'compileSchema', {
resourceDir,
parameters: this.getCfnParameters(apiName, authConfig, resourceDir),
authConfig,
});
}

this.context.amplify.updateamplifyMetaAfterResourceUpdate(category, apiName, 'output', { authConfig });
this.context.amplify.updateBackendConfigAfterResourceUpdate(category, apiName, 'output', { authConfig });
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { $TSContext } from 'amplify-cli-core';
import { askApiKeyQuestions } from './service-walkthroughs/appSync-walkthrough';
import { authConfigToAppSyncAuthType } from './utils/auth-config-to-app-sync-auth-type-bi-di-mapper';
import { getCfnApiArtifactHandler } from './cfn-api-artifact-handler';
import { prompter } from 'amplify-prompts';

export async function promptToAddApiKey(context: $TSContext): Promise<any> {
if (await prompter.confirmContinue('Would you like to create an API Key?')) {
const apiKeyConfig = await askApiKeyQuestions();
const authConfig = [apiKeyConfig];

await getCfnApiArtifactHandler(context).updateArtifacts(
{
version: 1,
serviceModification: {
serviceName: 'AppSync',
additionalAuthTypes: authConfig.map(authConfigToAppSyncAuthType),
},
},
{
skipCompile: true,
},
);

return apiKeyConfig;
}
}
Loading

0 comments on commit b5ba1f0

Please sign in to comment.