@kensio/yulin 1.21.6 → 1.21.7

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 (37) hide show
  1. package/dist/service/eventbridge/cfn/bus/sim-cfn-event-bus-creator.js +1 -0
  2. package/dist/service/eventbridge/cfn/bus/sim-cfn-event-bus-properties.d.ts +4 -0
  3. package/dist/service/eventbridge/cfn/bus/sim-cfn-event-bus-properties.js +26 -1
  4. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-creator.js +3 -1
  5. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-properties.d.ts +0 -7
  6. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-properties.js +0 -20
  7. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-unsimulated-properties.d.ts +13 -0
  8. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-unsimulated-properties.js +59 -0
  9. package/dist/service/eventbridge/cfn/sim-cfn-event-bridge-resource-error.d.ts +1 -1
  10. package/dist/service/eventbridge/cfn/sim-cfn-event-bridge-resource-error.js +1 -1
  11. package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-properties.js +1 -1
  12. package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-property-rules.d.ts +3 -2
  13. package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-property-rules.js +25 -3
  14. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-creator.js +1 -0
  15. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-properties.d.ts +9 -4
  16. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-properties.js +18 -6
  17. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-property-names.d.ts +10 -0
  18. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-property-names.js +16 -1
  19. package/dist/service/ssm/cfn/parameter/sim-cfn-ssm-parameter-creator.js +1 -1
  20. package/dist/service/ssm/cfn/parameter/sim-cfn-ssm-parameter-properties.d.ts +11 -6
  21. package/dist/service/ssm/cfn/parameter/sim-cfn-ssm-parameter-properties.js +18 -9
  22. package/docs/README.md +33 -4
  23. package/docs/ai-skill/README.md +52 -54
  24. package/docs/cli/README.md +84 -94
  25. package/docs/factories/README.md +42 -54
  26. package/docs/lint/README.md +41 -67
  27. package/docs/non-aws-dependencies/README.md +72 -168
  28. package/docs/sdk/README.md +97 -98
  29. package/docs/serve/README.md +192 -898
  30. package/docs/services/eventbridge/README.md +10 -2
  31. package/docs/services/lambda/README.md +7 -1
  32. package/docs/services/sns/README.md +13 -7
  33. package/docs/services/ssm/README.md +6 -4
  34. package/docs/terraform/README.md +108 -126
  35. package/docs/time/README.md +80 -120
  36. package/llms.txt +1 -1
  37. package/package.json +1 -1
@@ -919,6 +919,12 @@ at deploy time naming the property and the Resource. The alternative is a rule t
919
919
  event where one field was asked for. Tearing the stack down removes the buses, rules and targets it
920
920
  created.
921
921
 
922
+ `Tags` is the one difference from the commands, which refuse it outright. A template's tags are
923
+ usually the whole stack's (a CDK app calling `Tags.of(app).add(...)` tags every rule and bus in it),
924
+ and a rule routes the same events whether it carries them or not. They are recorded as an ignored
925
+ property and the deploy stands. Nothing reads them back. A rule or a bus deployed with tags behaves
926
+ as though the template had never named them.
927
+
922
928
  ## Reading back a failed delivery
923
929
 
924
930
  Real EventBridge tells the caller nothing about a failed delivery. A `PutEvents` that matched a rule
@@ -1101,7 +1107,8 @@ no permission for.
1101
1107
  - EventBridge Scheduler is a separate service, simulated separately. See
1102
1108
  [simulated Scheduler](https://yulinsim.dev/services/scheduler/).
1103
1109
  - Rule tags, a rule `RoleArn`, managed rules and the `ENABLED_WITH_ALL_CLOUDTRAIL_MANAGEMENT_EVENTS`
1104
- state are all refused.
1110
+ state are all refused at `PutRule`. An `AWS::Events::Rule` carrying `Tags` deploys with the tags
1111
+ dropped and the property recorded.
1105
1112
  - Deleting an event bus deletes its rules, and deleting a rule deletes its targets. Real EventBridge
1106
1113
  refuses to delete either while it still has what hangs off it.
1107
1114
  - `AWS::Events::EventBusPolicy`, `AWS::Events::Archive`, `AWS::Events::Connection` and
@@ -1113,6 +1120,7 @@ no permission for.
1113
1120
  stricter than real AWS.
1114
1121
  - Putting an event onto another account's or region's bus is refused.
1115
1122
  - Partner event buses and partner event sources are refused, as are event bus tags, encryption with
1116
- a customer managed key, dead letter queues, logging configuration and global endpoints.
1123
+ a customer managed key, dead letter queues, logging configuration and global endpoints. An
1124
+ `AWS::Events::EventBus` carrying `Tags` deploys with the tags dropped and the property recorded.
1117
1125
  - Archives, replay, schema registry and discovery, API destinations and connections are not
1118
1126
  simulated.
@@ -1702,6 +1702,10 @@ Reporting individual failures can be tested against a made event too. The handle
1702
1702
  a template naming one is refused. The same Resource deploys a
1703
1703
  [stream mapping](#stream-mappings-in-templates), which has to have one.
1704
1704
 
1705
+ `Tags` is the one property recorded rather than refused. A template's tags are usually the whole
1706
+ stack's (a CDK app calling `Tags.of(app).add(...)` tags every mapping in it), and a mapping delivers
1707
+ the same records whether it carries them or not. The deploy stands and nothing reads them back.
1708
+
1705
1709
  ## Triggering a function from a DynamoDB stream
1706
1710
 
1707
1711
  An event source mapping also connects a [simulated table's stream](https://yulinsim.dev/services/dynamodb/#capturing-changes-with-a-stream "Simulated DynamoDB streams docs")
@@ -4268,7 +4272,9 @@ Current documented limitations:
4268
4272
  - SQS queues, DynamoDB streams and Kinesis streams are the only event sources. Kafka, DocumentDB and
4269
4273
  Kinesis enhanced fan-out consumers are refused outright, and so are `FilterCriteria`,
4270
4274
  `ScalingConfig`, `DestinationConfig`, `BisectBatchOnFunctionError`, `ParallelizationFactor`,
4271
- `TumblingWindowInSeconds` and the other mapping inputs this simulation has no behaviour for.
4275
+ `TumblingWindowInSeconds` and the other mapping inputs this simulation has no behaviour for. An
4276
+ `AWS::Lambda::EventSourceMapping` carrying `Tags` is the exception, and deploys with the tags
4277
+ dropped and the property recorded.
4272
4278
  - A failed stream batch waits 1, 2, 4, 8 and 16 seconds between attempts, where AWS documents no
4273
4279
  delay. That is deliberate. A delay of zero falls due at the instant the clock already reads, and a
4274
4280
  handler that always throws would leave `advanceBy` with work falling due forever. A mapping that
@@ -1742,16 +1742,21 @@ ARNs, and `Ref` on an `AWS::SNS::Topic` gives one.
1742
1742
 
1743
1743
  A property with no simulated behaviour fails the resource rather than being dropped. That covers
1744
1744
  `FifoTopic`, `ContentBasedDeduplication`, `FifoThroughputScope`, `KmsMasterKeyId`,
1745
- `SignatureVersion`, `TracingConfig`, `ArchivePolicy`, `DeliveryStatusLogging`, `DataProtectionPolicy`
1746
- and `Tags` on a topic, and `DeliveryPolicy`, `RedrivePolicy`, `ReplayPolicy`, `SubscriptionRoleArn`
1747
- and `Region` on a subscription. Most of them are refused by simulated SNS itself, since they are
1748
- topic or subscription attributes of the same name, and the reason is the same one an SDK caller gets.
1749
- A property the resource type never had is refused too. The failure is worded as an invalid resource,
1750
- which fails the resource where an unsupported one would be
1745
+ `SignatureVersion`, `TracingConfig`, `ArchivePolicy`, `DeliveryStatusLogging` and
1746
+ `DataProtectionPolicy` on a topic, and `DeliveryPolicy`, `RedrivePolicy`, `ReplayPolicy`,
1747
+ `SubscriptionRoleArn` and `Region` on a subscription. Most of them are refused by simulated SNS
1748
+ itself, since they are topic or subscription attributes of the same name, and the reason is the same
1749
+ one an SDK caller gets. A property the resource type never had is refused too. The failure is worded
1750
+ as an invalid resource, which fails the resource where an unsupported one would be
1751
1751
  [skipped](https://yulinsim.dev/services/cloudformation/#values-from-a-skipped-resource). A topic that cannot be created
1752
1752
  as the template asked for it would otherwise leave a stack that looks deployed with no publisher
1753
1753
  behind it.
1754
1754
 
1755
+ `Tags` is the one difference from `CreateTopic`, which refuses it outright. A template's tags are
1756
+ usually the whole stack's (a CDK app calling `Tags.of(app).add(...)` tags every topic in it), and a
1757
+ topic delivers the same messages whether it carries them or not. They are recorded as an ignored
1758
+ property and the deploy stands. Nothing reads them back either.
1759
+
1755
1760
  CDK works without hand-editing. `topic.addSubscription(new subscriptions.SqsSubscription(queue))`
1756
1761
  synthesises an `AWS::SNS::Subscription` alongside the `AWS::SQS::QueuePolicy` that authorizes the
1757
1762
  delivery, and both deploy. `new subscriptions.LambdaSubscription(fn)` does the same with the
@@ -1880,7 +1885,8 @@ Current documented limitations:
1880
1885
  - Encryption is left out. `KmsMasterKeyId` is refused, and message bodies are held in process memory
1881
1886
  as they were published. Anything sharing the process can read them.
1882
1887
  - Tags are left out. `TagResource`, `UntagResource` and `ListTagsForResource` are absent, and
1883
- `CreateTopic` refuses a `Tags` parameter rather than dropping it.
1888
+ `CreateTopic` refuses a `Tags` parameter rather than dropping it. An `AWS::SNS::Topic` carrying
1889
+ `Tags` deploys with the tags dropped and the property recorded.
1884
1890
  - Data protection policies are left out. `PutDataProtectionPolicy` and `GetDataProtectionPolicy` are
1885
1891
  absent, and `CreateTopic` refuses a `DataProtectionPolicy` rather than creating a topic that
1886
1892
  redacts nothing.
@@ -1039,7 +1039,8 @@ Current documented limitations:
1039
1039
  - Parameter policies (expiration and notification) are left out. `Policies` is refused, and
1040
1040
  `DescribeParameters` always reports an empty `Policies` list.
1041
1041
  - Tags are left out. `Tags` on `PutParameter` is refused, and `AddTagsToResource`,
1042
- `RemoveTagsFromResource` and `ListTagsForResource` are absent.
1042
+ `RemoveTagsFromResource` and `ListTagsForResource` are absent. An `AWS::SSM::Parameter` carrying
1043
+ `Tags` deploys with the tags dropped and the property recorded.
1043
1044
  - `AllowedPattern` is refused outright. Ignoring it would store a value it was meant to reject,
1044
1045
  without complaint.
1045
1046
  - `KeyId` on a `String` or `StringList` parameter is refused, since nothing would encrypt a value
@@ -1060,9 +1061,10 @@ Current documented limitations:
1060
1061
  - Deletion is immediate. Real Parameter Store asks for thirty seconds before a deleted name is
1061
1062
  reused, where here the name is free straight away.
1062
1063
  - `AWS::SSM::Parameter` supports `Name`, `Type`, `Value`, `Description` and `Tier`. `AllowedPattern`,
1063
- `DataType`, `Policies` and `Tags` reach `PutParameter`, which refuses them for the reasons above.
1064
- `Type: SecureString` is refused, as real CloudFormation refuses it for this resource type. The
1065
- plaintext value would sit in the template.
1064
+ `DataType` and `Policies` reach `PutParameter`, which refuses them for the reasons above. `Tags`
1065
+ is the one difference from the command, and is recorded as an ignored property so a stack that
1066
+ tags every Resource in it still deploys. `Type: SecureString` is refused, as real CloudFormation
1067
+ refuses it for this resource type. The plaintext value would sit in the template.
1066
1068
  - The other `AWS::SSM::*` resource types (`Document`, `Association`, `MaintenanceWindow`,
1067
1069
  `PatchBaseline`, `ResourceDataSync` and the rest) are reported as unsupported and skipped.
1068
1070
  - Every deployment of an `AWS::SSM::Parameter` is a create. A name another stack already used is
@@ -1,27 +1,29 @@
1
- # Terraform
1
+ # Deploy Terraform plans
2
2
 
3
- A team whose infrastructure is written in Terraform can deploy it into simulated AWS without
4
- hand-writing a second CloudFormation template describing the same infrastructure. `TerraformAdapter`
5
- reads the JSON `terraform show -json` writes for a saved plan file and creates the resources the
6
- plan declares.
3
+ `TerraformAdapter` reads a Terraform plan in JSON form and deploys its AWS resources into a
4
+ `SimAws` instance.
7
5
 
8
6
  ```bash
9
7
  npm i -D @kensio/yulin
10
8
  ```
11
9
 
12
- ## Deploying a plan
10
+ ## Create the plan JSON
13
11
 
14
- Write the JSON first. `terraform plan` produces the saved plan in Terraform's own binary format, and
15
- `terraform show -json` turns that into the document the adapter reads.
12
+ Save a plan, then convert it to JSON:
16
13
 
17
14
  ```bash
18
15
  terraform plan -out=orders.tfplan
19
16
  terraform show -json orders.tfplan > orders.tfplan.json
20
17
  ```
21
18
 
22
- A plan carries no code for its functions. It points at a zip on disk, an S3 object or a container
23
- image, and none of the three is a handler Yulin can run. A binding matched on the function name the
24
- plan declares is where the behaviour comes from.
19
+ `TerraformAdapter` expects the JSON file produced by `terraform show -json`. The binary `.tfplan`
20
+ file is only the input to that command.
21
+
22
+ ## Deploy the plan
23
+
24
+ Create an adapter for the `SimAws` instance and pass the JSON path to `deployPlan`. A Terraform plan
25
+ records the location of each Lambda deployment package. Use a binding to supply an executable
26
+ handler for the simulated function:
25
27
 
26
28
  ```typescript terraform-deploy-plan
27
29
  /**
@@ -50,9 +52,10 @@ console.log(simAws.dynamoDb().findTable("orders-orders")?.tableName);
50
52
  console.log(stack.status);
51
53
  ```
52
54
 
53
- The Stack is named after the plan file when the deployment does not name one, so
54
- `orders.tfplan.json` deploys as `orders`. Pass `stackName` to name it yourself, and pass the path on
55
- its own where nothing else needs saying.
55
+ The default stack name comes from the plan filename. For example, `orders.tfplan.json` creates a
56
+ stack named `orders`. Pass `stackName` when the stack needs a different name.
57
+
58
+ If the deployment needs no bindings, overrides, or custom stack name, pass the path directly:
56
59
 
57
60
  ```typescript terraform-deploy-plan-path
58
61
  /**
@@ -71,43 +74,75 @@ const { stack } = await new TerraformAdapter(simAws).deployPlan(
71
74
  console.log(stack.stackName);
72
75
  ```
73
76
 
74
- ## What comes back
77
+ ## Read the deployed stack and import report
78
+
79
+ `deployPlan` returns `stack` and `report`.
80
+
81
+ `stack` is a simulated CloudFormation stack. Use `stack.getResource(...)` to read a resource,
82
+ `stack.output(...)` to read an output, and `stack.delete()` to delete it. The
83
+ [CloudFormation guide](https://yulinsim.dev/services/cloudformation/ "Simulated CloudFormation usage docs")
84
+ describes the rest of the stack API.
85
+
86
+ `report` explains how Terraform resources were imported:
87
+
88
+ ```typescript terraform-plan-report
89
+ /**
90
+ * Reading what a Terraform plan import made of the plan.
91
+ */
92
+
93
+ import { SimAws } from "@kensio/yulin";
94
+ import { TerraformAdapter } from "@kensio/yulin/terraform";
95
+
96
+ const simAws = new SimAws();
97
+
98
+ const { report } = await new TerraformAdapter(simAws).deployPlan(
99
+ "terraform/orders.tfplan.json",
100
+ );
101
+
102
+ // [ { address: 'aws_s3_bucket.uploads', type: 'aws_s3_bucket',
103
+ // cfnType: 'AWS::S3::Bucket', logicalId: 'AwsS3BucketUploads' } ]
104
+ console.log(report.mapped);
75
105
 
76
- `deployPlan` answers with the Stack and a report of what reading the plan made of it.
106
+ // [ { address: 'aws_route53_zone.public', type: 'aws_route53_zone',
107
+ // reason: 'no mapping for resource type' } ]
108
+ console.log(report.skipped);
77
109
 
78
- The Stack is an ordinary simulated CloudFormation Stack, and everything the [CloudFormation
79
- docs](https://yulinsim.dev/services/cloudformation/ "Simulated CloudFormation usage docs") describe applies to it.
80
- Resources are read with `stack.getResource(...)`, Outputs with `stack.output(...)`, and the whole
81
- thing is torn down with `stack.delete()`.
110
+ // The aws_s3_bucket_versioning and friends that became bucket properties.
111
+ console.log(report.folded);
82
112
 
83
- ## What the adapter reads
113
+ // Attributes a mapping could not carry and no override supplied, such as a
114
+ // Lambda's environment variables, which Terraform collapses whole when one of
115
+ // them is unknown.
116
+ console.log(report.lost);
117
+ ```
118
+
119
+ - `mapped` lists resources that became CloudFormation resources.
120
+ - `folded` lists Terraform resources that became properties of another resource.
121
+ - `skipped` lists resources that were omitted and gives the reason for each omission.
122
+ - `lost` lists attributes that the plan could not supply and no override replaced.
123
+
124
+ The `mapped`, `folded`, and `skipped` lists account for every managed resource in the plan.
125
+
126
+ ## How resources and references are imported
84
127
 
85
128
  A resource declared with `count` or `for_each` arrives in the plan already expanded, and each
86
- instance becomes a resource of its own. Resources declared inside a module are reached through the
87
- module path they were declared under, however many modules deep.
129
+ instance becomes a separate simulated resource. The adapter also reads resources from nested
130
+ modules.
88
131
 
89
- An attribute Terraform could not resolve at plan time is absent from the plan's values. The plan
90
- keeps the reference behind it, and that reference becomes the link a hand-written template would
91
- have carried.
132
+ When an attribute is unknown at plan time, Terraform omits its value but keeps its references. The
133
+ adapter follows references through module inputs, module outputs, `each.value`, and `each.key`.
92
134
 
93
- Ordering is rebuilt. Terraform resolves what it can before writing the plan, so a Lambda permission
94
- naming a function the same plan creates carries the function's name as a plain string. The value is
95
- right and the edge CloudFormation orders from has gone with it. Every reference a resource declares
96
- becomes an ordering edge, whether or not the value resolved.
135
+ The adapter also restores dependency ordering from each resource's references. This matters when
136
+ Terraform has already resolved a reference to a plain string in the planned values.
97
137
 
98
138
  ## Supplying environment variables and role policies
99
139
 
100
- Terraform resolves nothing inside a value it could not build. A Lambda `environment.variables` map
101
- holding one reference to a queue of the same plan arrives unknown in its entirety, and the variable
102
- names go with it. An `aws_iam_role_policy` written with `jsonencode` around an ARN of the same plan
103
- arrives without its statements.
140
+ Terraform marks a whole compound value as unknown when any part of it cannot be resolved. This can
141
+ remove every key from a Lambda `environment.variables` map. It can also remove every statement from
142
+ an IAM policy built with `jsonencode`.
104
143
 
105
- Those two cost more than their count suggests (four attributes out of 154 on a hand-written
106
- application configuration). A handler reads its configuration out of environment variables, and
107
- simulated IAM evaluates authorization.
108
-
109
- `overrides` supplies them, matched on the name the plan carries, the way a binding is matched on a
110
- function name. An environment is matched on the function's name and an inline policy on the role's.
144
+ Use `overrides` to supply these values. Lambda environment overrides match the function name. IAM
145
+ policy overrides match the role name:
111
146
 
112
147
  ```typescript terraform-plan-overrides
113
148
  /**
@@ -160,89 +195,36 @@ const { report } = await new TerraformAdapter(simAws).deployPlan({
160
195
  console.log(report.lost);
161
196
  ```
162
197
 
163
- An override fills a gap. Where Terraform resolved the value, the plan wins, and environment
164
- variables are merged one variable at a time. A configuration that stops collapsing a value stops
165
- needing the override written for it.
166
-
167
- A role whose policy no override supplies is created allowing everything, and `policy` is named on
168
- the report's `lost`. Simulated IAM evaluates authorization, and a role holding no policy would deny
169
- what the configuration allowed and fail the resources using it (an event source mapping is refused
170
- outright when its execution role cannot poll the queue). Supplying the policy takes that default
171
- off. The document is evaluated as it stands, and one omitting `sqs:ReceiveMessage` fails the mapping
172
- the way AWS fails it.
173
-
174
- ## What it maps
175
-
176
- The adapter maps 24 Terraform resource types and folds 11 more into the resource they configure. The
177
- set covers API Gateway, CloudWatch (log groups, metric alarms and EventBridge rules), Cognito,
178
- DynamoDB, ECR, IAM, KMS, Lambda, S3, Secrets Manager, SNS, SQS and SSM Parameter Store.
179
-
180
- A hand-written application configuration of 46 resources deploys whole. A configuration built out of
181
- published `terraform-aws-modules` modules reaches 21 of its 25. Of the four it leaves, the Lambda
182
- module uses `null_resource` and `local_file` to package a zip, and an integration and a route read
183
- their values through a `for_each` hop the adapter steps over.
184
-
185
- ## What the report says
186
-
187
- A type with no mapping, and a resource from a provider other than AWS, are recorded and stepped over
188
- rather than failing the deployment.
189
-
190
- ```typescript terraform-plan-report
191
- /**
192
- * Reading what a Terraform plan import made of the plan.
193
- */
194
-
195
- import { SimAws } from "@kensio/yulin";
196
- import { TerraformAdapter } from "@kensio/yulin/terraform";
197
-
198
- const simAws = new SimAws();
199
-
200
- const { report } = await new TerraformAdapter(simAws).deployPlan(
201
- "terraform/orders.tfplan.json",
202
- );
203
-
204
- // [ { address: 'aws_s3_bucket.uploads', type: 'aws_s3_bucket',
205
- // cfnType: 'AWS::S3::Bucket', logicalId: 'AwsS3BucketUploads' } ]
206
- console.log(report.mapped);
207
-
208
- // [ { address: 'aws_route53_zone.public', type: 'aws_route53_zone',
209
- // reason: 'no mapping for resource type' } ]
210
- console.log(report.skipped);
211
-
212
- // The aws_s3_bucket_versioning and friends that became bucket properties.
213
- console.log(report.folded);
214
-
215
- // Attributes a mapping could not carry and no override supplied, such as a
216
- // Lambda's environment variables, which Terraform collapses whole when one of
217
- // them is unknown.
218
- console.log(report.lost);
219
- ```
220
-
221
- `mapped`, `folded` and `skipped` add up to the plan's managed resource count. `lost` names the
222
- attributes that did not survive the plan and that no override covered, per resource. A Terraform
223
- value that names a resource of the same plan and sits inside something Terraform builds in one go,
224
- such as a `jsonencode` document or a `for_each` map, is unknown in its entirety and its contents go
225
- with it.
226
-
227
- ## What a reference cannot reach
228
-
229
- A value a plan resolved arrives as a value. A value the plan could not resolve arrives as a
230
- reference, and the import follows that reference to the resource that will produce it, through
231
- module outputs, module variables, `each.value` and `each.key`. That covers what a community module
232
- such as `terraform-aws-modules/apigateway-v2/aws` does with a `routes` map.
233
-
234
- Two shapes stop it, and both are recorded as `unresolved required attribute` on `report.skipped`.
235
-
236
- A plan records the references of a whole collection in one list, and the list says what the
237
- collection was built from without saying which entry holds which. A `routes` map naming one function
238
- is unambiguous. A `routes` map naming two functions leaves `each.value.uri` able to mean either, and
239
- the import declines. Setting the value with a resource of its own, or with one module call per
240
- function, gives each reference a collection to itself.
241
-
242
- A value reaching a resource through a `local` is out of range whatever it holds. A plan carries the
243
- locals' effects and none of their definitions, so there is nothing to follow.
244
-
245
- ## The scope of what it reads
246
-
247
- One plan JSON file, already produced. Reading HCL, reading `terraform.tfstate`, and running
248
- `terraform` as a subprocess are all outside it.
198
+ An override only fills a missing value. A value resolved by Terraform takes precedence. Environment
199
+ variables are merged by key.
200
+
201
+ If an IAM role's inline policy is missing, Yulin gives the role an allow-all policy so resources can
202
+ still be created. The report records `policy` under `lost`. Supplying a policy override removes that
203
+ fallback, and simulated IAM evaluates the supplied policy normally.
204
+
205
+ ## Available functionality
206
+
207
+ - `TerraformAdapter` reads JSON produced by `terraform show -json` for a saved plan.
208
+ - `deployPlan` accepts a path or an object containing `planPath`, `stackName`, `bindings`, and
209
+ `overrides`.
210
+ - The adapter maps 24 Terraform resource types and folds 11 configuration resources into their
211
+ parent resources.
212
+ - Supported resource areas include API Gateway HTTP APIs, CloudWatch, Cognito, DynamoDB, ECR, IAM,
213
+ KMS, Lambda, S3, Secrets Manager, SNS, SQS, and SSM Parameter Store.
214
+ - Resources created with `count` and `for_each` are imported as separate instances.
215
+ - Resources in nested modules are imported.
216
+ - The adapter reports mapped, folded, skipped, and lost data for the plan.
217
+
218
+ ## Limitations
219
+
220
+ - The adapter reads one existing plan JSON file. It does not read HCL or Terraform state, and it does
221
+ not run Terraform.
222
+ - Resources from non-AWS providers and Terraform types without a mapping are skipped and recorded in
223
+ `report.skipped`.
224
+ - The adapter cannot follow values through Terraform `local` declarations because a plan contains
225
+ their results but not their definitions.
226
+ - A collection reference can be ambiguous. For example, `each.value.uri` cannot be resolved when the
227
+ source collection contains several possible Lambda function references. The affected resource is
228
+ skipped with the reason `unresolved required attribute`.
229
+ - Some unknown compound values need an override because Terraform omits the whole value from the
230
+ plan.