Skip to content

Commit

Permalink
feat(cli): add sandbox mode warning to amplify status
Browse files Browse the repository at this point in the history
  • Loading branch information
danielleadams committed Sep 8, 2021
1 parent acaff15 commit 2c0f74a
Show file tree
Hide file tree
Showing 19 changed files with 448 additions and 32 deletions.
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 @@ -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
Expand Up @@ -21,6 +21,7 @@ import {
$TSContext,
open,
} from 'amplify-cli-core';
import { Duration, Expiration } from '@aws-cdk/core';

const serviceName = 'AppSync';
const elasticContainerServiceName = 'ElasticContainer';
Expand Down Expand Up @@ -508,9 +509,11 @@ export async function askAdditionalAuthQuestions(context, authConfig, defaultAut
if (await context.prompt.confirm('Configure additional auth types?')) {
// Get additional auth configured
const remainingAuthProviderChoices = authProviderChoices.filter(p => p.value !== defaultAuthType);
const currentAdditionalAuth = ((currentAuthConfig && currentAuthConfig.additionalAuthenticationProviders
? currentAuthConfig.additionalAuthenticationProviders
: []) as any[]).map(authProvider => authProvider.authenticationType);
const currentAdditionalAuth = (
(currentAuthConfig && currentAuthConfig.additionalAuthenticationProviders
? currentAuthConfig.additionalAuthenticationProviders
: []) as any[]
).map(authProvider => authProvider.authenticationType);

const additionalProvidersQuestion: CheckboxQuestion = {
type: 'checkbox',
Expand Down Expand Up @@ -619,6 +622,8 @@ async function askApiKeyQuestions() {
];

const apiKeyConfig = await inquirer.prompt(apiKeyQuestions);
const apiKeyExpirationDaysNum = Number(apiKeyConfig.apiKeyExpirationDays);
apiKeyConfig.apiKeyExpirationDate = Expiration.after(Duration.days(apiKeyExpirationDaysNum)).date;

return {
authenticationType: 'API_KEY',
Expand Down Expand Up @@ -677,9 +682,10 @@ function validateDays(input) {
}

function validateIssuerUrl(input) {
const isValid = /^(((?!http:\/\/(?!localhost))([a-zA-Z0-9.]{1,}):\/\/([a-zA-Z0-9-._~:?#@!$&'()*+,;=/]{1,})\/)|(?!http)(?!https)([a-zA-Z0-9.]{1,}):\/\/)$/.test(
input,
);
const isValid =
/^(((?!http:\/\/(?!localhost))([a-zA-Z0-9.]{1,}):\/\/([a-zA-Z0-9-._~:?#@!$&'()*+,;=/]{1,})\/)|(?!http)(?!https)([a-zA-Z0-9.]{1,}):\/\/)$/.test(
input,
);

if (!isValid) {
return 'The value must be a valid URI with a trailing forward slash. HTTPS must be used instead of HTTP unless you are using localhost.';
Expand Down Expand Up @@ -779,8 +785,8 @@ const buildPolicyResource = (resourceName: string, path: string | null) => {
{
Ref: `${category}${resourceName}GraphQLAPIIdOutput`,
},
...(path ? [path] : [])
]
...(path ? [path] : []),
],
],
};
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const authConfigToAppSyncAuthTypeMap: Record<string, (authConfig: any) => AppSyn
API_KEY: authConfig => ({
mode: 'API_KEY',
expirationTime: authConfig.apiKeyConfig.apiKeyExpirationDays,
apiKeyExpirationDate: authConfig.apiKeyConfig?.apiKeyExpirationDate,
keyDescription: authConfig.apiKeyConfig.description,
}),
AWS_IAM: () => ({
Expand All @@ -54,6 +55,7 @@ const appSyncAuthTypeToAuthConfigMap: Record<string, (authType: AppSyncAuthType)
authenticationType: 'API_KEY',
apiKeyConfig: {
apiKeyExpirationDays: authType.expirationTime,
apiKeyExpirationDate: authType?.apiKeyExpirationDate,
description: authType.keyDescription,
},
}),
Expand Down
5 changes: 2 additions & 3 deletions packages/amplify-cli-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ interface AmplifyToolkit {
) => $TSAny;
sharedQuestions: () => $TSAny;
showAllHelp: () => $TSAny;
showGlobalSandboxModeWarning: (context: $TSContext) => $TSAny;
showHelp: (header: string, commands: { name: string; description: string }[]) => $TSAny;
showHelpfulProviderLinks: (context: $TSContext) => $TSAny;
showResourceTable: () => $TSAny;
Expand Down Expand Up @@ -310,9 +311,7 @@ interface AmplifyToolkit {
leaveBreadcrumbs: (category: string, resourceName: string, breadcrumbs: unknown) => void;
readBreadcrumbs: (category: string, resourceName: string) => $TSAny;
loadRuntimePlugin: (context: $TSContext, pluginId: string) => Promise<$TSAny>;
getImportedAuthProperties: (
context: $TSContext,
) => {
getImportedAuthProperties: (context: $TSContext) => {
imported: boolean;
userPoolId?: string;
authRoleArn?: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import fs from 'fs';
import { getAppSyncApiConfig, getApiKeyConfig, apiKeyIsActive, hasApiKey } from '../../../extensions/amplify-helpers/api-key';
import { stateManager } from 'amplify-cli-core';

jest.mock('amplify-cli-core', () => {
const original = jest.requireActual('amplify-cli-core');
const amplifyMeta = fs.readFileSync(`${__dirname}/testData/mockLocalCloud/amplify-meta.json`);
return {
...original,
stateManager: {
metaFileExists: jest.fn(),
getMeta: jest.fn().mockImplementation(() => JSON.parse(amplifyMeta.toString())),
},
};
});

const stateManager_mock = stateManager as jest.Mocked<typeof stateManager>;

describe('getAppSyncApiConfig', () => {
it('returns the api object', async () => {
const result = getAppSyncApiConfig();

expect(result).toStrictEqual({
service: 'AppSync',
providerPlugin: 'awscloudformation',
output: {
authConfig: {
defaultAuthentication: {
authenticationType: 'AWS_IAM',
},
additionalAuthenticationProviders: [
{
authenticationType: 'API_KEY',
apiKeyConfig: {
apiKeyExpirationDays: 2,
apiKeyExpirationDate: '2021-08-20T20:38:07.585Z',
description: '',
},
},
],
},
globalSandboxModeConfig: {
dev: {
enabled: true,
},
},
},
});
});
});

describe('getApiKeyConfig', () => {
it('returns the api key config', () => {
const result = getApiKeyConfig();

expect(result).toStrictEqual({
apiKeyExpirationDays: 2,
apiKeyExpirationDate: '2021-08-20T20:38:07.585Z',
description: '',
});
});
});

describe('apiKeyIsActive', () => {
it('returns true if api key is active', () => {
const result = apiKeyIsActive();

expect(result).toBe(false);
});
});

describe('hasApiKey', () => {
it('returns true if api key is present', () => {
const result = hasApiKey();

expect(result).toBe(true);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import {
globalSandboxModeEnabled,
showGlobalSandboxModeWarning,
} from '../../../extensions/amplify-helpers/show-global-sandbox-mode-warning';
import { $TSContext } from '../../../../../amplify-cli-core/lib';
import fs from 'fs';
import chalk from 'chalk';

let ctx, amplifyMeta;

jest.mock('amplify-cli-core', () => ({
stateManager: {
getMeta: jest.fn(() => JSON.parse(amplifyMeta.toString())),
},
}));

describe('global sandbox mode warning', () => {
beforeEach(() => {
const envName = 'dev';
ctx = {
amplify: {
getEnvInfo() {
return { envName };
},
},
print: {
info() {
// noop
},
},
} as unknown as $TSContext;
});

describe('globalSandboxModeEnabled', () => {
describe('enabled', () => {
it('returns true', async () => {
amplifyMeta = fs.readFileSync(`${__dirname}/testData/mockLocalCloud/amplify-meta.json`);
expect(globalSandboxModeEnabled(ctx)).toBe(true);
});
});

describe('not specified', () => {
it('returns false', async () => {
amplifyMeta = fs.readFileSync(`${__dirname}/testData/mockLocalCloud/amplify-meta-2.json`);
expect(globalSandboxModeEnabled(ctx)).toBe(false);
});
});
});

describe('showGlobalSandboxModeWarning', () => {
it('prints warning message', async () => {
amplifyMeta = fs.readFileSync(`${__dirname}/testData/mockLocalCloud/amplify-meta.json`);

jest.spyOn(ctx.print, 'info');

await showGlobalSandboxModeWarning(ctx);

expect(ctx.print.info).toBeCalledWith(`
⚠️ WARNING: ${chalk.green('"type AMPLIFY_GLOBAL @allow_public_data_access_with_api_key"')} in your GraphQL schema
allows public create, read, update, and delete access to all models via API Key. This
should only be used for testing purposes. API Key expiration date is: 8/20/2021
To configure PRODUCTION-READY authorization rules, review: https://docs.amplify.aws/cli/graphql-transformer/auth
`);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"api": {
"ampapp": {
"service": "AppSync",
"providerPlugin": "awscloudformation",
"output": {
"authConfig": {
"defaultAuthentication": {
"authenticationType": "AWS_IAM"
},
"additionalAuthenticationProviders": [
{
"authenticationType": "API_KEY",
"apiKeyConfig": {
"apiKeyExpirationDays": 2,
"apiKeyExpirationDate": "2021-08-20T20:38:07.585Z",
"description": ""
}
}
]
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"api": {
"ampapp": {
"service": "AppSync",
"providerPlugin": "awscloudformation",
"output": {
"authConfig": {
"defaultAuthentication": {
"authenticationType": "AWS_IAM"
},
"additionalAuthenticationProviders": [
{
"authenticationType": "API_KEY",
"apiKeyConfig": {
"apiKeyExpirationDays": 2,
"apiKeyExpirationDate": "2021-08-20T20:38:07.585Z",
"description": ""
}
}
]
},
"globalSandboxModeConfig": {
"dev": {
"enabled": true
}
}
}
}
}
}
26 changes: 14 additions & 12 deletions packages/amplify-cli/src/commands/status.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
import { ViewResourceTableParams, CLIParams, $TSContext } from "amplify-cli-core";
import { ViewResourceTableParams, CLIParams, $TSContext } from 'amplify-cli-core';

export const run = async (context: $TSContext) => {
const cliParams: CLIParams = {
cliCommand: context?.input?.command,
cliSubcommands: context?.input?.subCommands,
cliOptions: context?.input?.options,
};

export const run = async (context : $TSContext) => {
const cliParams:CLIParams = { cliCommand : context?.input?.command,
cliSubcommands: context?.input?.subCommands,
cliOptions : context?.input?.options }

const view = new ViewResourceTableParams( cliParams );
if ( context?.input?.subCommands?.includes("help")){
context.print.info( view.getStyledHelp() );
const view = new ViewResourceTableParams(cliParams);
if (context?.input?.subCommands?.includes('help')) {
context.print.info(view.getStyledHelp());
} else {
try {
await context.amplify.showStatusTable( view );
await context.amplify.showStatusTable(view);
await context.amplify.showGlobalSandboxModeWarning(context);
await context.amplify.showHelpfulProviderLinks(context);
await showAmplifyConsoleHostingStatus(context);
} catch ( e ){
} catch (e) {
view.logErrorException(e, context);
}
}
};

async function showAmplifyConsoleHostingStatus( context) {
async function showAmplifyConsoleHostingStatus(context) {
const pluginInfo = context.amplify.getCategoryPluginInfo(context, 'hosting', 'amplifyhosting');
if (pluginInfo && pluginInfo.packageLocation) {
const { status } = await import(pluginInfo.packageLocation);
Expand Down
10 changes: 8 additions & 2 deletions packages/amplify-cli/src/domain/amplify-toolkit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export class AmplifyToolkit {
private _removeResource: any;
private _sharedQuestions: any;
private _showAllHelp: any;
private _showGlobalSandboxModeWarning: any;
private _showHelp: any;
private _showHelpfulProviderLinks: any;
private _showResourceTable: any;
Expand Down Expand Up @@ -240,6 +241,12 @@ export class AmplifyToolkit {
this._sharedQuestions = this._sharedQuestions || require(path.join(this._amplifyHelpersDirPath, 'shared-questions')).sharedQuestions;
return this._sharedQuestions;
}
get showGlobalSandboxModeWarning(): any {
this._showGlobalSandboxModeWarning =
this._showGlobalSandboxModeWarning ||
require(path.join(this._amplifyHelpersDirPath, 'show-global-sandbox-mode-warning')).showGlobalSandboxModeWarning;
return this._showGlobalSandboxModeWarning;
}
get showHelp(): any {
this._showHelp = this._showHelp || require(path.join(this._amplifyHelpersDirPath, 'show-help')).showHelp;
return this._showHelp;
Expand All @@ -261,8 +268,7 @@ export class AmplifyToolkit {
}

get showStatusTable(): any {
this._showStatusTable =
this._showStatusTable || require(path.join(this._amplifyHelpersDirPath, 'resource-status')).showStatusTable;
this._showStatusTable = this._showStatusTable || require(path.join(this._amplifyHelpersDirPath, 'resource-status')).showStatusTable;
return this._showStatusTable;
}

Expand Down
Loading

0 comments on commit 2c0f74a

Please sign in to comment.