@aws/nx-plugin 0.1.6 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/LICENSE-THIRD-PARTY +1554 -3241
  2. package/generators.json +1 -13
  3. package/package.json +14 -14
  4. package/src/cloudscape-website/app/README.md +84 -48
  5. package/src/cloudscape-website/app/__snapshots__/generator.spec.ts.snap +168 -233
  6. package/src/cloudscape-website/app/files/app/README.md.template +44 -0
  7. package/src/cloudscape-website/app/files/app/src/layouts/App/index.tsx.template +40 -43
  8. package/src/cloudscape-website/app/files/app/src/layouts/App/navitems.ts.template +3 -3
  9. package/src/cloudscape-website/app/files/app/src/layouts/Routes/index.tsx.template +4 -6
  10. package/src/cloudscape-website/app/files/app/src/main.tsx.template +7 -10
  11. package/src/cloudscape-website/app/files/app/src/pages/Home/index.tsx.template +0 -2
  12. package/src/cloudscape-website/app/files/common/constructs/src/app/static-websites/__websiteNameKebabCase__.ts.template +13 -0
  13. package/src/cloudscape-website/app/files/common/constructs/src/{__websiteNameKebabCase__ → core}/static-website.ts.template +79 -144
  14. package/src/cloudscape-website/app/generator.js +90 -74
  15. package/src/cloudscape-website/app/generator.js.map +1 -1
  16. package/src/cloudscape-website/app/schema.d.ts +3 -5
  17. package/src/cloudscape-website/app/schema.json +1 -24
  18. package/src/cloudscape-website/cognito-auth/README.md +53 -32
  19. package/src/cloudscape-website/cognito-auth/__snapshots__/generator.spec.ts.snap +162 -124
  20. package/src/cloudscape-website/cognito-auth/files/app/components/CognitoAuth/index.tsx.template +53 -39
  21. package/src/cloudscape-website/cognito-auth/files/common/constructs/src/core/user-identity.ts.template +168 -0
  22. package/src/cloudscape-website/cognito-auth/generator.js +130 -47
  23. package/src/cloudscape-website/cognito-auth/generator.js.map +1 -1
  24. package/src/cloudscape-website/cognito-auth/schema.d.ts +1 -0
  25. package/src/cloudscape-website/cognito-auth/schema.json +7 -1
  26. package/src/cloudscape-website/runtime-config/__snapshots__/generator.spec.ts.snap +20 -15
  27. package/src/cloudscape-website/runtime-config/files/app/components/RuntimeConfig/index.tsx.template +7 -10
  28. package/src/cloudscape-website/runtime-config/files/app/hooks/useRuntimeConfig.tsx.template +13 -0
  29. package/src/cloudscape-website/runtime-config/generator.js +4 -2
  30. package/src/cloudscape-website/runtime-config/generator.js.map +1 -1
  31. package/src/infra/app/README.md +71 -46
  32. package/src/infra/app/__snapshots__/generator.spec.ts.snap +184 -305
  33. package/src/infra/app/files/app/README.md.template +76 -0
  34. package/src/infra/app/files/app/src/main.ts.template +18 -0
  35. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/aws-prototyping.guard +1282 -0
  36. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/cfn-nag.guard +6839 -0
  37. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/hipaa-security.guard +2807 -0
  38. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/nist-csf.guard +2585 -0
  39. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/pci-dss-3-2-1.guard +2236 -0
  40. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/wa-reliability-pillar.guard +885 -0
  41. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/wa-security-pillar.guard +2205 -0
  42. package/src/infra/app/files/common/constructs/src/core/cfn-guard.ts.template +63 -0
  43. package/src/infra/app/generator.js +36 -7
  44. package/src/infra/app/generator.js.map +1 -1
  45. package/src/infra/app/schema.d.ts +10 -1
  46. package/src/infra/app/schema.json +16 -8
  47. package/src/trpc/backend/README.md +102 -80
  48. package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +42 -19
  49. package/src/trpc/backend/files/backend/README.md.template +33 -0
  50. package/src/trpc/backend/files/common/constructs/src/app/trpc-apis/__apiNameKebabCase__.ts.template +18 -0
  51. package/src/trpc/backend/files/common/constructs/src/{__apiNameKebabCase__/index.ts.template → core/trpc-api.ts.template} +12 -16
  52. package/src/trpc/backend/files/schema/README.md.template +33 -0
  53. package/src/trpc/backend/generator.js +30 -44
  54. package/src/trpc/backend/generator.js.map +1 -1
  55. package/src/trpc/backend/schema.d.ts +3 -1
  56. package/src/trpc/backend/schema.json +8 -13
  57. package/src/trpc/react/README.md +46 -66
  58. package/src/trpc/react/__snapshots__/generator.spec.ts.snap +104 -65
  59. package/src/trpc/react/files/src/components/TrpcClients/IsolatedTrpcProvider.tsx.template +75 -0
  60. package/src/trpc/react/files/src/components/TrpcClients/TrpcApis.tsx.template +1 -0
  61. package/src/trpc/react/files/src/components/TrpcClients/TrpcClientProviders.tsx.template +10 -0
  62. package/src/trpc/react/files/src/components/TrpcClients/index.tsx.template +5 -0
  63. package/src/trpc/react/files/src/hooks/useSigV4.tsx.template +38 -0
  64. package/src/trpc/react/files/src/hooks/use__apiNameClassName__.tsx.template +3 -0
  65. package/src/trpc/react/generator.js +124 -25
  66. package/src/trpc/react/generator.js.map +1 -1
  67. package/src/trpc/react/schema.json +2 -2
  68. package/src/ts/lib/__snapshots__/generator.spec.ts.snap +47 -93
  69. package/src/ts/lib/eslint.d.ts +1 -2
  70. package/src/ts/lib/eslint.js +62 -21
  71. package/src/ts/lib/eslint.js.map +1 -1
  72. package/src/ts/lib/files/README.md.template +33 -0
  73. package/src/ts/lib/generator.js +44 -5
  74. package/src/ts/lib/generator.js.map +1 -1
  75. package/src/ts/lib/schema.d.ts +1 -4
  76. package/src/ts/lib/schema.json +2 -21
  77. package/src/ts/lib/ts-project-utils.js +3 -18
  78. package/src/ts/lib/ts-project-utils.js.map +1 -1
  79. package/src/ts/lib/vitest.js +12 -0
  80. package/src/ts/lib/vitest.js.map +1 -1
  81. package/src/utils/ast.d.ts +13 -0
  82. package/src/utils/ast.js +102 -0
  83. package/src/utils/ast.js.map +1 -0
  84. package/src/utils/files/common/constructs/src/app/index.ts.template +0 -0
  85. package/src/utils/files/common/constructs/src/{runtime-config → core}/runtime-config.ts.template +3 -5
  86. package/src/utils/files/common/constructs/src/index.ts.template +2 -1
  87. package/src/utils/files/common/readme/README.md.template +33 -0
  88. package/src/utils/files/common/types/src/runtime-config.ts.template +2 -13
  89. package/src/utils/format.d.ts +1 -1
  90. package/src/utils/format.js +2 -2
  91. package/src/utils/format.js.map +1 -1
  92. package/src/utils/names.d.ts +2 -0
  93. package/src/utils/names.js +27 -0
  94. package/src/utils/names.js.map +1 -0
  95. package/src/utils/npm-scope.js.map +1 -1
  96. package/src/utils/paths.js.map +1 -1
  97. package/src/utils/shared-constructs.js +37 -4
  98. package/src/utils/shared-constructs.js.map +1 -1
  99. package/src/utils/test.d.ts +2 -0
  100. package/src/utils/test.js +19 -0
  101. package/src/utils/test.js.map +1 -0
  102. package/src/utils/versions.d.ts +15 -9
  103. package/src/utils/versions.js +14 -8
  104. package/src/utils/versions.js.map +1 -1
  105. package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/cloudfront-web-acl.ts.template +0 -317
  106. package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/index.ts.template +0 -4
  107. package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/webacl_event_handler/index.ts.template +0 -301
  108. package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/index.ts.template +0 -4
  109. package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/user-identity.ts.template +0 -66
  110. package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/userpool-with-mfa.ts.template +0 -70
  111. package/src/gitlab/generator.d.ts +0 -8
  112. package/src/gitlab/generator.js +0 -16
  113. package/src/gitlab/generator.js.map +0 -1
  114. package/src/gitlab/schema.d.ts +0 -9
  115. package/src/gitlab/schema.json +0 -52
  116. package/src/infra/app/files/src/main.ts.template +0 -37
  117. package/src/trpc/react/files/src/components/TRPCClientProvider/index.tsx.template +0 -34
  118. package/src/trpc/react/files/src/hooks/useTrpc.tsx.template +0 -5
  119. package/src/ts/cjs-to-esm/generator.d.ts +0 -12
  120. package/src/ts/cjs-to-esm/generator.js +0 -189
  121. package/src/ts/cjs-to-esm/generator.js.map +0 -1
  122. package/src/ts/cjs-to-esm/schema.d.ts +0 -9
  123. package/src/ts/cjs-to-esm/schema.json +0 -28
  124. /package/src/infra/app/files/{cdk.json → app/cdk.json} +0 -0
  125. /package/src/infra/app/files/{src → app/src}/stacks/application-stack.ts.template +0 -0
  126. /package/src/utils/files/common/constructs/src/{runtime-config → core}/index.ts.template +0 -0
@@ -1,8 +1,3 @@
1
- /*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
2
- SPDX-License-Identifier: Apache-2.0 */
3
- import { useCognitoAuthContext } from '@aws-northstar/ui';
4
- import getBreadcrumbs from '@aws-northstar/ui/components/AppLayout/utils/getBreadcrumbs';
5
- import NavHeader from '@aws-northstar/ui/components/AppLayout/components/NavHeader';
6
1
  import * as React from 'react';
7
2
  import { createContext, useCallback, useEffect, useState } from 'react';
8
3
  import { NavItems } from './navitems';
@@ -13,11 +8,42 @@ import {
13
8
  BreadcrumbGroup,
14
9
  BreadcrumbGroupProps,
15
10
  SideNavigation,
11
+ TopNavigation,
16
12
  } from '@cloudscape-design/components';
17
13
  import AppLayout, {
18
14
  AppLayoutProps,
19
15
  } from '@cloudscape-design/components/app-layout';
20
- import { useLocation, useNavigate } from 'react-router-dom';
16
+ import { matchPath, useLocation, useNavigate } from 'react-router-dom';
17
+
18
+ const getBreadcrumbs = (
19
+ pathName: string,
20
+ search: string,
21
+ defaultBreadcrumb: string,
22
+ availableRoutes?: string[]
23
+ ) => {
24
+ const segments = [
25
+ defaultBreadcrumb,
26
+ ...pathName.split('/').filter((segment) => segment !== ''),
27
+ ];
28
+
29
+ return segments.map((segment, i) => {
30
+ const href =
31
+ i === 0
32
+ ? '/'
33
+ : `/${segments
34
+ .slice(1, i + 1)
35
+ .join('/')
36
+ .replace('//', '/')}`;
37
+
38
+ const matched =
39
+ !availableRoutes || availableRoutes.find((r) => matchPath(r, href));
40
+
41
+ return {
42
+ href: matched ? `${href}${search}` : '#',
43
+ text: segment,
44
+ };
45
+ });
46
+ };
21
47
 
22
48
  /**
23
49
  * Context for updating/retrieving the AppLayout.
@@ -32,10 +58,6 @@ export const AppLayoutContext = createContext({
32
58
  * Defines the App layout and contains logic for routing.
33
59
  */
34
60
  const App: React.FC = () => {
35
- const [username, setUsername] = useState<string | undefined>();
36
- const [email, setEmail] = useState<string | undefined>();
37
- const { getAuthenticatedUser } = useCognitoAuthContext();
38
-
39
61
  const navigate = useNavigate();
40
62
  const [activeHref, setActiveHref] = useState('/');
41
63
  const [activeBreadcrumbs, setActiveBreadcrumbs] = useState<
@@ -44,17 +66,6 @@ const App: React.FC = () => {
44
66
  const [appLayoutProps, setAppLayoutProps] = useState<AppLayoutProps>({});
45
67
  const location = useLocation();
46
68
 
47
- useEffect(() => {
48
- const authUser = getAuthenticatedUser();
49
- setUsername(authUser?.getUsername());
50
-
51
- authUser?.getSession(() => {
52
- authUser.getUserAttributes((_, attributes) => {
53
- setEmail(attributes?.find((a) => a.Name === 'email')?.Value);
54
- });
55
- });
56
- }, [getAuthenticatedUser, setUsername, setEmail]);
57
-
58
69
  const setAppLayoutPropsSafe = useCallback(
59
70
  (props: AppLayoutProps) => {
60
71
  JSON.stringify(appLayoutProps) !== JSON.stringify(props) &&
@@ -75,9 +86,6 @@ const App: React.FC = () => {
75
86
  e.preventDefault();
76
87
  setAppLayoutPropsSafe({
77
88
  contentType: undefined,
78
- splitPanelOpen: false,
79
- splitPanelSize: undefined,
80
- splitPanelPreferences: undefined,
81
89
  });
82
90
  navigate(e.detail.href);
83
91
  }
@@ -89,23 +97,14 @@ const App: React.FC = () => {
89
97
  <AppLayoutContext.Provider
90
98
  value={{ appLayoutProps, setAppLayoutProps: setAppLayoutPropsSafe }}
91
99
  >
92
- <NavHeader
93
- title={Config.applicationName}
94
- logo={Config.logo}
95
- user={
96
- username
97
- ? {
98
- username,
99
- email,
100
- }
101
- : undefined
102
- }
103
- onSignout={() =>
104
- new Promise(() => {
105
- getAuthenticatedUser()?.signOut();
106
- window.location.href = '/';
107
- })
108
- }
100
+ <TopNavigation
101
+ identity={{
102
+ href: '/',
103
+ title: Config.applicationName,
104
+ logo: {
105
+ src: Config.logo,
106
+ },
107
+ }}
109
108
  />
110
109
  <AppLayout
111
110
  breadcrumbs={
@@ -121,8 +120,6 @@ const App: React.FC = () => {
121
120
  />
122
121
  }
123
122
  content={<Routes />}
124
- splitPanelOpen={false}
125
- splitPanelPreferences={{ position: 'bottom' }}
126
123
  {...appLayoutProps}
127
124
  />
128
125
  </AppLayoutContext.Provider>
@@ -1,8 +1,8 @@
1
- import { SideNavigationProps } from "@cloudscape-design/components";
1
+ import { SideNavigationProps } from '@cloudscape-design/components';
2
2
 
3
3
  /**
4
4
  * Define your Navigation Items here
5
5
  */
6
6
  export const NavItems: SideNavigationProps.Item[] = [
7
- { text: "Home", type: "link", href: "/" }
8
- ];
7
+ { text: 'Home', type: 'link', href: '/' },
8
+ ];
@@ -1,8 +1,6 @@
1
- /*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
2
- SPDX-License-Identifier: Apache-2.0 */
3
- import * as React from "react";
4
- import { Route, Routes as ReactRoutes } from "react-router-dom";
5
- import Home from "../../pages/Home";
1
+ import * as React from 'react';
2
+ import { Route, Routes as ReactRoutes } from 'react-router-dom';
3
+ import Home from '../../pages/Home';
6
4
 
7
5
  /**
8
6
  * Defines the Routes.
@@ -15,4 +13,4 @@ const Routes: React.FC = () => {
15
13
  );
16
14
  };
17
15
 
18
- export default Routes;
16
+ export default Routes;
@@ -1,6 +1,3 @@
1
- /*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
2
- SPDX-License-Identifier: Apache-2.0 */
3
- import { NorthStarThemeProvider } from '@aws-northstar/ui';
4
1
  import React from 'react';
5
2
  import { createRoot } from 'react-dom/client';
6
3
  import { BrowserRouter } from 'react-router-dom';
@@ -8,16 +5,16 @@ import { I18nProvider } from '@cloudscape-design/components/i18n';
8
5
  import messages from '@cloudscape-design/components/i18n/messages/all.en';
9
6
  import App from './layouts/App';
10
7
 
8
+ import '@cloudscape-design/global-styles/index.css';
9
+
11
10
  const root = document.getElementById('root');
12
11
  root &&
13
12
  createRoot(root).render(
14
13
  <React.StrictMode>
15
- <NorthStarThemeProvider>
16
- <I18nProvider locale="en" messages={[messages]}>
17
- <BrowserRouter>
18
- <App />
19
- </BrowserRouter>
20
- </I18nProvider>
21
- </NorthStarThemeProvider>
14
+ <I18nProvider locale="en" messages={[messages]}>
15
+ <BrowserRouter>
16
+ <App />
17
+ </BrowserRouter>
18
+ </I18nProvider>
22
19
  </React.StrictMode>
23
20
  );
@@ -1,5 +1,3 @@
1
- /*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
2
- SPDX-License-Identifier: Apache-2.0 */
3
1
  import {
4
2
  Container,
5
3
  ContentLayout,
@@ -0,0 +1,13 @@
1
+ import * as url from 'url';
2
+ import { Construct } from 'constructs';
3
+ import { StaticWebsite } from '../../core/index.js';
4
+
5
+ export class <%= websiteNameClassName %> extends StaticWebsite {
6
+ constructor(scope: Construct, id: string) {
7
+ super(scope, id, {
8
+ websiteFilePath: url.fileURLToPath(
9
+ new URL('../../../../../../<%= websiteContentPath %>', import.meta.url)
10
+ ),
11
+ });
12
+ }
13
+ }
@@ -1,8 +1,4 @@
1
- /*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
2
- SPDX-License-Identifier: Apache-2.0 */
3
- import * as url from 'url';
4
- import { PDKNag } from '@aws/pdk/pdk-nag';
5
- import { CfnJson, CfnOutput, Lazy, RemovalPolicy, Stack, Token } from 'aws-cdk-lib';
1
+ import { CfnJson, CfnOutput, RemovalPolicy, Stack, Token } from 'aws-cdk-lib';
6
2
  import { Distribution, ViewerProtocolPolicy } from 'aws-cdk-lib/aws-cloudfront';
7
3
  import { S3BucketOrigin } from 'aws-cdk-lib/aws-cloudfront-origins';
8
4
  import {
@@ -13,13 +9,16 @@ import {
13
9
  ObjectOwnership,
14
10
  } from 'aws-cdk-lib/aws-s3';
15
11
  import { BucketDeployment, Source } from 'aws-cdk-lib/aws-s3-deployment';
16
- import { NagSuppressions } from 'cdk-nag';
17
12
  import { Construct } from 'constructs';
18
- import { CloudfrontWebAcl } from './cloudfront-web-acl.js';
19
- import { RuntimeConfig } from '../runtime-config/index.js';
20
-
13
+ import { RuntimeConfig } from './runtime-config.js';
14
+ import { Key } from 'aws-cdk-lib/aws-kms';
15
+ import { CfnWebACL } from 'aws-cdk-lib/aws-wafv2';
21
16
  const DEFAULT_RUNTIME_CONFIG_FILENAME = 'runtime-config.json';
22
17
 
18
+ export interface StaticWebsiteProps {
19
+ readonly websiteFilePath: string;
20
+ }
21
+
23
22
  /**
24
23
  * Deploys a Static Website using by default a private S3 bucket as an origin and Cloudfront as the entrypoint.
25
24
  *
@@ -33,61 +32,68 @@ export class StaticWebsite extends Construct {
33
32
  public readonly cloudFrontDistribution: Distribution;
34
33
  public readonly bucketDeployment: BucketDeployment;
35
34
 
36
- constructor(scope: Construct, id: string) {
35
+ constructor(
36
+ scope: Construct,
37
+ id: string,
38
+ { websiteFilePath }: StaticWebsiteProps
39
+ ) {
37
40
  super(scope, id);
38
-
39
41
  this.node.setContext(
40
42
  '@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy',
41
43
  true
42
44
  );
43
45
 
46
+ const websiteKey = new Key(this, 'WebsiteKey', {
47
+ enableKeyRotation: true,
48
+ });
49
+
44
50
  const accessLogsBucket = new Bucket(this, 'AccessLogsBucket', {
45
51
  versioned: false,
46
52
  enforceSSL: true,
47
53
  autoDeleteObjects: true,
48
54
  removalPolicy: RemovalPolicy.DESTROY,
49
- encryption: BucketEncryption.S3_MANAGED,
55
+ encryption: BucketEncryption.KMS,
56
+ encryptionKey: websiteKey,
50
57
  objectOwnership: ObjectOwnership.OBJECT_WRITER,
51
58
  publicReadAccess: false,
52
59
  blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
53
60
  });
54
-
55
61
  // S3 Bucket to hold website files
56
62
  this.websiteBucket = new Bucket(this, 'WebsiteBucket', {
57
63
  versioned: true,
58
64
  enforceSSL: true,
59
65
  autoDeleteObjects: true,
60
66
  removalPolicy: RemovalPolicy.DESTROY,
61
- encryption: BucketEncryption.S3_MANAGED,
67
+ encryption: BucketEncryption.KMS,
68
+ encryptionKey: websiteKey,
62
69
  objectOwnership: ObjectOwnership.BUCKET_OWNER_ENFORCED,
63
70
  publicReadAccess: false,
64
71
  blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
65
72
  serverAccessLogsPrefix: 'website-access-logs',
66
73
  serverAccessLogsBucket: accessLogsBucket,
67
74
  });
68
-
69
75
  // Web ACL
70
- const webAclArn = new CloudfrontWebAcl(this, 'WebsiteAcl').webAclArn;
76
+ const wafStack = new CloudfrontWebAcl(this, 'waf');
71
77
 
72
78
  // Cloudfront Distribution
73
79
  const logBucket = new Bucket(this, 'DistributionLogBucket', {
74
80
  enforceSSL: true,
75
81
  autoDeleteObjects: true,
76
82
  removalPolicy: RemovalPolicy.DESTROY,
77
- encryption: BucketEncryption.S3_MANAGED,
83
+ encryption: BucketEncryption.KMS,
84
+ encryptionKey: websiteKey,
78
85
  objectOwnership: ObjectOwnership.BUCKET_OWNER_PREFERRED,
79
86
  publicReadAccess: false,
80
87
  blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
81
88
  serverAccessLogsPrefix: 'distribution-access-logs',
82
89
  serverAccessLogsBucket: accessLogsBucket,
83
90
  });
84
-
85
91
  const defaultRootObject = 'index.html';
86
92
  this.cloudFrontDistribution = new Distribution(
87
93
  this,
88
94
  'CloudfrontDistribution',
89
95
  {
90
- webAclId: webAclArn,
96
+ webAclId: wafStack.wafArn,
91
97
  enableLogging: true,
92
98
  logBucket: logBucket,
93
99
  defaultBehavior: {
@@ -101,48 +107,42 @@ export class StaticWebsite extends Construct {
101
107
  responseHttpStatus: 200,
102
108
  responsePagePath: `/${defaultRootObject}`,
103
109
  },
110
+ {
111
+ httpStatus: 403, // We need to redirect reloads from paths (e.g. /foo/bar) to index.html for single page apps
112
+ responseHttpStatus: 200,
113
+ responsePagePath: `/${defaultRootObject}`,
114
+ },
104
115
  ],
105
116
  }
106
117
  );
107
-
108
118
  // Deploy Website
109
- const runtimeConfig = RuntimeConfig.ensure(this).config;
110
119
  this.bucketDeployment = new BucketDeployment(this, 'WebsiteDeployment', {
111
120
  sources: [
112
- Source.asset(
113
- url.fileURLToPath(
114
- new URL('../../../../../<%= websiteContentPath %>', import.meta.url)
115
- )
121
+ Source.asset(websiteFilePath),
122
+ Source.jsonData(
123
+ DEFAULT_RUNTIME_CONFIG_FILENAME,
124
+ this.resolveTokens(RuntimeConfig.ensure(this).config)
116
125
  ),
117
- ...(Object.keys(runtimeConfig).length > 0
118
- ? [Source.jsonData(DEFAULT_RUNTIME_CONFIG_FILENAME, this.lazilyRender(runtimeConfig))]
119
- : []),
120
126
  ],
121
127
  destinationBucket: this.websiteBucket,
122
128
  // Files in the distribution's edge caches will be invalidated after files are uploaded to the destination bucket.
123
129
  distribution: this.cloudFrontDistribution,
124
130
  });
125
-
126
131
  new CfnOutput(this, 'DistributionDomainName', {
127
132
  value: this.cloudFrontDistribution.domainName,
128
133
  });
129
-
130
- this.suppressCDKNagViolations();
131
134
  }
132
-
133
- private lazilyRender = (payload: any) => Lazy.any({
134
- produce: () => this.resolveTokens(payload),
135
- });
136
-
137
135
  private resolveTokens = (payload: any) => {
138
136
  const _payload: Record<string, any> = {};
139
-
140
137
  Object.entries(payload).forEach(([key, value]) => {
141
- if (Token.isUnresolved(value) || (typeof value === "string" && value.endsWith("}}"))) {
138
+ if (
139
+ Token.isUnresolved(value) ||
140
+ (typeof value === 'string' && value.endsWith('}}'))
141
+ ) {
142
142
  _payload[key] = new CfnJson(this, `ResolveToken-${key}`, {
143
- value,
143
+ value,
144
144
  }).value;
145
- } else if (typeof value === "object") {
145
+ } else if (typeof value === 'object') {
146
146
  _payload[key] = this.resolveTokens(value);
147
147
  } else if (Array.isArray(value)) {
148
148
  _payload[key] = value.map((v) => this.resolveTokens(v));
@@ -150,114 +150,49 @@ export class StaticWebsite extends Construct {
150
150
  _payload[key] = value;
151
151
  }
152
152
  });
153
-
154
153
  return _payload;
155
- }
154
+ };
155
+ }
156
156
 
157
- private suppressCDKNagViolations = () => {
158
- const stack = Stack.of(this);
157
+ export class CloudfrontWebAcl extends Stack {
158
+ public readonly wafArn;
159
+ constructor(scope: Construct, id: string) {
160
+ super(scope, id, {
161
+ env: {
162
+ region: 'us-east-1',
163
+ account: Stack.of(scope).account,
164
+ },
165
+ crossRegionReferences: true,
166
+ });
159
167
 
160
- NagSuppressions.addResourceSuppressions(
161
- this,
162
- [
168
+ this.wafArn = new CfnWebACL(this, 'WebAcl', {
169
+ defaultAction: { allow: {} },
170
+ scope: 'CLOUDFRONT',
171
+ visibilityConfig: {
172
+ cloudWatchMetricsEnabled: true,
173
+ metricName: id,
174
+ sampledRequestsEnabled: true,
175
+ },
176
+ rules: [
163
177
  {
164
- id: 'AwsPrototyping-CloudFrontDistributionGeoRestrictions',
165
- reason:
166
- 'Suppressed to allow unrestricted access. Not recommended in production.',
178
+ name: 'CRSRule',
179
+ priority: 0,
180
+ statement: {
181
+ managedRuleGroupStatement: {
182
+ name: 'AWSManagedRulesCommonRuleSet',
183
+ vendorName: 'AWS',
184
+ },
185
+ },
186
+ visibilityConfig: {
187
+ cloudWatchMetricsEnabled: true,
188
+ metricName: 'MetricForWebACLCDK-CRS',
189
+ sampledRequestsEnabled: true,
190
+ },
191
+ overrideAction: {
192
+ none: {},
193
+ },
167
194
  },
168
195
  ],
169
- true
170
- );
171
-
172
- [
173
- 'AwsSolutions-CFR4',
174
- 'AwsPrototyping-CloudFrontDistributionHttpsViewerNoOutdatedSSL',
175
- ].forEach((RuleId) => {
176
- NagSuppressions.addResourceSuppressions(this.cloudFrontDistribution, [
177
- {
178
- id: RuleId,
179
- reason:
180
- 'Certificate is not mandatory therefore the Cloudfront certificate will be used.',
181
- },
182
- ]);
183
- });
184
-
185
- ['AwsSolutions-L1', 'AwsPrototyping-LambdaLatestVersion'].forEach(
186
- (RuleId) => {
187
- NagSuppressions.addResourceSuppressions(
188
- this,
189
- [
190
- {
191
- id: RuleId,
192
- reason:
193
- 'Latest runtime cannot be configured. CDK will need to upgrade the BucketDeployment construct accordingly.',
194
- },
195
- ],
196
- true
197
- );
198
- }
199
- );
200
-
201
- ['AwsSolutions-IAM5', 'AwsPrototyping-IAMNoWildcardPermissions'].forEach(
202
- (RuleId) => {
203
- NagSuppressions.addResourceSuppressions(
204
- this,
205
- [
206
- {
207
- id: RuleId,
208
- reason:
209
- 'All Policies have been scoped to a Bucket. Given Buckets can contain arbitrary content, wildcard resources with bucket scope are required.',
210
- appliesTo: [
211
- {
212
- regex: '/^Action::s3:.*$/g',
213
- },
214
- {
215
- regex: `/^Resource::.*$/g`,
216
- },
217
- ],
218
- },
219
- ],
220
- true
221
- );
222
- }
223
- );
224
-
225
- ['AwsSolutions-IAM4', 'AwsPrototyping-IAMNoManagedPolicies'].forEach(
226
- (RuleId) => {
227
- NagSuppressions.addResourceSuppressions(
228
- this,
229
- [
230
- {
231
- id: RuleId,
232
- reason:
233
- 'Buckets can contain arbitrary content, therefore wildcard resources under a bucket are required.',
234
- appliesTo: [
235
- {
236
- regex: `/^Policy::arn:${PDKNag.getStackPartitionRegex(
237
- stack
238
- )}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole$/g`,
239
- },
240
- ],
241
- },
242
- ],
243
- true
244
- );
245
- }
246
- );
247
-
248
- ['AwsSolutions-S1', 'AwsPrototyping-S3BucketLoggingEnabled'].forEach(
249
- (RuleId) => {
250
- NagSuppressions.addResourceSuppressions(
251
- this,
252
- [
253
- {
254
- id: RuleId,
255
- reason: 'Access Log buckets should not have s3 bucket logging',
256
- },
257
- ],
258
- true
259
- );
260
- }
261
- );
262
- };
196
+ }).attrArn;
197
+ }
263
198
  }