@kensio/yulin 1.20.15 → 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 (95) hide show
  1. package/README.md +13 -0
  2. package/dist/sdk/module/sim-sdk-module-client-interceptor.d.ts +5 -0
  3. package/dist/sdk/module/sim-sdk-module-client-interceptor.js +14 -0
  4. package/dist/sdk/module/sim-sdk-static-client-factory.d.ts +26 -0
  5. package/dist/sdk/module/sim-sdk-static-client-factory.js +59 -0
  6. package/dist/sdk/send-patch.d.ts +8 -0
  7. package/dist/sdk/send-patch.js +11 -0
  8. package/dist/service/aws/caller/sim-aws-caller-resolver.d.ts +28 -6
  9. package/dist/service/aws/caller/sim-aws-caller-resolver.js +18 -11
  10. package/dist/service/aws/caller/sim-aws-caller.d.ts +9 -0
  11. package/dist/service/aws/caller/sim-aws-resolved-caller.d.ts +19 -0
  12. package/dist/service/aws/caller/sim-aws-resolved-caller.js +26 -0
  13. package/dist/service/aws/factory/sim-aws-account-region-service-builder.d.ts +6 -0
  14. package/dist/service/aws/factory/sim-aws-account-region-service-builder.js +3 -0
  15. package/dist/service/aws/factory/sim-aws-account-service-cache.d.ts +6 -0
  16. package/dist/service/aws/factory/sim-aws-account-service-cache.js +5 -0
  17. package/dist/service/aws/factory/sim-aws-service-factory.d.ts +5 -0
  18. package/dist/service/aws/factory/sim-aws-service-factory.js +6 -0
  19. package/dist/service/aws/sim-aws-properties.d.ts +15 -0
  20. package/dist/service/aws/sim-aws.js +2 -1
  21. package/dist/service/iam/authorize/context/sim-iam-auth-z-caller-context-builder.d.ts +30 -7
  22. package/dist/service/iam/authorize/context/sim-iam-auth-z-caller-context-builder.js +20 -11
  23. package/dist/service/iam/authorize/context/sim-iam-auth-z-context-builder.d.ts +2 -1
  24. package/dist/service/iam/authorize/context/sim-iam-auth-z-context-builder.js +5 -1
  25. package/dist/service/iam/authorize/match/sim-iam-policy-principal-matcher.d.ts +10 -0
  26. package/dist/service/iam/authorize/match/sim-iam-policy-principal-matcher.js +15 -3
  27. package/dist/service/iam/authorize/sim-iam-account-auth-z.d.ts +11 -4
  28. package/dist/service/iam/authorize/sim-iam-account-auth-z.js +5 -3
  29. package/dist/service/iam/authorize/sim-iam-authorizer.d.ts +2 -1
  30. package/dist/service/iam/authorize/sim-iam-authorizer.js +1 -0
  31. package/dist/service/iam/role/sim-iam-role-with-policy.factory.d.ts +9 -0
  32. package/dist/service/iam/role/sim-iam-role-with-policy.factory.js +4 -2
  33. package/dist/service/iam/sim-iam-account-parts.d.ts +8 -0
  34. package/dist/service/iam/sim-iam-account-parts.js +1 -0
  35. package/dist/service/sts/auth-z/assume-role-auth-z-coordinator.d.ts +9 -2
  36. package/dist/service/sts/auth-z/assume-role-auth-z-coordinator.js +2 -2
  37. package/dist/service/sts/auth-z/assume-role-source-account-auth-z.d.ts +10 -4
  38. package/dist/service/sts/auth-z/assume-role-source-account-auth-z.js +8 -7
  39. package/dist/service/sts/auth-z/assume-role-target-auth-z.d.ts +2 -2
  40. package/dist/service/sts/auth-z/assume-role-trust-policy-authorizer.d.ts +6 -2
  41. package/dist/service/sts/auth-z/assume-role-trust-policy-authorizer.js +14 -11
  42. package/dist/service/sts/command/assume-role/assume-role.handler.d.ts +5 -1
  43. package/dist/service/sts/command/assume-role/assume-role.handler.js +5 -2
  44. package/dist/service/sts/command/get-caller-identity/get-caller-identity.handler.d.ts +5 -1
  45. package/dist/service/sts/command/get-caller-identity/get-caller-identity.handler.js +4 -1
  46. package/dist/service/sts/service-role/sim-service-role.js +5 -1
  47. package/dist/service/sts/sim-sts.d.ts +9 -1
  48. package/dist/service/sts/sim-sts.js +4 -0
  49. package/docs/README.md +54 -0
  50. package/docs/ai-skill/README.md +69 -0
  51. package/docs/cli/README.md +284 -0
  52. package/docs/factories/README.md +140 -0
  53. package/docs/lint/README.md +176 -0
  54. package/docs/non-aws-dependencies/README.md +261 -0
  55. package/docs/sdk/README.md +272 -0
  56. package/docs/serve/README.md +1126 -0
  57. package/docs/services/acm/README.md +823 -0
  58. package/docs/services/apigateway/README.md +1919 -0
  59. package/docs/services/apigatewayv2/README.md +2678 -0
  60. package/docs/services/athena/README.md +1044 -0
  61. package/docs/services/bedrock/README.md +350 -0
  62. package/docs/services/cloudformation/README.md +3440 -0
  63. package/docs/services/cloudfront/README.md +2874 -0
  64. package/docs/services/cloudwatch/README.md +420 -0
  65. package/docs/services/cognito/README.md +4923 -0
  66. package/docs/services/dynamodb/README.md +3784 -0
  67. package/docs/services/ecr/README.md +302 -0
  68. package/docs/services/ecs/README.md +2010 -0
  69. package/docs/services/elbv2/README.md +1897 -0
  70. package/docs/services/eventbridge/README.md +1110 -0
  71. package/docs/services/firehose/README.md +805 -0
  72. package/docs/services/glue/README.md +501 -0
  73. package/docs/services/iam/README.md +1283 -0
  74. package/docs/services/kinesis/README.md +454 -0
  75. package/docs/services/kms/README.md +659 -0
  76. package/docs/services/lambda/README.md +3645 -0
  77. package/docs/services/logs/README.md +868 -0
  78. package/docs/services/organizations/README.md +574 -0
  79. package/docs/services/personalize/README.md +835 -0
  80. package/docs/services/rekognition/README.md +1070 -0
  81. package/docs/services/route53/README.md +1783 -0
  82. package/docs/services/s3/README.md +3024 -0
  83. package/docs/services/scheduler/README.md +806 -0
  84. package/docs/services/secretsmanager/README.md +667 -0
  85. package/docs/services/ses/README.md +1011 -0
  86. package/docs/services/sns/README.md +1904 -0
  87. package/docs/services/sqs/README.md +1185 -0
  88. package/docs/services/ssm/README.md +1072 -0
  89. package/docs/services/stepfunctions/README.md +1332 -0
  90. package/docs/services/sts/README.md +245 -0
  91. package/docs/services/wafv2/README.md +1378 -0
  92. package/docs/terraform/README.md +248 -0
  93. package/docs/time/README.md +284 -0
  94. package/llms.txt +59 -0
  95. package/package.json +7 -4
@@ -0,0 +1,302 @@
1
+ # Simulated ECR
2
+
3
+ Yulin includes a simulated Amazon ECR for tests and local development. It holds repositories, and
4
+ each repository holds images by tag, where a simulated image is a real in-process handler.
5
+
6
+ That is what this service is for. A container image Lambda function cannot run here, because Yulin
7
+ never reads an image, so something has to say what the code inside that image actually is. A
8
+ repository is the natural place to say it. It is the stable name for the thing that holds the code,
9
+ outliving any tag and any CDK construct ID, and a repository holding a registered handler outlives
10
+ the stack that declared it too.
11
+
12
+ ECR-specific types are imported from the `@kensio/yulin/ecr` subpath.
13
+
14
+ ## What a simulated image is
15
+
16
+ An image URI is only ever an identifier here. No image is pulled or inspected, and no layer,
17
+ manifest, digest or scan finding exists. A simulated image is a handler function, registered against
18
+ a repository and a tag.
19
+
20
+ Registering one is a Yulin-native operation, named `simulateImage` to keep it clear of a simulated
21
+ `PutImage`. Real `PutImage` takes an image manifest for layers that were pushed over the Docker
22
+ registry protocol. None of that happens in this process, and a simulated `PutImage` would be a
23
+ command taking an argument nothing could produce.
24
+
25
+ ## Registering a handler as an image
26
+
27
+ Register the handler once, in test setup, and every function that runs an image from that repository
28
+ is created from it.
29
+
30
+ ```typescript sim-ecr-register-image
31
+ /**
32
+ * Registering a handler as the image in a simulated ECR repository.
33
+ */
34
+
35
+ import { InvokeCommand } from "@aws-sdk/client-lambda";
36
+
37
+ import { SimAws } from "@kensio/yulin";
38
+
39
+ const simAws = new SimAws();
40
+
41
+ simAws
42
+ .ecr()
43
+ .repository("orders")
44
+ .simulateImage({
45
+ imageTag: "latest",
46
+ handler: (event: { orderId: string }): string =>
47
+ `Processed ${event.orderId}`,
48
+ });
49
+
50
+ // Any stack whose function image points into that repository runs the handler.
51
+ await simAws.cloudFormation().deployTemplate({
52
+ stackName: "orders-api",
53
+ template: {
54
+ Resources: {
55
+ OrdersFunction: {
56
+ Type: "AWS::Lambda::Function",
57
+ Properties: {
58
+ FunctionName: "orders",
59
+ Role: `arn:aws:iam::${simAws.defaultAccountId}:role/OrdersRole`,
60
+ PackageType: "Image",
61
+ Code: {
62
+ ImageUri:
63
+ `${simAws.defaultAccountId}.dkr.ecr.` +
64
+ `${simAws.defaultRegionName}.amazonaws.com/orders:2f0e1dab4c`,
65
+ },
66
+ },
67
+ },
68
+ },
69
+ },
70
+ });
71
+
72
+ const output = await simAws.lambda().invoke(
73
+ new InvokeCommand({
74
+ FunctionName: "orders",
75
+ Payload: JSON.stringify({ orderId: "order-1" }),
76
+ }),
77
+ );
78
+
79
+ if (output.Payload === undefined) throw new Error("No invoke Payload");
80
+ console.log(Buffer.from(output.Payload).toString());
81
+
82
+ await simAws.backgroundTasksComplete();
83
+ ```
84
+
85
+ Naming a repository is what creates it. A repository holds only its images. There is no prior
86
+ declaration to make, and a test can name the repository its templates already point at.
87
+
88
+ The repository takes a bare name such as `orders` or `platform/orders`, and never a full image URI.
89
+ The account, the region and the registry host around it come from the simulated ECR the repository
90
+ belongs to. A name real ECR would refuse is refused here too.
91
+
92
+ ## How an image URI is matched
93
+
94
+ Resolving an image URI happens in two steps, and the tag means something different in each.
95
+
96
+ Finding the repository ignores the tag. A function's `Code.ImageUri` is matched on the registry host
97
+ and the repository name, with any tag or digest dropped, because no tag is stable enough to write
98
+ into a test. A CDK image asset is tagged with the asset content hash, which changes whenever the
99
+ image source does, and a pipeline-built image is usually tagged with a git sha or a build number
100
+ passed in as a stack parameter. An `ImageUri` built by `Fn::Sub` or from a stack parameter is
101
+ matched on what it resolves to.
102
+
103
+ Choosing the image in that repository does read the tag. A tag the repository holds selects exactly
104
+ that image, and any other tag, or none at all, falls back to the image registered most recently.
105
+
106
+ The registry host is part of the match, and the account and the region have to agree. A function can
107
+ run an image from another account's repository, as it can on real AWS, and a same-named repository
108
+ in another account is a different repository.
109
+
110
+ So `orders:blue` runs the handler registered under `blue` where the repository holds one, and the
111
+ handler registered most recently otherwise. That is how a blue/green pair of images in one
112
+ repository can back two functions differently, while a content hash tag nobody registered still
113
+ finds something to run. Registering a tag again both replaces what it held and makes it the most
114
+ recent registration.
115
+
116
+ ```typescript sim-ecr-image-tags
117
+ /**
118
+ * Two tagged images in one simulated ECR repository.
119
+ */
120
+
121
+ import { CreateFunctionCommand, InvokeCommand } from "@aws-sdk/client-lambda";
122
+
123
+ import { SimAws } from "@kensio/yulin";
124
+
125
+ const simAws = new SimAws();
126
+ const registryHost =
127
+ `${simAws.defaultAccountId}.dkr.ecr.` +
128
+ `${simAws.defaultRegionName}.amazonaws.com`;
129
+
130
+ simAws
131
+ .ecr()
132
+ .repository("orders")
133
+ .simulateImage({ imageTag: "blue", handler: (): string => "blue handler" })
134
+ .simulateImage({ imageTag: "green", handler: (): string => "green handler" });
135
+
136
+ await simAws.lambda().createFunction(
137
+ new CreateFunctionCommand({
138
+ FunctionName: "orders-blue",
139
+ Role: `arn:aws:iam::${simAws.defaultAccountId}:role/OrdersRole`,
140
+ PackageType: "Image",
141
+ Code: { ImageUri: `${registryHost}/orders:blue` },
142
+ }),
143
+ );
144
+
145
+ const output = await simAws
146
+ .lambda()
147
+ .invoke(new InvokeCommand({ FunctionName: "orders-blue" }));
148
+
149
+ if (output.Payload === undefined) throw new Error("No invoke Payload");
150
+ console.log(Buffer.from(output.Payload).toString()); // "blue handler"
151
+
152
+ await simAws.backgroundTasksComplete();
153
+ ```
154
+
155
+ A function created directly through `CreateFunction` resolves its image the same way a template
156
+ function does, as the example above shows. A function whose image resolves to no handler is refused,
157
+ the way real Lambda refuses a function whose image it cannot pull.
158
+
159
+ ## Repositories in CloudFormation
160
+
161
+ `AWS::ECR::Repository` creates a simulated repository. A template declares a repository and never an
162
+ image, as real CloudFormation does. A deployed repository starts empty unless a handler has already
163
+ been registered in it.
164
+
165
+ `Ref` returns the repository name, and `Fn::GetAtt` exposes `Arn` and `RepositoryUri`. An
166
+ application stack can build its function's `ImageUri` from the repository a platform stack declared.
167
+
168
+ ```typescript sim-ecr-cloudformation-repository
169
+ /**
170
+ * An AWS::ECR::Repository declared by one stack and used by another.
171
+ */
172
+
173
+ import { InvokeCommand } from "@aws-sdk/client-lambda";
174
+
175
+ import { SimAws } from "@kensio/yulin";
176
+
177
+ const simAws = new SimAws();
178
+
179
+ // The platform stack declares the repository.
180
+ const platformStack = await simAws.cloudFormation().deployTemplate({
181
+ stackName: "platform",
182
+ template: {
183
+ Resources: {
184
+ OrdersRepository: {
185
+ Type: "AWS::ECR::Repository",
186
+ Properties: { RepositoryName: "orders" },
187
+ },
188
+ },
189
+ Outputs: {
190
+ RepositoryUri: {
191
+ Value: { "Fn::GetAtt": ["OrdersRepository", "RepositoryUri"] },
192
+ },
193
+ },
194
+ },
195
+ });
196
+
197
+ await platformStack.waitForDeployComplete();
198
+
199
+ const repositoryUri = platformStack.output("RepositoryUri");
200
+
201
+ if (typeof repositoryUri !== "string") {
202
+ throw new TypeError("No RepositoryUri Output");
203
+ }
204
+
205
+ // The handler stands in for whatever the pipeline would have pushed.
206
+ simAws
207
+ .ecr()
208
+ .repository("orders")
209
+ .simulateImage({ handler: (): string => "ran the repository image" });
210
+
211
+ // The application stack runs an image from it.
212
+ await simAws.cloudFormation().deployTemplate({
213
+ stackName: "orders-api",
214
+ template: {
215
+ Resources: {
216
+ OrdersFunction: {
217
+ Type: "AWS::Lambda::Function",
218
+ Properties: {
219
+ FunctionName: "orders",
220
+ Role: `arn:aws:iam::${simAws.defaultAccountId}:role/OrdersRole`,
221
+ PackageType: "Image",
222
+ Code: { ImageUri: `${repositoryUri}:latest` },
223
+ },
224
+ },
225
+ },
226
+ },
227
+ });
228
+
229
+ const output = await simAws
230
+ .lambda()
231
+ .invoke(new InvokeCommand({ FunctionName: "orders" }));
232
+
233
+ if (output.Payload === undefined) throw new Error("No invoke Payload");
234
+ console.log(Buffer.from(output.Payload).toString());
235
+
236
+ await simAws.backgroundTasksComplete();
237
+ ```
238
+
239
+ A repository a handler is already registered in is adopted, and the order these happen in makes no
240
+ difference. The image can exist before the stack that declares the repository, as it does in real
241
+ life.
242
+
243
+ Tearing the stack down removes the repository only where it holds no simulated image. One that does
244
+ is left where it is, and the deletion is recorded as skipped, because the handler in it was
245
+ registered outside any stack and is what every later deploy resolves to. Real ECR also refuses to
246
+ delete a repository that still holds images, which fails the stack unless the template says
247
+ `EmptyOnDelete`. Here the refusal is recorded and the teardown carries on, since what is being
248
+ protected is a test's own registration.
249
+
250
+ Every other property a repository can declare is recorded as an ignored property, and the repository
251
+ is created without it. That covers `ImageScanningConfiguration`, `ImageTagMutability`,
252
+ `LifecyclePolicy`, `RepositoryPolicyText`, `EncryptionConfiguration`, `EmptyOnDelete` and `Tags`.
253
+
254
+ ## Where a function's handler comes from
255
+
256
+ Two things can back a container image function, and a deploy is looked at in this order:
257
+
258
+ 1. An [executable binding](https://yulinsim.dev/services/lambda/#executable-bindings) given to that deploy, including one
259
+ naming the image repository. A binding is the more specific thing to have said, since it is about
260
+ one deploy.
261
+ 2. The simulated ECR repository the function's `Code.ImageUri` names. That is a standing statement
262
+ about what the image is, made once and good for every stack that runs it.
263
+
264
+ A function with no binding and no registered image is skipped with a diagnostic, and the rest of the
265
+ stack deploys. The reason separates a missing repository from an empty one, since those send you to
266
+ different places. One is a wrong name, and the other is a handler that was never registered.
267
+
268
+ ## Available functionality
269
+
270
+ - Repositories, made by naming them, scoped by account and region
271
+ - `simulateImage`, registering a real in-process handler as the image under a tag
272
+ - Resolution of a Lambda `Code.ImageUri` to that handler, finding the repository on registry host
273
+ and name alone, then reading the tag to choose between the images it holds
274
+ - Functions created from a repository image through CloudFormation and through `CreateFunction`
275
+ - Images resolved across accounts and regions, as real Lambda pulls across them
276
+ - `AWS::ECR::Repository`, answering `Ref` with the repository name and `Fn::GetAtt` with `Arn` and
277
+ `RepositoryUri`
278
+
279
+ ## Limitations
280
+
281
+ Current documented limitations:
282
+
283
+ - No image content, layer, digest, manifest or scan behaviour is simulated. A repository holds
284
+ handlers, and no image is ever pulled or inspected.
285
+ - There are no ECR SDK commands. `CreateRepository`, `DescribeRepositories`, `PutImage`,
286
+ `DescribeImages`, `BatchDeleteImage` and `GetAuthorizationToken` are all absent. Registering an
287
+ image is a Yulin-native operation because real `PutImage` takes a manifest for layers pushed over
288
+ the Docker registry protocol, and that protocol never runs in this process.
289
+ - Nothing authorizes against a repository. With no requests to authorize, a repository policy goes
290
+ unread and simulated IAM stays out of it.
291
+ - Lifecycle policies go unevaluated, and no simulated image ever expires. Tag mutability goes
292
+ unenforced, and registering the same tag again replaces what it held.
293
+ - Naming a repository creates it. There is no `CreateRepository` to fail for a name already taken,
294
+ and no way to ask whether a repository exists without making one, other than `hasRepository`.
295
+ - A stack teardown records the deletion of a repository holding a simulated image and carries on,
296
+ where real CloudFormation fails the stack unless the template says `EmptyOnDelete`. The repository
297
+ and its handler are left in place, and `EmptyOnDelete` itself goes unread.
298
+ - Nothing tracks which stack created a repository. A repository holding no simulated image is
299
+ removed by the teardown of any stack that declared it, and made again by the next deploy.
300
+ - Repository tags, registry policies, pull through cache rules, replication configuration and ECR
301
+ Public are not simulated.
302
+ - ECR has no HTTP API under `serveSimAws`, and nothing for a Docker client to talk to.