@kensio/yulin 1.20.14 → 1.20.16

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 (154) hide show
  1. package/README.md +13 -0
  2. package/{dist/config/oxlint/cffjs2.oxlintrc.json → cffjs2.oxlintrc.json} +1 -1
  3. package/dist/config/oxlint/cffjs2.oxlint.config.js +4 -3
  4. package/dist/sdk/module/sim-sdk-module-client-interceptor.d.ts +5 -0
  5. package/dist/sdk/module/sim-sdk-module-client-interceptor.js +14 -0
  6. package/dist/sdk/module/sim-sdk-static-client-factory.d.ts +26 -0
  7. package/dist/sdk/module/sim-sdk-static-client-factory.js +59 -0
  8. package/dist/sdk/send-patch.d.ts +8 -0
  9. package/dist/sdk/send-patch.js +11 -0
  10. package/dist/service/aws/caller/sim-aws-caller-resolver.d.ts +28 -6
  11. package/dist/service/aws/caller/sim-aws-caller-resolver.js +18 -11
  12. package/dist/service/aws/caller/sim-aws-caller.d.ts +9 -0
  13. package/dist/service/aws/caller/sim-aws-resolved-caller.d.ts +19 -0
  14. package/dist/service/aws/caller/sim-aws-resolved-caller.js +26 -0
  15. package/dist/service/aws/factory/sim-aws-account-region-service-builder.d.ts +6 -0
  16. package/dist/service/aws/factory/sim-aws-account-region-service-builder.js +3 -0
  17. package/dist/service/aws/factory/sim-aws-account-service-cache.d.ts +6 -0
  18. package/dist/service/aws/factory/sim-aws-account-service-cache.js +5 -0
  19. package/dist/service/aws/factory/sim-aws-service-factory.d.ts +5 -0
  20. package/dist/service/aws/factory/sim-aws-service-factory.js +6 -0
  21. package/dist/service/aws/sim-aws-properties.d.ts +15 -0
  22. package/dist/service/aws/sim-aws.js +2 -1
  23. package/dist/service/cloudformation/resource/resolve/property/sim-cfn-resource-property-resolver.d.ts +11 -4
  24. package/dist/service/cloudformation/resource/resolve/property/sim-cfn-resource-property-resolver.js +21 -8
  25. package/dist/service/cloudformation/resource/sim-cfn-resource.type.d.ts +9 -0
  26. package/dist/service/cloudformation/template/dynamic/make-sim-cfn-dynamic-references.d.ts +2 -0
  27. package/dist/service/cloudformation/template/dynamic/make-sim-cfn-dynamic-references.js +2 -2
  28. package/dist/service/cloudformation/template/dynamic/sim-cfn-dynamic-reference-resolvers.d.ts +10 -0
  29. package/dist/service/cloudformation/template/dynamic/sim-cfn-dynamic-reference-resolvers.js +4 -3
  30. package/dist/service/cloudformation/template/dynamic/sim-cfn-dynamic-reference-scan.d.ts +11 -0
  31. package/dist/service/cloudformation/template/dynamic/sim-cfn-dynamic-reference-scan.js +21 -0
  32. package/dist/service/cloudformation/template/dynamic/sim-cfn-dynamic-references.d.ts +24 -2
  33. package/dist/service/cloudformation/template/dynamic/sim-cfn-dynamic-references.js +50 -11
  34. package/dist/service/cloudformation/template/dynamic/sim-cfn-prefetched-dynamic-references.d.ts +42 -0
  35. package/dist/service/cloudformation/template/dynamic/sim-cfn-prefetched-dynamic-references.js +80 -0
  36. package/dist/service/eventbridge/delivery/sim-event-bridge-delivery-failures.d.ts +16 -0
  37. package/dist/service/eventbridge/delivery/sim-event-bridge-delivery-failures.js +19 -0
  38. package/dist/service/iam/authorize/context/sim-iam-auth-z-caller-context-builder.d.ts +30 -7
  39. package/dist/service/iam/authorize/context/sim-iam-auth-z-caller-context-builder.js +20 -11
  40. package/dist/service/iam/authorize/context/sim-iam-auth-z-context-builder.d.ts +2 -1
  41. package/dist/service/iam/authorize/context/sim-iam-auth-z-context-builder.js +5 -1
  42. package/dist/service/iam/authorize/match/sim-iam-policy-principal-matcher.d.ts +10 -0
  43. package/dist/service/iam/authorize/match/sim-iam-policy-principal-matcher.js +15 -3
  44. package/dist/service/iam/authorize/sim-iam-account-auth-z.d.ts +11 -4
  45. package/dist/service/iam/authorize/sim-iam-account-auth-z.js +5 -3
  46. package/dist/service/iam/authorize/sim-iam-authorizer.d.ts +2 -1
  47. package/dist/service/iam/authorize/sim-iam-authorizer.js +1 -0
  48. package/dist/service/iam/command/policy/create-policy/create-policy-input-resolver.js +4 -1
  49. package/dist/service/iam/command/policy/put-role-policy/put-role-policy.handler.js +5 -1
  50. package/dist/service/iam/command/policy/put-user-policy/put-user-policy.handler.js +5 -1
  51. package/dist/service/iam/policy/parse/sim-iam-document-parser.d.ts +4 -1
  52. package/dist/service/iam/policy/parse/sim-iam-document-parser.js +13 -15
  53. package/dist/service/iam/policy/sim-iam-statement-label.d.ts +28 -0
  54. package/dist/service/iam/policy/sim-iam-statement-label.js +17 -0
  55. package/dist/service/iam/policy/sim-iam-statement-strings.d.ts +11 -0
  56. package/dist/service/iam/policy/sim-iam-statement-strings.js +27 -0
  57. package/dist/service/iam/role/sim-iam-role-with-policy.factory.d.ts +9 -0
  58. package/dist/service/iam/role/sim-iam-role-with-policy.factory.js +4 -2
  59. package/dist/service/iam/sim-iam-account-parts.d.ts +8 -0
  60. package/dist/service/iam/sim-iam-account-parts.js +1 -0
  61. package/dist/service/iam/validate/sim-iam-policy-document-validator.d.ts +9 -2
  62. package/dist/service/iam/validate/sim-iam-policy-document-validator.js +37 -19
  63. package/dist/service/lambda/function/code/sim-lambda-vm-zip-function.factory.d.ts +7 -0
  64. package/dist/service/lambda/function/code/sim-lambda-vm-zip-function.factory.js +1 -0
  65. package/dist/service/lambda/function/code/vm/sdk/sim-lambda-provided-sdk-module.d.ts +19 -0
  66. package/dist/service/lambda/function/code/vm/sdk/sim-lambda-provided-sdk-module.js +78 -0
  67. package/dist/service/lambda/function/code/vm/sdk/sim-lambda-sdk-packages-not-installed.error.d.ts +15 -0
  68. package/dist/service/lambda/function/code/vm/sdk/sim-lambda-sdk-packages-not-installed.error.js +27 -0
  69. package/dist/service/lambda/function/code/vm/sdk/sim-lambda-vm-sdk-module-provider.d.ts +9 -0
  70. package/dist/service/lambda/function/code/vm/sdk/sim-sdk-lambda-vm-module-provider.d.ts +10 -0
  71. package/dist/service/lambda/function/code/vm/sdk/sim-sdk-lambda-vm-module-provider.js +28 -34
  72. package/dist/service/lambda/function/code/vm/sim-lambda-host-modules.d.ts +15 -0
  73. package/dist/service/lambda/function/code/vm/sim-lambda-host-modules.js +31 -0
  74. package/dist/service/lambda/function/code/vm/sim-lambda-vm-module-resolver.d.ts +7 -0
  75. package/dist/service/lambda/function/code/vm/sim-lambda-vm-module-resolver.js +15 -0
  76. package/dist/service/lambda/function/code/vm/sim-lambda-vm-modules.js +5 -4
  77. package/dist/service/s3/command/put-bucket-policy/put-bucket-policy.handler.js +4 -1
  78. package/dist/service/scheduler/delivery/sim-scheduler-delivery-failures.d.ts +16 -0
  79. package/dist/service/scheduler/delivery/sim-scheduler-delivery-failures.js +19 -0
  80. package/dist/service/scheduler/index.d.ts +1 -1
  81. package/dist/service/scheduler/index.js +1 -1
  82. package/dist/service/secretsmanager/cfn/dynamic/sim-cfn-secrets-manager-dynamic-reference-resolver.d.ts +13 -15
  83. package/dist/service/secretsmanager/cfn/dynamic/sim-cfn-secrets-manager-dynamic-reference-resolver.js +22 -43
  84. package/dist/service/secretsmanager/cfn/dynamic/sim-cfn-secrets-manager-reference-stand-in.d.ts +9 -0
  85. package/dist/service/secretsmanager/cfn/dynamic/sim-cfn-secrets-manager-reference-stand-in.js +14 -0
  86. package/dist/service/secretsmanager/cfn/dynamic/sim-cfn-secrets-manager-reference-value.d.ts +12 -0
  87. package/dist/service/secretsmanager/cfn/dynamic/sim-cfn-secrets-manager-reference-value.js +29 -0
  88. package/dist/service/ssm/cfn/dynamic/sim-cfn-ssm-dynamic-reference-resolver.d.ts +22 -6
  89. package/dist/service/ssm/cfn/dynamic/sim-cfn-ssm-dynamic-reference-resolver.js +39 -24
  90. package/dist/service/ssm/cfn/dynamic/sim-cfn-ssm-secure-dynamic-reference-resolver.d.ts +10 -5
  91. package/dist/service/ssm/cfn/dynamic/sim-cfn-ssm-secure-dynamic-reference-resolver.js +10 -8
  92. package/dist/service/ssm/sim-ssm.d.ts +10 -2
  93. package/dist/service/ssm/sim-ssm.js +12 -4
  94. package/dist/service/sts/auth-z/assume-role-auth-z-coordinator.d.ts +9 -2
  95. package/dist/service/sts/auth-z/assume-role-auth-z-coordinator.js +2 -2
  96. package/dist/service/sts/auth-z/assume-role-source-account-auth-z.d.ts +10 -4
  97. package/dist/service/sts/auth-z/assume-role-source-account-auth-z.js +8 -7
  98. package/dist/service/sts/auth-z/assume-role-target-auth-z.d.ts +2 -2
  99. package/dist/service/sts/auth-z/assume-role-trust-policy-authorizer.d.ts +6 -2
  100. package/dist/service/sts/auth-z/assume-role-trust-policy-authorizer.js +14 -11
  101. package/dist/service/sts/command/assume-role/assume-role.handler.d.ts +5 -1
  102. package/dist/service/sts/command/assume-role/assume-role.handler.js +5 -2
  103. package/dist/service/sts/command/get-caller-identity/get-caller-identity.handler.d.ts +5 -1
  104. package/dist/service/sts/command/get-caller-identity/get-caller-identity.handler.js +4 -1
  105. package/dist/service/sts/service-role/sim-service-role.js +5 -1
  106. package/dist/service/sts/sim-sts.d.ts +9 -1
  107. package/dist/service/sts/sim-sts.js +4 -0
  108. package/docs/README.md +54 -0
  109. package/docs/ai-skill/README.md +69 -0
  110. package/docs/cli/README.md +284 -0
  111. package/docs/factories/README.md +140 -0
  112. package/docs/lint/README.md +176 -0
  113. package/docs/non-aws-dependencies/README.md +261 -0
  114. package/docs/sdk/README.md +272 -0
  115. package/docs/serve/README.md +1126 -0
  116. package/docs/services/acm/README.md +823 -0
  117. package/docs/services/apigateway/README.md +1919 -0
  118. package/docs/services/apigatewayv2/README.md +2678 -0
  119. package/docs/services/athena/README.md +1044 -0
  120. package/docs/services/bedrock/README.md +350 -0
  121. package/docs/services/cloudformation/README.md +3440 -0
  122. package/docs/services/cloudfront/README.md +2874 -0
  123. package/docs/services/cloudwatch/README.md +420 -0
  124. package/docs/services/cognito/README.md +4923 -0
  125. package/docs/services/dynamodb/README.md +3784 -0
  126. package/docs/services/ecr/README.md +302 -0
  127. package/docs/services/ecs/README.md +2010 -0
  128. package/docs/services/elbv2/README.md +1897 -0
  129. package/docs/services/eventbridge/README.md +1110 -0
  130. package/docs/services/firehose/README.md +805 -0
  131. package/docs/services/glue/README.md +501 -0
  132. package/docs/services/iam/README.md +1283 -0
  133. package/docs/services/kinesis/README.md +454 -0
  134. package/docs/services/kms/README.md +659 -0
  135. package/docs/services/lambda/README.md +3645 -0
  136. package/docs/services/logs/README.md +868 -0
  137. package/docs/services/organizations/README.md +574 -0
  138. package/docs/services/personalize/README.md +835 -0
  139. package/docs/services/rekognition/README.md +1070 -0
  140. package/docs/services/route53/README.md +1783 -0
  141. package/docs/services/s3/README.md +3024 -0
  142. package/docs/services/scheduler/README.md +806 -0
  143. package/docs/services/secretsmanager/README.md +667 -0
  144. package/docs/services/ses/README.md +1011 -0
  145. package/docs/services/sns/README.md +1904 -0
  146. package/docs/services/sqs/README.md +1185 -0
  147. package/docs/services/ssm/README.md +1072 -0
  148. package/docs/services/stepfunctions/README.md +1332 -0
  149. package/docs/services/sts/README.md +245 -0
  150. package/docs/services/wafv2/README.md +1378 -0
  151. package/docs/terraform/README.md +248 -0
  152. package/docs/time/README.md +284 -0
  153. package/llms.txt +59 -0
  154. package/package.json +9 -5
@@ -0,0 +1,823 @@
1
+ # Simulated ACM
2
+
3
+ Yulin includes a simulated AWS Certificate Manager (ACM) for tests and local development. In this
4
+ guide, you'll request certificates, configure DNS validation, filter certificate lists, and use ACM
5
+ with simulated CloudFormation.
6
+
7
+ ## Prerequisites
8
+
9
+ - Install `@kensio/yulin` in your project.
10
+ - Import ACM commands from `@aws-sdk/client-acm`.
11
+ - Import `SimAws` from `@kensio/yulin`.
12
+
13
+ ## Request a certificate
14
+
15
+ 1. Create a `SimAws` instance and get a simulated ACM client.
16
+ 2. Call `requestCertificate` with a `RequestCertificateCommand`.
17
+ 3. Call `listCertificates` with a `ListCertificatesCommand` to confirm the certificate exists.
18
+
19
+ ```typescript sim-acm-request-certificate
20
+ /**
21
+ * Requesting a simulated ACM certificate.
22
+ */
23
+
24
+ import {
25
+ ListCertificatesCommand,
26
+ RequestCertificateCommand,
27
+ } from "@aws-sdk/client-acm";
28
+
29
+ import { SimAws } from "@kensio/yulin";
30
+
31
+ const simAws = new SimAws();
32
+ const acm = simAws.account("555555555555").region("eu-west-1").acm();
33
+
34
+ const requestOutput = await acm.requestCertificate(
35
+ new RequestCertificateCommand({
36
+ DomainName: "example.test",
37
+ }),
38
+ );
39
+
40
+ console.log(requestOutput.CertificateArn);
41
+
42
+ const listOutput = await acm.listCertificates(new ListCertificatesCommand());
43
+
44
+ console.log(listOutput.CertificateSummaryList?.[0]?.DomainName);
45
+ console.log(listOutput.CertificateSummaryList?.[0]?.Status);
46
+ ```
47
+
48
+ Certificate ARNs include the selected simulated account and region, for example:
49
+
50
+ ```mermaid
51
+ flowchart LR
52
+ A["RequestCertificateCommand\n(DomainName)"] --> B["Simulated ACM"]
53
+ B --> C["Certificate ARN\narn:aws:acm:eu-west-1:555555555555:certificate/00000001"]
54
+ B --> D["Status: PENDING_VALIDATION"]
55
+ ```
56
+
57
+ ```text
58
+ arn:aws:acm:eu-west-1:555555555555:certificate/00000001
59
+ ```
60
+
61
+ You can request multiple certificates for the same domain. Each request receives a distinct ARN.
62
+
63
+ ## Add subject alternative names
64
+
65
+ Pass `SubjectAlternativeNames` when a certificate must cover more than one DNS name.
66
+
67
+ ```typescript sim-acm-subject-alternative-names
68
+ /**
69
+ * Requesting a simulated ACM certificate with subject alternative names.
70
+ */
71
+
72
+ import {
73
+ ListCertificatesCommand,
74
+ RequestCertificateCommand,
75
+ } from "@aws-sdk/client-acm";
76
+
77
+ import { SimAws } from "@kensio/yulin";
78
+
79
+ const simAws = new SimAws();
80
+ const acm = simAws.acm();
81
+
82
+ const requestOutput = await acm.requestCertificate(
83
+ new RequestCertificateCommand({
84
+ DomainName: "example.test",
85
+ SubjectAlternativeNames: ["www.example.test", "api.example.test"],
86
+ }),
87
+ );
88
+
89
+ const listOutput = await acm.listCertificates(new ListCertificatesCommand());
90
+
91
+ console.log(requestOutput.CertificateArn);
92
+ console.log(
93
+ listOutput.CertificateSummaryList?.[0]?.SubjectAlternativeNameSummaries,
94
+ );
95
+ ```
96
+
97
+ `ListCertificatesCommand` includes up to 100 subject alternative names in each summary. If a
98
+ certificate has more than 100 names, `HasAdditionalSubjectAlternativeNames` is set on the summary.
99
+
100
+ ## Describe a certificate and its validation records
101
+
102
+ Use `DescribeCertificateCommand` to inspect certificate details, including validation options.
103
+
104
+ ```typescript sim-acm-describe-certificate
105
+ /**
106
+ * Describing a simulated ACM certificate and its DNS validation records.
107
+ */
108
+
109
+ import {
110
+ DescribeCertificateCommand,
111
+ RequestCertificateCommand,
112
+ } from "@aws-sdk/client-acm";
113
+
114
+ import { SimAws } from "@kensio/yulin";
115
+
116
+ const simAws = new SimAws();
117
+ const acm = simAws.acm();
118
+
119
+ const requestOutput = await acm.requestCertificate(
120
+ new RequestCertificateCommand({
121
+ DomainName: "example.test",
122
+ SubjectAlternativeNames: ["www.example.test"],
123
+ ValidationMethod: "DNS",
124
+ }),
125
+ );
126
+
127
+ const describeOutput = await acm.describeCertificate(
128
+ new DescribeCertificateCommand({
129
+ CertificateArn: requestOutput.CertificateArn,
130
+ }),
131
+ );
132
+
133
+ const certificate = describeOutput.Certificate;
134
+
135
+ console.log(certificate?.DomainName);
136
+ console.log(certificate?.Status);
137
+
138
+ const domainValidationOptions = certificate?.DomainValidationOptions ?? [];
139
+ for (const validation of domainValidationOptions) {
140
+ console.log(validation.DomainName);
141
+ console.log(validation.ValidationMethod);
142
+ console.log(validation.ResourceRecord?.Name);
143
+ console.log(validation.ResourceRecord?.Type);
144
+ console.log(validation.ResourceRecord?.Value);
145
+ }
146
+ ```
147
+
148
+ For DNS validation, simulated ACM returns CNAME validation records for the primary domain and each
149
+ subject alternative name. The records are deterministic, which makes them suitable for assertions in
150
+ tests.
151
+
152
+ For EMAIL validation, the validation method is recorded but no DNS resource record is returned.
153
+
154
+ ```typescript sim-acm-email-validation
155
+ /**
156
+ * Requesting a simulated ACM certificate with EMAIL validation.
157
+ */
158
+
159
+ import {
160
+ DescribeCertificateCommand,
161
+ RequestCertificateCommand,
162
+ } from "@aws-sdk/client-acm";
163
+
164
+ import { SimAws } from "@kensio/yulin";
165
+
166
+ const simAws = new SimAws();
167
+ const acm = simAws.acm();
168
+
169
+ const requestOutput = await acm.requestCertificate(
170
+ new RequestCertificateCommand({
171
+ DomainName: "mail.example.test",
172
+ ValidationMethod: "EMAIL",
173
+ }),
174
+ );
175
+
176
+ const describeOutput = await acm.describeCertificate(
177
+ new DescribeCertificateCommand({
178
+ CertificateArn: requestOutput.CertificateArn,
179
+ }),
180
+ );
181
+
182
+ const validation = describeOutput.Certificate?.DomainValidationOptions?.[0];
183
+
184
+ console.log(validation?.ValidationMethod);
185
+ console.log(validation?.ResourceRecord);
186
+ ```
187
+
188
+ ## Wait for certificate issuance
189
+
190
+ Requested certificates start in `PENDING_VALIDATION` status. Simulated ACM schedules background work
191
+ to move them to `ISSUED`.
192
+
193
+ If your test needs the issued state, wait for background tasks to complete before describing the
194
+ certificate.
195
+
196
+ > **Note:** Where a simulated Route53 hosted zone covers the certificate domain, issuance waits for
197
+ > DNS validation first.
198
+ > See [Validate a certificate against simulated Route53](#validate-a-certificate-against-simulated-route53)
199
+ > below.
200
+
201
+ ```typescript sim-acm-background-issuance
202
+ /**
203
+ * Waiting for a simulated ACM certificate to be issued.
204
+ */
205
+
206
+ import {
207
+ DescribeCertificateCommand,
208
+ RequestCertificateCommand,
209
+ } from "@aws-sdk/client-acm";
210
+
211
+ import { SimAws } from "@kensio/yulin";
212
+
213
+ const simAws = new SimAws();
214
+ const acm = simAws.acm();
215
+
216
+ const requestOutput = await acm.requestCertificate(
217
+ new RequestCertificateCommand({
218
+ DomainName: "issued.example.test",
219
+ }),
220
+ );
221
+
222
+ await simAws.backgroundTasksComplete();
223
+
224
+ const describeOutput = await acm.describeCertificate(
225
+ new DescribeCertificateCommand({
226
+ CertificateArn: requestOutput.CertificateArn,
227
+ }),
228
+ );
229
+
230
+ console.log(describeOutput.Certificate?.Status);
231
+ console.log(describeOutput.Certificate?.IssuedAt);
232
+ ```
233
+
234
+ ## Validate a certificate against simulated Route53
235
+
236
+ Real ACM issues a DNS-validated certificate only once the CNAME it requests is resolvable. Simulated
237
+ ACM does the same, but only where the simulation can answer for the domain.
238
+
239
+ By default, the rules are:
240
+
241
+ - If a simulated Route53 hosted zone covers the certificate domain, the certificate waits for its validation record.
242
+ - If no hosted zone covers the domain, the certificate is issued as soon as background tasks drain.
243
+
244
+ Templates commonly reference hosted zones managed by another team or another tool. Those
245
+ certificates keep working here because the simulation holds no zone for their domain.
246
+
247
+ [Two methods override that default](#override-when-validation-is-required) where it doesn't suit
248
+ your test.
249
+
250
+ ```typescript sim-acm-dns-validation
251
+ /**
252
+ * Validating a simulated ACM certificate against a simulated Route53 record.
253
+ */
254
+
255
+ import {
256
+ DescribeCertificateCommand,
257
+ RequestCertificateCommand,
258
+ } from "@aws-sdk/client-acm";
259
+ import {
260
+ ChangeResourceRecordSetsCommand,
261
+ CreateHostedZoneCommand,
262
+ } from "@aws-sdk/client-route-53";
263
+
264
+ import { SimAws } from "@kensio/yulin";
265
+
266
+ const simAws = new SimAws();
267
+
268
+ const zoneOutput = await simAws.route53().createHostedZone(
269
+ new CreateHostedZoneCommand({
270
+ Name: "example.test",
271
+ CallerReference: "acm-dns-validation",
272
+ }),
273
+ );
274
+
275
+ const requestOutput = await simAws.acm().requestCertificate(
276
+ new RequestCertificateCommand({
277
+ DomainName: "api.example.test",
278
+ }),
279
+ );
280
+
281
+ await simAws.backgroundTasksComplete();
282
+
283
+ // A hosted zone covers the domain, so the certificate waits for its record.
284
+ const pendingOutput = await simAws.acm().describeCertificate(
285
+ new DescribeCertificateCommand({
286
+ CertificateArn: requestOutput.CertificateArn,
287
+ }),
288
+ );
289
+
290
+ console.log(pendingOutput.Certificate?.Status); // PENDING_VALIDATION
291
+
292
+ const validationRecord =
293
+ pendingOutput.Certificate?.DomainValidationOptions?.[0]?.ResourceRecord;
294
+
295
+ await simAws.route53().changeResourceRecordSets(
296
+ new ChangeResourceRecordSetsCommand({
297
+ HostedZoneId: zoneOutput.HostedZone?.Id,
298
+ ChangeBatch: {
299
+ Changes: [
300
+ {
301
+ Action: "CREATE",
302
+ ResourceRecordSet: {
303
+ Name: validationRecord?.Name,
304
+ Type: "CNAME",
305
+ TTL: 300,
306
+ ResourceRecords: [{ Value: validationRecord?.Value ?? "" }],
307
+ },
308
+ },
309
+ ],
310
+ },
311
+ }),
312
+ );
313
+
314
+ await simAws.backgroundTasksComplete();
315
+
316
+ const issuedOutput = await simAws.acm().describeCertificate(
317
+ new DescribeCertificateCommand({
318
+ CertificateArn: requestOutput.CertificateArn,
319
+ }),
320
+ );
321
+
322
+ console.log(issuedOutput.Certificate?.Status); // ISSUED
323
+ ```
324
+
325
+ Each domain on a certificate is validated separately. A certificate with subject alternative names
326
+ is issued only once every domain that needs DNS validation has its record. Domains that are not
327
+ covered by any hosted zone don't need anything published for them. Until all domains are validated,
328
+ `DescribeCertificateCommand` reports `SUCCESS` for validated domains and `PENDING_VALIDATION` for
329
+ the rest.
330
+
331
+ Hosted zones are looked up across every simulated account, matching real ACM validating against
332
+ public DNS. A certificate in one account can be validated by a hosted zone in another.
333
+
334
+ ### Skip the validation record
335
+
336
+ > **Note:** Use `completeDnsValidation()` when your test needs a hosted zone for reasons unrelated
337
+ > to certificate validation and you don't want to go through the full validation flow.
338
+
339
+ Call `completeDnsValidation()` on a pending certificate. It publishes the validation records and
340
+ resolves once the certificate is issued.
341
+
342
+ ```typescript sim-acm-complete-dns-validation
343
+ /**
344
+ * Completing simulated ACM DNS validation in one call.
345
+ */
346
+
347
+ import {
348
+ DescribeCertificateCommand,
349
+ RequestCertificateCommand,
350
+ } from "@aws-sdk/client-acm";
351
+ import { CreateHostedZoneCommand } from "@aws-sdk/client-route-53";
352
+
353
+ import { SimAws } from "@kensio/yulin";
354
+
355
+ const simAws = new SimAws();
356
+
357
+ await simAws.route53().createHostedZone(
358
+ new CreateHostedZoneCommand({
359
+ Name: "example.test",
360
+ CallerReference: "acm-shortcut",
361
+ }),
362
+ );
363
+
364
+ const requestOutput = await simAws.acm().requestCertificate(
365
+ new RequestCertificateCommand({
366
+ DomainName: "api.example.test",
367
+ }),
368
+ );
369
+
370
+ await simAws.acm().completeDnsValidation(requestOutput.CertificateArn);
371
+
372
+ const describeOutput = await simAws.acm().describeCertificate(
373
+ new DescribeCertificateCommand({
374
+ CertificateArn: requestOutput.CertificateArn,
375
+ }),
376
+ );
377
+
378
+ console.log(describeOutput.Certificate?.Status); // ISSUED
379
+ ```
380
+
381
+ ### Override when validation is required
382
+
383
+ Two methods override the default behavior when the hosted zone heuristic doesn't match your test's
384
+ needs:
385
+
386
+ | Method | Behavior |
387
+ | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
388
+ | `simAws.acm().autoIssueCertificates()` | Never requires validation. Use this when a hosted zone exists for unrelated reasons and you don't care about certificates. |
389
+ | `simAws.acm().requireDnsValidation()` | Always requires DNS validation. Use this to exercise the validation path without creating a hosted zone first. |
390
+
391
+ A standalone `new SimAcm()` instance has no simulated Route53, and always issues certificates
392
+ immediately. Calling `requireDnsValidation()` on one throws, because nothing can publish the record
393
+ it would then wait for.
394
+
395
+ ## List and filter certificates
396
+
397
+ Use `ListCertificatesCommand` to inspect certificates in the selected simulated account and region.
398
+
399
+ ```typescript sim-acm-list-certificates
400
+ /**
401
+ * Listing simulated ACM certificates.
402
+ */
403
+
404
+ import {
405
+ ListCertificatesCommand,
406
+ RequestCertificateCommand,
407
+ } from "@aws-sdk/client-acm";
408
+
409
+ import { SimAws } from "@kensio/yulin";
410
+
411
+ const simAws = new SimAws();
412
+ const acm = simAws.acm();
413
+
414
+ await acm.requestCertificate(
415
+ new RequestCertificateCommand({
416
+ DomainName: "one.example.test",
417
+ }),
418
+ );
419
+
420
+ await acm.requestCertificate(
421
+ new RequestCertificateCommand({
422
+ DomainName: "two.example.test",
423
+ }),
424
+ );
425
+
426
+ const listOutput = await acm.listCertificates(
427
+ new ListCertificatesCommand({
428
+ MaxItems: 10,
429
+ }),
430
+ );
431
+
432
+ const certificateSummaries = listOutput.CertificateSummaryList ?? [];
433
+ for (const summary of certificateSummaries) {
434
+ console.log(summary.CertificateArn);
435
+ console.log(summary.DomainName);
436
+ console.log(summary.Status);
437
+ }
438
+ ```
439
+
440
+ Certificates are listed in creation order. `MaxItems` must be between 1 and 1000 and defaults to 100. When more results are available, pass `NextToken` from the response into your next request.
441
+
442
+ To filter by status, pass `CertificateStatuses` to `ListCertificatesCommand`.
443
+
444
+ ```typescript sim-acm-list-issued-certificates
445
+ /**
446
+ * Filtering simulated ACM certificates by status.
447
+ */
448
+
449
+ import {
450
+ ListCertificatesCommand,
451
+ RequestCertificateCommand,
452
+ } from "@aws-sdk/client-acm";
453
+
454
+ import { SimAws } from "@kensio/yulin";
455
+
456
+ const simAws = new SimAws();
457
+ const acm = simAws.acm();
458
+
459
+ await acm.requestCertificate(
460
+ new RequestCertificateCommand({
461
+ DomainName: "issued.example.test",
462
+ }),
463
+ );
464
+
465
+ await simAws.backgroundTasksComplete();
466
+
467
+ const listOutput = await acm.listCertificates(
468
+ new ListCertificatesCommand({
469
+ CertificateStatuses: ["ISSUED"],
470
+ }),
471
+ );
472
+
473
+ console.log(listOutput.CertificateSummaryList?.map((cert) => cert.DomainName));
474
+ ```
475
+
476
+ ## Add tags to a certificate
477
+
478
+ Pass `Tags` when requesting a certificate. Simulated ACM accepts up to 50 tags, matching the ACM
479
+ request limit. Requests with more than 50 tags throw `TooManyTagsException`.
480
+
481
+ ```typescript sim-acm-tags
482
+ /**
483
+ * Requesting a simulated ACM certificate with tags.
484
+ */
485
+
486
+ import { RequestCertificateCommand } from "@aws-sdk/client-acm";
487
+
488
+ import { SimAws } from "@kensio/yulin";
489
+
490
+ const simAws = new SimAws();
491
+ const acm = simAws.acm();
492
+
493
+ await acm.requestCertificate(
494
+ new RequestCertificateCommand({
495
+ DomainName: "tagged.example.test",
496
+ Tags: [
497
+ {
498
+ Key: "Purpose",
499
+ Value: "local-test",
500
+ },
501
+ {
502
+ Key: "Owner",
503
+ Value: "docs",
504
+ },
505
+ ],
506
+ }),
507
+ );
508
+ ```
509
+
510
+ ## Scope certificates to an account and region
511
+
512
+ Use `SimAws` scopes to create ACM certificates in different simulated accounts and regions. ACM
513
+ state is scoped to the selected account and region. Certificates requested in one scope don't
514
+ appear in another.
515
+
516
+ ```typescript sim-acm-account-region-scoping
517
+ /**
518
+ * Simulated ACM account and region scoping.
519
+ */
520
+
521
+ import { RequestCertificateCommand } from "@aws-sdk/client-acm";
522
+
523
+ import { SimAws } from "@kensio/yulin";
524
+
525
+ const simAws = new SimAws();
526
+
527
+ const defaultAcm = simAws.acm();
528
+ const euWest2Acm = simAws.region("eu-west-2").acm();
529
+ const accountAcm = simAws.account("111111111111").acm();
530
+ const scopedAcm = simAws.account("222222222222").region("ap-east-1").acm();
531
+
532
+ await defaultAcm.requestCertificate(
533
+ new RequestCertificateCommand({
534
+ DomainName: "default.example.test",
535
+ }),
536
+ );
537
+
538
+ await euWest2Acm.requestCertificate(
539
+ new RequestCertificateCommand({
540
+ DomainName: "eu-west-2.example.test",
541
+ }),
542
+ );
543
+
544
+ await accountAcm.requestCertificate(
545
+ new RequestCertificateCommand({
546
+ DomainName: "account.example.test",
547
+ }),
548
+ );
549
+
550
+ await scopedAcm.requestCertificate(
551
+ new RequestCertificateCommand({
552
+ DomainName: "scoped.example.test",
553
+ }),
554
+ );
555
+ ```
556
+
557
+ Each `SimAws` instance has its own isolated state. Create a fresh instance per test or share one across related local setup.
558
+
559
+ ## Register a certificate with a chosen ARN
560
+
561
+ `RequestCertificateCommand` allocates its own certificate ARN, as real ACM does, and takes none from
562
+ you. When something else already decided the ARN, register the certificate as part of your test setup
563
+ instead.
564
+
565
+ The usual reason is a CDK app that creates its certificate in one stack and uses it in another. The
566
+ ARN crosses between the two as a plain string, and the stack using it carries that ARN into its
567
+ synthesized template. Simulated CloudFront checks the certificate before it creates a Distribution,
568
+ so registering the certificate first lets the template deploy as it is, with no rewriting.
569
+
570
+ ```typescript sim-acm-register-certificate
571
+ /**
572
+ * Registering a simulated ACM certificate with a chosen certificate ARN.
573
+ */
574
+
575
+ import { SimAws } from "@kensio/yulin";
576
+
577
+ const simAws = new SimAws();
578
+
579
+ // The certificate ARN a CDK app carried into the template of the stack using it.
580
+ const certificateArn =
581
+ "arn:aws:acm:us-east-1:111122223333:certificate/3b82191c-b029-4e5f-a94f-038f98a53ede";
582
+
583
+ // Register it in the account and region the ARN itself names.
584
+ simAws
585
+ .account("111122223333")
586
+ .region("us-east-1")
587
+ .acm()
588
+ .registerCertificate({
589
+ arn: certificateArn,
590
+ domainName: "example.test",
591
+ subjectAlternativeNames: ["www.example.test"],
592
+ });
593
+
594
+ const stack = await simAws
595
+ .account("111122223333")
596
+ .region("us-east-1")
597
+ .cloudFormation()
598
+ .deployTemplate({
599
+ stackName: "site-stack",
600
+ template: {
601
+ Resources: {
602
+ SiteDistribution: {
603
+ Type: "AWS::CloudFront::Distribution",
604
+ Properties: {
605
+ DistributionConfig: {
606
+ CallerReference: "site-distribution",
607
+ Enabled: true,
608
+ Aliases: ["www.example.test"],
609
+ DefaultCacheBehavior: {
610
+ TargetOriginId: "origin",
611
+ ViewerProtocolPolicy: "redirect-to-https",
612
+ },
613
+ ViewerCertificate: {
614
+ AcmCertificateArn: certificateArn,
615
+ SslSupportMethod: "sni-only",
616
+ },
617
+ },
618
+ },
619
+ },
620
+ },
621
+ },
622
+ });
623
+
624
+ await stack.waitForDeployComplete();
625
+
626
+ console.log(stack.getResource("SiteDistribution")?.status);
627
+ ```
628
+
629
+ A registered certificate behaves like any other. It answers `DescribeCertificateCommand`, appears in
630
+ `ListCertificatesCommand` under an `ISSUED` status filter, and satisfies the certificate lookups
631
+ simulated CloudFront and ELBv2 make. It is `ISSUED` from the moment it is registered, since the
632
+ simulation was told it already exists, and it carries no DNS validation records.
633
+
634
+ Pass `status` to register a certificate in some other state, such as `EXPIRED`, to see what a
635
+ Distribution does with it. An ARN that another certificate already holds is refused with
636
+ `InvalidArgsException`, as is a string that is no ACM certificate ARN. So is an ARN naming an account
637
+ or region other than the ACM's own, since other services find a certificate through the account and
638
+ region inside its ARN.
639
+
640
+ ## Create a certificate with CloudFormation
641
+
642
+ Simulated CloudFormation can create ACM certificates from `AWS::CertificateManager::Certificate`.
643
+
644
+ For `AWS::CertificateManager::Certificate`:
645
+
646
+ - `Ref` returns the certificate ARN.
647
+ - `Fn::GetAtt` supports `CertificateArn` and `CertificateStatus`.
648
+
649
+ Supported certificate properties:
650
+
651
+ | Property | Description |
652
+ | ------------------------- | -------------------------------------------------------- |
653
+ | `DomainName` | Primary domain for the certificate. |
654
+ | `SubjectAlternativeNames` | Additional DNS names to cover. |
655
+ | `ValidationMethod` | `DNS` or `EMAIL`. |
656
+ | `DomainValidationOptions` | Validation options per domain, including `HostedZoneId`. |
657
+ | `Tags` | Up to 50 key-value tags. |
658
+
659
+ ```typescript sim-acm-cloudformation-certificate
660
+ /**
661
+ * Creating an ACM certificate through simulated CloudFormation.
662
+ */
663
+
664
+ import {
665
+ DescribeCertificateCommand,
666
+ ListCertificatesCommand,
667
+ } from "@aws-sdk/client-acm";
668
+
669
+ import { SimAws } from "@kensio/yulin";
670
+
671
+ const simAws = new SimAws();
672
+
673
+ const stack = await simAws.cloudFormation().deployTemplate({
674
+ stackName: "acm-certificate-stack",
675
+ template: {
676
+ Resources: {
677
+ SiteCertificate: {
678
+ Type: "AWS::CertificateManager::Certificate",
679
+ Properties: {
680
+ DomainName: "example.test",
681
+ SubjectAlternativeNames: ["www.example.test"],
682
+ ValidationMethod: "DNS",
683
+ DomainValidationOptions: [
684
+ {
685
+ DomainName: "example.test",
686
+ ValidationDomain: "example.test",
687
+ },
688
+ ],
689
+ Tags: [
690
+ {
691
+ Key: "Purpose",
692
+ Value: "local-test",
693
+ },
694
+ ],
695
+ },
696
+ },
697
+ },
698
+ Outputs: {
699
+ CertificateArn: {
700
+ Value: {
701
+ Ref: "SiteCertificate",
702
+ },
703
+ },
704
+ CertificateStatus: {
705
+ Value: {
706
+ "Fn::GetAtt": ["SiteCertificate", "CertificateStatus"],
707
+ },
708
+ },
709
+ },
710
+ },
711
+ });
712
+
713
+ const certificateArn = stack.output("CertificateArn");
714
+ if (typeof certificateArn !== "string")
715
+ throw new Error("No CertificateArn Output");
716
+
717
+ const listOutput = await simAws
718
+ .acm()
719
+ .listCertificates(new ListCertificatesCommand());
720
+
721
+ const describeOutput = await simAws.acm().describeCertificate(
722
+ new DescribeCertificateCommand({
723
+ CertificateArn: certificateArn,
724
+ }),
725
+ );
726
+
727
+ console.log(stack.output("CertificateStatus"));
728
+ console.log(listOutput.CertificateSummaryList?.[0]?.DomainName);
729
+ console.log(describeOutput.Certificate?.Status);
730
+ ```
731
+
732
+ ### Validate a certificate from the template
733
+
734
+ Give a `DomainValidationOptions` entry a `HostedZoneId` and simulated CloudFormation publishes the validation record itself, the same way real CloudFormation does. This is what CDK emits for `CertificateValidation.fromDns(zone)`. A CDK-synthesized template works without changes.
735
+
736
+ A certificate resource is only complete once the certificate is issued. Anything depending on the certificate is created after it exists, as in real CloudFormation.
737
+
738
+ ```typescript sim-acm-cloudformation-dns-validation
739
+ /**
740
+ * Validating an ACM certificate from a simulated CloudFormation template.
741
+ */
742
+
743
+ import { SimAws } from "@kensio/yulin";
744
+
745
+ const simAws = new SimAws();
746
+
747
+ const stack = await simAws.cloudFormation().deployTemplate({
748
+ stackName: "acm-dns-validation-stack",
749
+ template: {
750
+ Resources: {
751
+ Zone: {
752
+ Type: "AWS::Route53::HostedZone",
753
+ Properties: {
754
+ Name: "example.test",
755
+ },
756
+ },
757
+ SiteCertificate: {
758
+ Type: "AWS::CertificateManager::Certificate",
759
+ Properties: {
760
+ DomainName: "api.example.test",
761
+ ValidationMethod: "DNS",
762
+ DomainValidationOptions: [
763
+ {
764
+ DomainName: "api.example.test",
765
+ HostedZoneId: { Ref: "Zone" },
766
+ },
767
+ ],
768
+ },
769
+ },
770
+ },
771
+ Outputs: {
772
+ CertificateStatus: {
773
+ Value: {
774
+ "Fn::GetAtt": ["SiteCertificate", "CertificateStatus"],
775
+ },
776
+ },
777
+ },
778
+ },
779
+ });
780
+
781
+ await stack.waitForDeployComplete();
782
+
783
+ // The hosted zone, the validation record and the issued certificate, from one
784
+ // template deploy.
785
+ console.log(stack.output("CertificateStatus")); // ISSUED
786
+ ```
787
+
788
+ `HostedZoneId` accepts a `Ref` to an `AWS::Route53::HostedZone` in the same template, or the literal ID of a zone created outside the stack.
789
+
790
+ A `HostedZoneId` that names a hosted zone the simulator doesn't hold is skipped rather than failing. Route53 is often managed by another team or another tool. The certificate then follows the usual rule from [Validate a certificate against simulated Route53](#validate-a-certificate-against-simulated-route53): with nothing authoritative for its domain, it's issued without validation.
791
+
792
+ If a hosted zone covers the domain but the validation record never appears, the stack fails rather than hanging. Real CloudFormation sits in `CREATE_IN_PROGRESS` for hours before timing out, which is of little use in a test. The resource fails immediately and names the record it waited for.
793
+
794
+ ## Available functionality
795
+
796
+ Simulated ACM supports:
797
+
798
+ - `RequestCertificateCommand`, `DescribeCertificateCommand`, and `ListCertificatesCommand`
799
+ - DNS validation against records in simulated Route53
800
+ - CloudFormation-published validation records from `DomainValidationOptions[].HostedZoneId`
801
+ - EMAIL validation method shapes (validation always succeeds regardless)
802
+ - Subject alternative names
803
+ - Certificate tags, up to the ACM limit of 50
804
+ - Deterministic certificate ARNs scoped to account and region
805
+ - Certificates registered under a caller-chosen ARN, for a template naming one another stack created
806
+ - Deterministic DNS validation CNAME records
807
+ - Background certificate issuance from `PENDING_VALIDATION` to `ISSUED`
808
+ - Per-domain validation status for multi-domain certificates
809
+ - The `AWS::CertificateManager::Certificate` CloudFormation resource, with `Ref` and `Fn::GetAtt`
810
+
811
+ Unsupported ACM options might be ignored or might throw errors, depending on whether the simulator needs them to model the requested behavior.
812
+
813
+ ## Limitations
814
+
815
+ | Limitation | Detail |
816
+ | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
817
+ | Certificate deletion | Not supported. |
818
+ | Certificate renewal | Not supported. |
819
+ | Imported certificates | Not supported. |
820
+ | EMAIL validation | Always succeeds; only DNS validation is enforced. |
821
+ | DNS validation scope | Checked against simulated Route53 only, never against real DNS. |
822
+ | Validation timeout | A certificate requested through the SDK whose record never appears stays `PENDING_VALIDATION`. A CloudFormation certificate fails its stack instead. |
823
+ | HTTP API | ACM is not served as an HTTP API by `serveSimAws`. |