@fjall/components-infrastructure 32.0.0 → 33.1.0

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 (88) hide show
  1. package/README.md +15 -76
  2. package/dist/lib/app.d.ts +1 -1
  3. package/dist/lib/config/audit.js +2 -1
  4. package/dist/lib/config/aws/identityCentreConfig.d.ts +1 -1
  5. package/dist/lib/config/aws/identityCentreConfig.js +1 -1
  6. package/dist/lib/config/aws/scpPreset.js +1 -2
  7. package/dist/lib/lambda-assets/cert-generator/asset/index.js +126 -0
  8. package/dist/lib/patterns/aws/buildkite/buildkite.d.ts +1 -1
  9. package/dist/lib/patterns/aws/buildkite/buildkite.js +1 -1
  10. package/dist/lib/patterns/aws/buildkite/factory.d.ts +2 -2
  11. package/dist/lib/patterns/aws/buildkite/pins.d.ts +2 -2
  12. package/dist/lib/patterns/aws/buildkite/pins.js +3 -4
  13. package/dist/lib/patterns/aws/buildkite/schema.d.ts +1 -1
  14. package/dist/lib/patterns/aws/buildkite/schema.js +1 -1
  15. package/dist/lib/patterns/aws/buildkite/userData.d.ts +1 -1
  16. package/dist/lib/patterns/aws/buildkite/userData.js +1 -1
  17. package/dist/lib/patterns/aws/buildkite.d.ts +1 -1
  18. package/dist/lib/patterns/aws/buildkite.js +1 -1
  19. package/dist/lib/patterns/aws/cdn.d.ts +14 -0
  20. package/dist/lib/patterns/aws/cdn.js +31 -3
  21. package/dist/lib/patterns/aws/clickhouseDatabase.d.ts +8 -0
  22. package/dist/lib/patterns/aws/clickhouseDatabase.js +19 -3
  23. package/dist/lib/patterns/aws/clickhouseTls/types.d.ts +1 -1
  24. package/dist/lib/patterns/aws/compute.js +4 -2
  25. package/dist/lib/patterns/aws/computeEcs.d.ts +7 -0
  26. package/dist/lib/patterns/aws/computeEcs.js +26 -3
  27. package/dist/lib/patterns/aws/computeEcsTypes.d.ts +30 -7
  28. package/dist/lib/patterns/aws/computeLambda.d.ts +12 -0
  29. package/dist/lib/patterns/aws/computeLambda.js +2 -0
  30. package/dist/lib/patterns/aws/computePropApplicability.js +2 -0
  31. package/dist/lib/patterns/aws/database.d.ts +14 -0
  32. package/dist/lib/patterns/aws/database.js +16 -6
  33. package/dist/lib/patterns/aws/interfaces/pattern.d.ts +6 -6
  34. package/dist/lib/patterns/aws/messaging.js +4 -1
  35. package/dist/lib/patterns/aws/patternDomain.d.ts +1 -1
  36. package/dist/lib/patterns/aws/patternDomain.js +1 -1
  37. package/dist/lib/patterns/aws/payload.js +7 -5
  38. package/dist/lib/patterns/aws/staticSite.d.ts +6 -6
  39. package/dist/lib/patterns/aws/staticSite.js +9 -6
  40. package/dist/lib/patterns/aws/storage.d.ts +8 -0
  41. package/dist/lib/patterns/aws/storage.js +1 -0
  42. package/dist/lib/resources/aws/cdn/cloudFront.d.ts +2 -0
  43. package/dist/lib/resources/aws/cdn/cloudFront.js +1 -0
  44. package/dist/lib/resources/aws/cdn/responseHeadersPolicy.d.ts +1 -1
  45. package/dist/lib/resources/aws/cdn/responseHeadersPolicy.js +1 -1
  46. package/dist/lib/resources/aws/compute/applicationLoadBalancer.d.ts +10 -0
  47. package/dist/lib/resources/aws/compute/applicationLoadBalancer.js +7 -1
  48. package/dist/lib/resources/aws/compute/ec2.d.ts +2 -2
  49. package/dist/lib/resources/aws/compute/ec2.js +1 -1
  50. package/dist/lib/resources/aws/compute/ecs.d.ts +11 -0
  51. package/dist/lib/resources/aws/compute/ecs.js +51 -6
  52. package/dist/lib/resources/aws/compute/ecsContext.d.ts +10 -1
  53. package/dist/lib/resources/aws/compute/ecsNetworking.js +3 -1
  54. package/dist/lib/resources/aws/compute/ecsTaskDefinition.js +4 -1
  55. package/dist/lib/resources/aws/compute/ecsTypes.d.ts +31 -8
  56. package/dist/lib/resources/aws/compute/lambda.d.ts +18 -1
  57. package/dist/lib/resources/aws/compute/lambda.js +21 -3
  58. package/dist/lib/resources/aws/database/clickhouseConstants.d.ts +5 -5
  59. package/dist/lib/resources/aws/database/clickhouseConstants.js +5 -5
  60. package/dist/lib/resources/aws/database/dynamodb.d.ts +19 -0
  61. package/dist/lib/resources/aws/database/dynamodb.js +13 -2
  62. package/dist/lib/resources/aws/database/rdsAurora.d.ts +11 -0
  63. package/dist/lib/resources/aws/database/rdsAurora.js +24 -3
  64. package/dist/lib/resources/aws/database/rdsAuroraGlobal.d.ts +11 -1
  65. package/dist/lib/resources/aws/database/rdsAuroraGlobal.js +1 -0
  66. package/dist/lib/resources/aws/database/rdsDefaults.d.ts +0 -2
  67. package/dist/lib/resources/aws/database/rdsDefaults.js +0 -2
  68. package/dist/lib/resources/aws/database/rdsInstance.d.ts +11 -0
  69. package/dist/lib/resources/aws/database/rdsInstance.js +19 -4
  70. package/dist/lib/resources/aws/iam/identityCenter/user.d.ts +1 -1
  71. package/dist/lib/resources/aws/iam/identityCenter/user.js +1 -1
  72. package/dist/lib/resources/aws/logging/accessLogBucket.d.ts +22 -0
  73. package/dist/lib/resources/aws/logging/accessLogBucket.js +41 -0
  74. package/dist/lib/resources/aws/logging/index.d.ts +1 -0
  75. package/dist/lib/resources/aws/logging/index.js +1 -0
  76. package/dist/lib/resources/aws/messaging/sns.d.ts +14 -5
  77. package/dist/lib/resources/aws/messaging/sns.js +7 -1
  78. package/dist/lib/resources/aws/secrets/index.d.ts +1 -0
  79. package/dist/lib/resources/aws/secrets/index.js +1 -0
  80. package/dist/lib/resources/aws/secrets/stackEncryptionKey.d.ts +47 -0
  81. package/dist/lib/resources/aws/secrets/stackEncryptionKey.js +114 -0
  82. package/dist/lib/resources/aws/storage/bucketDeployment.d.ts +2 -3
  83. package/dist/lib/resources/aws/storage/bucketDeployment.js +2 -3
  84. package/dist/lib/resources/aws/storage/s3.d.ts +13 -1
  85. package/dist/lib/resources/aws/storage/s3.js +6 -3
  86. package/dist/lib/utils/backupTierMapping.d.ts +10 -2
  87. package/dist/lib/utils/backupTierMapping.js +3 -1
  88. package/package.json +5 -4
package/README.md CHANGED
@@ -54,84 +54,23 @@ for each of the two secrets.
54
54
 
55
55
  ## Useful commands
56
56
 
57
- - `npm run build` compile typescript to js
58
- - `npm run watch` watch for changes and compile
59
- - `npm run test` perform the jest unit tests
60
- - `cdk deploy` deploy this stack to your default AWS account/region
61
- - `cdk diff` compare deployed stack with current state
62
- - `cdk synth` emits the synthesized CloudFormation template
57
+ - `npm run build` — clean, bundle the Lambda assets and compile TypeScript to `dist/`
58
+ - `npm run watch` — recompile on change
59
+ - `npm test` — run the Vitest suites
60
+ - `npm run typecheck` — type-check the library
63
61
 
64
- ## Building patterns
62
+ Synthesis and deployment go through the `fjall` CLI (`fjall deploy`), which
63
+ assembles the stacks from an application's `fjall/` directory. The package is
64
+ not deployed with `cdk deploy` on its own.
65
65
 
66
- Common service patterns are built using a Stack class (i.e AwsStack) and use a builder pattern.
66
+ ## Using the constructs
67
67
 
68
- ### Referencing VPC
68
+ The constructs are consumed through the `fjall` CLI: `fjall create app` and
69
+ `fjall add <resource>` write the `infrastructure.ts` that composes them, and
70
+ `fjall deploy` synthesises and deploys it. Every construct is also exported
71
+ from the package root for direct use; the reference lives at
72
+ [docs.fjall.io](https://docs.fjall.io).
69
73
 
70
- There are three main ways to reference a VPC
74
+ ## Licence
71
75
 
72
- 1. In the same stack
73
-
74
- When a VPC is created in the same stack resources that rely on it will automatically detect it.
75
-
76
- ```typescript
77
- new AwsStack(`${id}App`)
78
- .addNetwork(FjallVpc.build(`${id}Vpc`))
79
- .addConstruct(Fargate.build(`${id}Fargate`));
80
- ```
81
-
82
- 2. In the same CDK Application but different stack
83
-
84
- When a VPC is created in the same application, but you want to use separate stacks, you can directly reference the vpc resource itself. This is easily
85
- retrieved from an awsStack using `awsStack.getNetwork()`.
86
-
87
- ```typescript
88
- const vpcStack = new AwsStack(`${id}Network`).addNetwork(
89
- FjallVpc.build(`${id}Vpc`)
90
- );
91
-
92
- const newStack = new AwsStack(`${id}Compute`, { dependencies: [vpcStack] })
93
- .addNetwork(vpcStack.getNetwork())
94
- .addConstruct(Fargate.build(`${id}Fargate`));
95
- ```
96
-
97
- 3. Different CDK Applications
98
-
99
- If your VPC was created in a completely separate CDK Stack it can be imported using it's `id` and `stackName`. However this method
100
- requires you explicitly configure your `AwsStack` with an `account` and `region.
101
-
102
- ```typescript
103
- const env = {
104
- region: "us-east-1",
105
- account: "058430617814"
106
- };
107
-
108
- const vpcStack = new AwsStack(`${id}Network`, { ...env }).addNetwork(
109
- FjallVpc.build(`${id}Vpc`)
110
- );
111
-
112
- const newStack = new AwsStack(`${id}Compute`, {
113
- ...env,
114
- dependencies: [vpcStack]
115
- })
116
- .addNetwork(FjallVpc.import(`${id}Vpc`, `${id}Network`))
117
- .addConstruct(Fargate.build(`${id}Fargate`));
118
- ```
119
-
120
- ## Publishing package to npm
121
-
122
- Log into your NPM account locally (make sure you have 2fa setup before trying this)
123
-
124
- ```
125
- npm login
126
- > Username:
127
- > Password
128
- > Email
129
- > 2Fa
130
- ```
131
-
132
- Update the version in ./package.json, build the package and then run publish command
133
-
134
- ```
135
- npm run build
136
- npm publish --access restricted
137
- ```
76
+ Proprietary — see [LICENSE](./LICENSE).
package/dist/lib/app.d.ts CHANGED
@@ -311,7 +311,7 @@ export declare class App extends CdkApp {
311
311
  addDevSubstrate(props: IDevSubstrateProps): DevSubstrate;
312
312
  /**
313
313
  * Instantiate the self-hosted Buildkite agent fleet on the default compute
314
- * stack (design `aiDocs/designs/2026-07-18-buildkite-selfhosted-agents.md`).
314
+ * stack (design: the 2026-07-18 Buildkite self-hosted agents design).
315
315
  *
316
316
  * Same placement contract as `addDevSubstrate` above: deploy-core selects
317
317
  * stacks by the fixed six-category enum, so scoping under
@@ -1,3 +1,4 @@
1
+ import { FJALL_PLATFORM_ACCOUNT_ID } from "./aws/platform.js";
1
2
  /**
2
3
  * Audit configuration for cross-account CloudQuery access
3
4
  */
@@ -6,7 +7,7 @@ export const FJALL_AUDIT_CONFIG = {
6
7
  * Fjall webapp AWS account ID
7
8
  * This account will be granted permission to assume audit roles for CloudQuery
8
9
  */
9
- webappAwsAccountId: "985539798308", // Fjall platform account
10
+ webappAwsAccountId: FJALL_PLATFORM_ACCOUNT_ID,
10
11
  /**
11
12
  * IAM role naming convention
12
13
  */
@@ -4,7 +4,7 @@ import { type DefaultPermissionSetName } from "@fjall/generator";
4
4
  * construct. The discriminated union on `source` mirrors AWS ground truth:
5
5
  * the identity source of an Identity Center instance is neither readable nor
6
6
  * settable via any supported API, so the mode is user-declared and
7
- * authoritative. Design: aiDocs/designs/2026-07-04-org-user-management-design.md
7
+ * authoritative. Design: the 2026-07-04 organisation user-management design.
8
8
  *
9
9
  * The source vocabulary is canonical in @fjall/generator
10
10
  * (organisationSchemas.ts) — re-exported here so existing consumers keep
@@ -5,7 +5,7 @@ import { stripAndCamelCase } from "../../utils/stripAndCamelCase.js";
5
5
  * construct. The discriminated union on `source` mirrors AWS ground truth:
6
6
  * the identity source of an Identity Center instance is neither readable nor
7
7
  * settable via any supported API, so the mode is user-declared and
8
- * authoritative. Design: aiDocs/designs/2026-07-04-org-user-management-design.md
8
+ * authoritative. Design: the 2026-07-04 organisation user-management design.
9
9
  *
10
10
  * The source vocabulary is canonical in @fjall/generator
11
11
  * (organisationSchemas.ts) — re-exported here so existing consumers keep
@@ -140,8 +140,7 @@ function buildFoundationGuardrails(allowedRegions) {
140
140
  // assume-root sessions) are deliberately NOT carved out — recovery on
141
141
  // this tier is a break-glass SCP detach, not a standing carve-out. Do
142
142
  // not add them without revisiting the decision:
143
- // aiDocs/troubleshooting/centralised-root-access-break-glass-runbook.md
144
- // § Scenario 3.
143
+ // the centralised root-access break-glass runbook, § Scenario 3.
145
144
  NotAction: [
146
145
  "s3:GetBucketPolicy",
147
146
  "s3:PutBucketPolicy",
@@ -18117,3 +18117,129 @@ exports.handler = async (event) => {
18117
18117
  Data: { CaCertSha256: caCertSha256 }
18118
18118
  };
18119
18119
  };
18120
+ /*! Bundled license information:
18121
+
18122
+ reflect-metadata/Reflect.js:
18123
+ (*! *****************************************************************************
18124
+ Copyright (C) Microsoft. All rights reserved.
18125
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use
18126
+ this file except in compliance with the License. You may obtain a copy of the
18127
+ License at http://www.apache.org/licenses/LICENSE-2.0
18128
+
18129
+ THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18130
+ KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
18131
+ WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
18132
+ MERCHANTABLITY OR NON-INFRINGEMENT.
18133
+
18134
+ See the Apache Version 2.0 License for specific language governing permissions
18135
+ and limitations under the License.
18136
+ ***************************************************************************** *)
18137
+
18138
+ pvtsutils/build/index.js:
18139
+ (*!
18140
+ * MIT License
18141
+ *
18142
+ * Copyright (c) 2017-2024 Peculiar Ventures, LLC
18143
+ *
18144
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
18145
+ * of this software and associated documentation files (the "Software"), to deal
18146
+ * in the Software without restriction, including without limitation the rights
18147
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18148
+ * copies of the Software, and to permit persons to whom the Software is
18149
+ * furnished to do so, subject to the following conditions:
18150
+ *
18151
+ * The above copyright notice and this permission notice shall be included in all
18152
+ * copies or substantial portions of the Software.
18153
+ *
18154
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18155
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18156
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18157
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18158
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18159
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
18160
+ * SOFTWARE.
18161
+ *
18162
+ *)
18163
+
18164
+ pvutils/build/utils.js:
18165
+ (*!
18166
+ Copyright (c) Peculiar Ventures, LLC
18167
+ *)
18168
+
18169
+ asn1js/build/index.js:
18170
+ (*!
18171
+ * Copyright (c) 2014, GMO GlobalSign
18172
+ * Copyright (c) 2015-2022, Peculiar Ventures
18173
+ * All rights reserved.
18174
+ *
18175
+ * Author 2014-2019, Yury Strozhevsky
18176
+ *
18177
+ * Redistribution and use in source and binary forms, with or without modification,
18178
+ * are permitted provided that the following conditions are met:
18179
+ *
18180
+ * * Redistributions of source code must retain the above copyright notice, this
18181
+ * list of conditions and the following disclaimer.
18182
+ *
18183
+ * * Redistributions in binary form must reproduce the above copyright notice, this
18184
+ * list of conditions and the following disclaimer in the documentation and/or
18185
+ * other materials provided with the distribution.
18186
+ *
18187
+ * * Neither the name of the copyright holder nor the names of its
18188
+ * contributors may be used to endorse or promote products derived from
18189
+ * this software without specific prior written permission.
18190
+ *
18191
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18192
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18193
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18194
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
18195
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18196
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18197
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
18198
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
18199
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
18200
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18201
+ *
18202
+ *)
18203
+
18204
+ tslib/tslib.es6.js:
18205
+ (*! *****************************************************************************
18206
+ Copyright (c) Microsoft Corporation.
18207
+
18208
+ Permission to use, copy, modify, and/or distribute this software for any
18209
+ purpose with or without fee is hereby granted.
18210
+
18211
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
18212
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18213
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
18214
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
18215
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
18216
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
18217
+ PERFORMANCE OF THIS SOFTWARE.
18218
+ ***************************************************************************** *)
18219
+
18220
+ @peculiar/x509/build/x509.cjs.js:
18221
+ (*!
18222
+ * MIT License
18223
+ *
18224
+ * Copyright (c) Peculiar Ventures. All rights reserved.
18225
+ *
18226
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
18227
+ * of this software and associated documentation files (the "Software"), to deal
18228
+ * in the Software without restriction, including without limitation the rights
18229
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18230
+ * copies of the Software, and to permit persons to whom the Software is
18231
+ * furnished to do so, subject to the following conditions:
18232
+ *
18233
+ * The above copyright notice and this permission notice shall be included in all
18234
+ * copies or substantial portions of the Software.
18235
+ *
18236
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18237
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18238
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18239
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18240
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18241
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
18242
+ * SOFTWARE.
18243
+ *
18244
+ *)
18245
+ */
@@ -14,7 +14,7 @@ export type BuildkiteConstructProps = BuildkitePropsInput & {
14
14
  * Self-hosted Buildkite agent fleet on the pinned Elastic CI Stack AMIs —
15
15
  * scale-to-zero ASG + buildkite-agent-scaler, no secret ever transiting
16
16
  * synth, allowlist-only instance IAM. Design:
17
- * `aiDocs/designs/2026-07-18-buildkite-selfhosted-agents.md`.
17
+ * the 2026-07-18 Buildkite self-hosted agents design.
18
18
  *
19
19
  * A Construct, not a Stack: instantiate via `App.addBuildkite(props)`, which
20
20
  * scopes it under the default compute stack so deploy-core's fixed
@@ -21,7 +21,7 @@ import { buildBuildkiteUserData } from "./userData.js";
21
21
  * Self-hosted Buildkite agent fleet on the pinned Elastic CI Stack AMIs —
22
22
  * scale-to-zero ASG + buildkite-agent-scaler, no secret ever transiting
23
23
  * synth, allowlist-only instance IAM. Design:
24
- * `aiDocs/designs/2026-07-18-buildkite-selfhosted-agents.md`.
24
+ * the 2026-07-18 Buildkite self-hosted agents design.
25
25
  *
26
26
  * A Construct, not a Stack: instantiate via `App.addBuildkite(props)`, which
27
27
  * scopes it under the default compute stack so deploy-core's fixed
@@ -5,8 +5,8 @@ import type { BuildkitePropsInput } from "./schema.js";
5
5
  /**
6
6
  * Thunk returned by `BuildkiteFactory.build` — materialised only by
7
7
  * `App.addBuildkite`, which owns stack placement (the fleet has exactly one
8
- * legal home, `${stackPrefix}Compute`; design
9
- * `aiDocs/designs/2026-07-18-fjall-add-buildkite.md` § D2).
8
+ * legal home, `${stackPrefix}Compute`; design:
9
+ * the 2026-07-18 `fjall add buildkite` design, § D2).
10
10
  */
11
11
  export type BuildkiteFactoryFn = (app: App, scope: Construct) => Buildkite;
12
12
  /**
@@ -4,7 +4,7 @@
4
4
  * release. AMI ids, the elastic-stack version, the scaler version and the
5
5
  * secrets-plugin floor MUST only change together, regenerated from the
6
6
  * upstream template for the new version (runbook:
7
- * `aiDocs/runbooks/buildkite-stack-bump-runbook.md`).
7
+ * the Buildkite stack-bump runbook).
8
8
  *
9
9
  * AMI ids come from the `Mappings.AWSRegion2AMI` block of
10
10
  * `https://s3.amazonaws.com/buildkite-aws-stack/<version>/aws-stack.yml` and
@@ -18,7 +18,7 @@
18
18
  * floats the AMI underneath a pinned stack version, needs lookup credentials
19
19
  * at synth time (unavailable in worker synth), and makes synth
20
20
  * non-deterministic. Design:
21
- * `aiDocs/designs/2026-07-18-buildkite-selfhosted-agents.md` § D2.
21
+ * the 2026-07-18 Buildkite self-hosted agents design, § D2.
22
22
  */
23
23
  export declare const BUILDKITE_AMI_OWNER_ACCOUNT_ID = "172840064832";
24
24
  export declare const BUILDKITE_CPU_ARCHITECTURES: readonly ["arm64", "amd64"];
@@ -4,7 +4,7 @@
4
4
  * release. AMI ids, the elastic-stack version, the scaler version and the
5
5
  * secrets-plugin floor MUST only change together, regenerated from the
6
6
  * upstream template for the new version (runbook:
7
- * `aiDocs/runbooks/buildkite-stack-bump-runbook.md`).
7
+ * the Buildkite stack-bump runbook).
8
8
  *
9
9
  * AMI ids come from the `Mappings.AWSRegion2AMI` block of
10
10
  * `https://s3.amazonaws.com/buildkite-aws-stack/<version>/aws-stack.yml` and
@@ -18,7 +18,7 @@
18
18
  * floats the AMI underneath a pinned stack version, needs lookup credentials
19
19
  * at synth time (unavailable in worker synth), and makes synth
20
20
  * non-deterministic. Design:
21
- * `aiDocs/designs/2026-07-18-buildkite-selfhosted-agents.md` § D2.
21
+ * the 2026-07-18 Buildkite self-hosted agents design, § D2.
22
22
  */
23
23
  export const BUILDKITE_AMI_OWNER_ACCOUNT_ID = "172840064832";
24
24
  export const BUILDKITE_CPU_ARCHITECTURES = ["arm64", "amd64"];
@@ -69,8 +69,7 @@ export function resolvePinnedAmiId(region, architecture) {
69
69
  if (!isSupportedRegion(region)) {
70
70
  throw new Error(`Buildkite: no pinned AMI for region '${region}'. Supported: ` +
71
71
  `${Object.keys(BUILDKITE_STACK_PINS.amiIdsByRegion).join(", ")}. ` +
72
- `Add the region to BUILDKITE_STACK_PINS via the bump runbook ` +
73
- `(aiDocs/runbooks/buildkite-stack-bump-runbook.md).`);
72
+ `Add the region to BUILDKITE_STACK_PINS.`);
74
73
  }
75
74
  return BUILDKITE_STACK_PINS.amiIdsByRegion[region][architecture];
76
75
  }
@@ -2,7 +2,7 @@
2
2
  * Buildkite props schema — re-export barrel. The canonical declaration lives
3
3
  * in `@fjall/generator` (`src/schemas/buildkiteSchemas.ts`) so construct
4
4
  * validation, the codemod fragment, and the LLM JSON schema all consume one
5
- * source (design `aiDocs/designs/2026-07-18-fjall-add-buildkite.md` § D4).
5
+ * source (design: the 2026-07-18 `fjall add buildkite` design, § D4).
6
6
  * Do NOT redeclare here — the cross-package reference-identity test pins it.
7
7
  */
8
8
  export { BuildkitePropsObjectSchema, BuildkitePropsSchema, validateBuildkiteProps, type BuildkiteProps, type BuildkitePropsInput, type BuildkitePropsObject } from "@fjall/generator";
@@ -2,7 +2,7 @@
2
2
  * Buildkite props schema — re-export barrel. The canonical declaration lives
3
3
  * in `@fjall/generator` (`src/schemas/buildkiteSchemas.ts`) so construct
4
4
  * validation, the codemod fragment, and the LLM JSON schema all consume one
5
- * source (design `aiDocs/designs/2026-07-18-fjall-add-buildkite.md` § D4).
5
+ * source (design: the 2026-07-18 `fjall add buildkite` design, § D4).
6
6
  * Do NOT redeclare here — the cross-package reference-identity test pins it.
7
7
  */
8
8
  export { BuildkitePropsObjectSchema, BuildkitePropsSchema, validateBuildkiteProps } from "@fjall/generator";
@@ -29,7 +29,7 @@ export interface BuildkiteUserDataContext {
29
29
  * vendored template in both directions: a key we emit that upstream does not
30
30
  * pass is silently ignored; a key upstream passes that we omit is the
31
31
  * boot-loop. Bumping the pins regenerates the fixture
32
- * (runbook: `aiDocs/runbooks/buildkite-stack-bump-runbook.md`).
32
+ * (runbook: the Buildkite stack-bump runbook).
33
33
  */
34
34
  export declare const BUILDKITE_MOUNT_PART_ENV_KEYS: readonly ["BUILDKITE_ENABLE_INSTANCE_STORAGE", "BUILDKITE_MOUNT_TMPFS_AT_TMP"];
35
35
  export declare const BUILDKITE_DOCKER_PART_ENV_KEYS: readonly ["DOCKER_USERNS_REMAP", "DOCKER_EXPERIMENTAL", "DOCKER_PRUNE_UNTIL", "ENABLE_PRE_EXIT_DISK_CLEANUP", "DOCKER_BUILDER_PRUNE_ENABLED", "DOCKER_NETWORKING_PROTOCOL", "DOCKER_IPV4_ADDRESS_POOL_1", "DOCKER_IPV4_ADDRESS_POOL_2", "DOCKER_IPV6_ADDRESS_POOL", "DOCKER_FIXED_CIDR_V4", "DOCKER_FIXED_CIDR_V6", "BUILDKITE_ENABLE_INSTANCE_STORAGE"];
@@ -10,7 +10,7 @@ import { BUILDKITE_STACK_PINS } from "./pins.js";
10
10
  * vendored template in both directions: a key we emit that upstream does not
11
11
  * pass is silently ignored; a key upstream passes that we omit is the
12
12
  * boot-loop. Bumping the pins regenerates the fixture
13
- * (runbook: `aiDocs/runbooks/buildkite-stack-bump-runbook.md`).
13
+ * (runbook: the Buildkite stack-bump runbook).
14
14
  */
15
15
  export const BUILDKITE_MOUNT_PART_ENV_KEYS = [
16
16
  "BUILDKITE_ENABLE_INSTANCE_STORAGE",
@@ -2,7 +2,7 @@
2
2
  * Self-hosted Buildkite agent fleet — barrel for the `buildkite/` modules.
3
3
  * The pre-2026-07 `Buildkite extends Stack` implementation is replaced by a
4
4
  * Construct instantiated via `App.addBuildkite()`; design:
5
- * `aiDocs/designs/2026-07-18-buildkite-selfhosted-agents.md`.
5
+ * the 2026-07-18 Buildkite self-hosted agents design.
6
6
  */
7
7
  export { AGENT_TOKEN_SECRET_NAME, BUILDKITE_SECRETS_CLUSTER, Buildkite, FJALL_API_KEY_SECRET_NAME, FJALL_ENV_HOOK_OBJECT_KEY, buildAgentSecretsEnvHookScript, type AgentSecretsEnvHookOptions, type BuildkiteConstructProps } from "./buildkite/buildkite.js";
8
8
  export { BUILDKITE_AMI_OWNER_ACCOUNT_ID, BUILDKITE_CPU_ARCHITECTURES, BUILDKITE_STACK_PINS, resolvePinnedAmiId, resolveScalerSarApplicationArn, type BuildkiteCpuArchitecture } from "./buildkite/pins.js";
@@ -2,7 +2,7 @@
2
2
  * Self-hosted Buildkite agent fleet — barrel for the `buildkite/` modules.
3
3
  * The pre-2026-07 `Buildkite extends Stack` implementation is replaced by a
4
4
  * Construct instantiated via `App.addBuildkite()`; design:
5
- * `aiDocs/designs/2026-07-18-buildkite-selfhosted-agents.md`.
5
+ * the 2026-07-18 Buildkite self-hosted agents design.
6
6
  */
7
7
  export { AGENT_TOKEN_SECRET_NAME, BUILDKITE_SECRETS_CLUSTER, Buildkite, FJALL_API_KEY_SECRET_NAME, FJALL_ENV_HOOK_OBJECT_KEY, buildAgentSecretsEnvHookScript } from "./buildkite/buildkite.js";
8
8
  export { BUILDKITE_AMI_OWNER_ACCOUNT_ID, BUILDKITE_CPU_ARCHITECTURES, BUILDKITE_STACK_PINS, resolvePinnedAmiId, resolveScalerSarApplicationArn } from "./buildkite/pins.js";
@@ -7,6 +7,7 @@ import type App from "../../app.js";
7
7
  import { CloudFrontDistribution, type CachePolicyPreset, type AccessGateConfig } from "../../resources/aws/cdn/index.js";
8
8
  import { type ICdn } from "./interfaces/cdn.js";
9
9
  import { type StaticSiteRouting, type CloudFrontPriceClass } from "@fjall/util";
10
+ import { type BackupTier } from "../../utils/backupTierMapping.js";
10
11
  import { type ManagedDomainBinding, type ManagedDomainExports } from "../../utils/domainTypes.js";
11
12
  import { type Storage } from "./storage.js";
12
13
  import { type AnyCompute } from "./compute.js";
@@ -81,11 +82,24 @@ interface BaseCdnProps {
81
82
  certificate?: ICertificate;
82
83
  certificateArn?: string;
83
84
  comment?: string;
85
+ /**
86
+ * Standard (S3) access logging. Default: the app backup tier's
87
+ * `cloudFrontLogging` column — enterprise logs to the stack's shared,
88
+ * lifecycle-expired access-log bucket under `cloudfront/<id>/`. Set either
89
+ * knob to take over: `enableLogging: false` opts out at any tier,
90
+ * `logBucket` delivers to a bucket of your own.
91
+ */
84
92
  enableLogging?: boolean;
85
93
  logBucket?: IBucket;
86
94
  priceClass?: CloudFrontPriceClass;
87
95
  forwardHostHeader?: boolean;
88
96
  accessGate?: false | AccessGateConfig;
97
+ /**
98
+ * The owning app's backup tier, which the logging default follows.
99
+ * `CdnFactory.build` fills it from the `App`; only set by hand for a
100
+ * directly-instantiated `Cdn`.
101
+ */
102
+ appBackupTier?: BackupTier;
89
103
  }
90
104
  /**
91
105
  * S3 origin CDN props - use with S3 bucket
@@ -3,12 +3,40 @@ import { Certificate } from "aws-cdk-lib/aws-certificatemanager";
3
3
  import { CloudFrontTarget, LoadBalancerTarget } from "aws-cdk-lib/aws-route53-targets";
4
4
  import { CloudFrontDistribution } from "../../resources/aws/cdn/index.js";
5
5
  import { AliasRecord } from "../../resources/aws/networking/index.js";
6
+ import { tierDefault } from "../../utils/backupTierMapping.js";
7
+ import { stackAccessLogBucket } from "../../resources/aws/logging/index.js";
6
8
  import { getSafeZoneName, toPascalCase } from "../../utils/capitaliseString.js";
7
9
  import { recordLabelWithin } from "../../utils/domainTypes.js";
8
10
  import { resolvePatternZone, resolvePatternCloudFrontCertificate } from "./patternDomain.js";
9
11
  import { isStorage } from "./storage.js";
10
12
  import { CdnEcsOriginResolver, cdnOriginRefusal, internalAlbMessage, normaliseDnsName } from "./cdnAppOrigin.js";
11
13
  import { isCompute, isEcsCompute, isLambdaCompute } from "./compute.js";
14
+ /**
15
+ * An explicit `enableLogging` or `logBucket` is the override and passes
16
+ * through untouched; otherwise the tier decides, and a tier-enabled CDN logs
17
+ * to the stack's shared access-log bucket under its own prefix.
18
+ */
19
+ function resolveCdnLogging(scope, id, props) {
20
+ if (props.enableLogging !== undefined || props.logBucket !== undefined) {
21
+ return {
22
+ enableLogging: props.enableLogging,
23
+ logBucket: props.logBucket,
24
+ logFilePrefix: undefined
25
+ };
26
+ }
27
+ if (!tierDefault(props.appBackupTier, "cloudFrontLogging")) {
28
+ return {
29
+ enableLogging: undefined,
30
+ logBucket: undefined,
31
+ logFilePrefix: undefined
32
+ };
33
+ }
34
+ return {
35
+ enableLogging: true,
36
+ logBucket: stackAccessLogBucket(scope),
37
+ logFilePrefix: `cloudfront/${id}/`
38
+ };
39
+ }
12
40
  /**
13
41
  * The distribution's own alias names, normalised — consumed by the
14
42
  * origin-loop guard and by the ECS origin resolver (auto-resolution excludes
@@ -458,8 +486,7 @@ export class Cdn extends CloudFrontDistribution {
458
486
  domainNames,
459
487
  certificate,
460
488
  comment: props.comment,
461
- enableLogging: props.enableLogging,
462
- logBucket: props.logBucket,
489
+ ...resolveCdnLogging(scope, id, props),
463
490
  priceClass: props.priceClass,
464
491
  forwardHostHeader: props.forwardHostHeader ?? impliedForwardHostHeader,
465
492
  accessGate: props.accessGate,
@@ -676,7 +703,8 @@ export class CdnFactory {
676
703
  return new Cdn(scope, id, {
677
704
  ...props,
678
705
  appName: props.appName ?? app.getName(),
679
- app: props.app ?? app
706
+ app: props.app ?? app,
707
+ appBackupTier: props.appBackupTier ?? app.getBackupTier()
680
708
  });
681
709
  };
682
710
  }
@@ -3,6 +3,7 @@ import { type TaskDefinition } from "aws-cdk-lib/aws-ecs";
3
3
  import { type IBucket } from "aws-cdk-lib/aws-s3";
4
4
  import { Construct } from "constructs";
5
5
  import { Secret, type SecretImport } from "../../resources/aws/secrets/secret.js";
6
+ import { type BackupTier } from "../../utils/backupTierMapping.js";
6
7
  import { type ClickHouseAlarmThresholds } from "../../resources/aws/monitoring/index.js";
7
8
  import { type ClickHouseSchemaAdmin, type ProfileSpec } from "../../resources/aws/database/clickhouseSchemas.js";
8
9
  import { type ISecret } from "aws-cdk-lib/aws-secretsmanager";
@@ -283,6 +284,13 @@ export interface ClickHouseDatabaseProps {
283
284
  * RDS branch of `DatabaseFactory.build`.
284
285
  */
285
286
  applicationId?: string;
287
+ /**
288
+ * The owning app's backup tier, which the tier-owned defaults of the
289
+ * compute this pattern builds (Container Insights, exec-session and
290
+ * log-group encryption) follow. `DatabaseFactory` fills it from the App;
291
+ * pass it only for direct `new ClickHouseDatabase(...)` construction.
292
+ */
293
+ appBackupTier?: BackupTier;
286
294
  }
287
295
  /**
288
296
  * Public-facing re-export of the alarm knob so factory consumers can type
@@ -15,6 +15,8 @@ import App from "../../app.js";
15
15
  import { S3Bucket } from "../../resources/aws/storage/s3.js";
16
16
  import { Secret } from "../../resources/aws/secrets/secret.js";
17
17
  import { LogGroup } from "../../resources/aws/logging/logGroup.js";
18
+ import { StackEncryptionKey } from "../../resources/aws/secrets/stackEncryptionKey.js";
19
+ import { tierDefault } from "../../utils/backupTierMapping.js";
18
20
  import { createClickHouseSecurityGroup } from "../../resources/aws/database/clickhouseSecurityGroup.js";
19
21
  import { buildMaintenancePreamble, maintenanceOkMarker, maintenanceRun } from "../../resources/aws/database/clickhouseMaintenanceScript.js";
20
22
  import { buildClickHouseEntrypointWrapper, buildClickHouseUserData, generateUsersConfigXml } from "../../resources/aws/database/clickhouseUserData.js";
@@ -379,22 +381,33 @@ export class ClickHouseDatabase extends Construct {
379
381
  const coldTierBucket = coldTierEnabled
380
382
  ? (props.coldTierBucket ??
381
383
  new S3Bucket(this, "ClickHouseColdTierBucket", {
382
- versioned: false
384
+ // Tiered table parts, re-tiered from hot storage — versioning would
385
+ // only bill for churn; the exemption stamp tells posture so.
386
+ versioned: false,
387
+ versioningExemption: "cold-tier"
383
388
  }))
384
389
  : undefined;
385
390
  this.#backupBucket = backupBucket;
386
391
  this.#coldTierBucket = coldTierBucket;
387
392
  this.#migrationsConfig = props.migrations;
393
+ // The maintenance-task log groups sit beside the compute's own container
394
+ // and exec-audit groups and follow the same tier: the stack's shared key
395
+ // at enterprise, nothing otherwise.
396
+ const taskLogGroupEncryption = tierDefault(props.appBackupTier, "customerManagedKeys")
397
+ ? { encryptionKey: StackEncryptionKey.of(this).forLogGroups() }
398
+ : {};
388
399
  const backupTaskLogGroup = backupEnabled
389
400
  ? new LogGroup(this, "ClickHouseBackupTaskLogGroup", {
390
- retention: RetentionDays.TWO_WEEKS
401
+ retention: RetentionDays.TWO_WEEKS,
402
+ ...taskLogGroupEncryption
391
403
  })
392
404
  : undefined;
393
405
  // Explicit rather than `logRetention` so the maintenance-status metric
394
406
  // filters can attach to it alongside the backup task's group.
395
407
  const optimiseTaskLogGroup = optimiseEnabled
396
408
  ? new LogGroup(this, "ClickHouseOptimiseTaskLogGroup", {
397
- retention: RetentionDays.ONE_WEEK
409
+ retention: RetentionDays.ONE_WEEK,
410
+ ...taskLogGroupEncryption
398
411
  })
399
412
  : undefined;
400
413
  // Resolved BEFORE the user data is built: the declared volume size is
@@ -576,6 +589,9 @@ export class ClickHouseDatabase extends Construct {
576
589
  containerInsights: true
577
590
  }),
578
591
  ...(applicationId !== undefined && { applicationId }),
592
+ ...(props.appBackupTier !== undefined && {
593
+ appBackupTier: props.appBackupTier
594
+ }),
579
595
  cluster: {
580
596
  loadBalancer: false,
581
597
  securityGroup,
@@ -17,7 +17,7 @@ export interface ClickHouseSelfSignedTls {
17
17
  * supplied the construct surfaces it as a CFN env-var token so consumers
18
18
  * can wire it into containers for rotation-triggers-task-replacement
19
19
  * parity with self-signed mode. Omit it and rotation requires manual task
20
- * restart (documented in `aiDocs/patterns/clickhouse-tls-pattern.md § "Imported mode"`).
20
+ * restart (documented in the ClickHouse TLS pattern, § "Imported mode").
21
21
  */
22
22
  export interface ClickHouseImportedTls {
23
23
  readonly mode: "imported";
@@ -164,7 +164,8 @@ export class ComputeFactory {
164
164
  computeProps = {
165
165
  ...computeProps,
166
166
  appName: computeProps.appName ?? app.getName(),
167
- applicationId: computeProps.applicationId ?? app.getName()
167
+ applicationId: computeProps.applicationId ?? app.getName(),
168
+ appBackupTier: computeProps.appBackupTier ?? app.getBackupTier()
168
169
  };
169
170
  }
170
171
  // Create specific compute class based on type discriminator
@@ -241,7 +242,8 @@ export class ComputeFactory {
241
242
  // Add appName to props for Lambda (needed for secrets path derivation)
242
243
  const lambdaComputeProps = {
243
244
  ...computeProps,
244
- appName: app.getName()
245
+ appName: app.getName(),
246
+ appBackupTier: computeProps.appBackupTier ?? app.getBackupTier()
245
247
  };
246
248
  // `ecrRepository` is already defaulted to the app's shared default
247
249
  // container registry above (line ~323) when omitted — the same