@kensio/yulin 1.21.6 → 1.21.8

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 (74) hide show
  1. package/README.md +22 -2
  2. package/dist/service/eventbridge/cfn/bus/sim-cfn-event-bus-creator.js +1 -0
  3. package/dist/service/eventbridge/cfn/bus/sim-cfn-event-bus-properties.d.ts +4 -0
  4. package/dist/service/eventbridge/cfn/bus/sim-cfn-event-bus-properties.js +26 -1
  5. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-creator.js +3 -1
  6. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-properties.d.ts +0 -7
  7. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-properties.js +0 -20
  8. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-unsimulated-properties.d.ts +13 -0
  9. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-unsimulated-properties.js +59 -0
  10. package/dist/service/eventbridge/cfn/sim-cfn-event-bridge-resource-error.d.ts +1 -1
  11. package/dist/service/eventbridge/cfn/sim-cfn-event-bridge-resource-error.js +1 -1
  12. package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-properties.js +1 -1
  13. package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-property-rules.d.ts +3 -2
  14. package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-property-rules.js +25 -3
  15. package/dist/service/ses/command/authorize/sim-ses-authorizer.d.ts +9 -0
  16. package/dist/service/ses/command/authorize/sim-ses-authorizer.js +18 -2
  17. package/dist/service/ses/command/send/sim-ses-send-email.js +2 -1
  18. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-creator.js +1 -0
  19. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-properties.d.ts +9 -4
  20. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-properties.js +18 -6
  21. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-property-names.d.ts +10 -0
  22. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-property-names.js +16 -1
  23. package/dist/service/ssm/cfn/parameter/sim-cfn-ssm-parameter-creator.js +1 -1
  24. package/dist/service/ssm/cfn/parameter/sim-cfn-ssm-parameter-properties.d.ts +11 -6
  25. package/dist/service/ssm/cfn/parameter/sim-cfn-ssm-parameter-properties.js +18 -9
  26. package/docs/README.md +40 -4
  27. package/docs/ai-skill/README.md +57 -54
  28. package/docs/cli/README.md +84 -94
  29. package/docs/factories/README.md +42 -54
  30. package/docs/lint/README.md +41 -67
  31. package/docs/non-aws-dependencies/README.md +72 -168
  32. package/docs/sdk/README.md +109 -95
  33. package/docs/serve/README.md +192 -898
  34. package/docs/services/acm/README.md +24 -40
  35. package/docs/services/apigateway/README.md +52 -71
  36. package/docs/services/apigatewayv2/README.md +55 -74
  37. package/docs/services/athena/README.md +17 -26
  38. package/docs/services/backup/README.md +29 -39
  39. package/docs/services/bedrock/README.md +38 -52
  40. package/docs/services/cloudformation/README.md +43 -55
  41. package/docs/services/cloudfront/README.md +69 -95
  42. package/docs/services/cloudwatch/README.md +40 -54
  43. package/docs/services/cognito/README.md +30 -45
  44. package/docs/services/dynamodb/README.md +34 -51
  45. package/docs/services/ecr/README.md +36 -77
  46. package/docs/services/ecs/README.md +26 -46
  47. package/docs/services/elbv2/README.md +19 -29
  48. package/docs/services/eventbridge/README.md +24 -20
  49. package/docs/services/firehose/README.md +24 -32
  50. package/docs/services/glue/README.md +41 -78
  51. package/docs/services/iam/README.md +13 -15
  52. package/docs/services/kinesis/README.md +53 -93
  53. package/docs/services/kms/README.md +22 -32
  54. package/docs/services/lambda/README.md +60 -80
  55. package/docs/services/logs/README.md +41 -50
  56. package/docs/services/organizations/README.md +50 -85
  57. package/docs/services/personalize/README.md +28 -44
  58. package/docs/services/rekognition/README.md +26 -38
  59. package/docs/services/route53/README.md +17 -17
  60. package/docs/services/s3/README.md +47 -51
  61. package/docs/services/scheduler/README.md +41 -52
  62. package/docs/services/secretsmanager/README.md +27 -42
  63. package/docs/services/ses/README.md +24 -34
  64. package/docs/services/sns/README.md +31 -33
  65. package/docs/services/sqs/README.md +14 -14
  66. package/docs/services/ssm/README.md +19 -21
  67. package/docs/services/stepfunctions/README.md +18 -20
  68. package/docs/services/sts/README.md +32 -45
  69. package/docs/services/wafv2/README.md +12 -17
  70. package/docs/terraform/README.md +108 -126
  71. package/docs/testing/README.md +228 -0
  72. package/docs/time/README.md +87 -117
  73. package/llms.txt +2 -1
  74. package/package.json +1 -1
@@ -1,11 +1,12 @@
1
1
  # Simulated Route53
2
2
 
3
- Yulin includes a simulated Route53 service for tests and local development.
3
+ Yulin simulates Amazon Route 53 hosted zones, records and DNSSEC configuration for tests and local
4
+ development. You can manage them through the AWS SDK or deploy them from CloudFormation and CDK
5
+ templates. When Yulin serves the simulation on localhost, Route 53 records can route local hostnames
6
+ to simulated services such as CloudFront distributions and S3 bucket websites.
4
7
 
5
- Sim Route53 can be used directly through `SimAws`, instantiated on its own as `SimRoute53`, and used
6
- by sim CloudFormation when deploying Route53 resources from CloudFormation or CDK templates. When
7
- served on localhost, Route53 records can route custom local hostnames to other simulated AWS
8
- services, such as simulated CloudFront distributions or simulated S3 bucket websites.
8
+ Use Route 53 through `SimAws` when it should share state with other services. Use `SimRoute53`
9
+ directly when you need an isolated Route 53 simulation.
9
10
 
10
11
  ## Basic Hosted Zone usage
11
12
 
@@ -54,8 +55,8 @@ console.log(hostedZoneOut.HostedZone?.ResourceRecordSetCount);
54
55
  Hosted Zone names are normalised with a trailing dot in Route53-style outputs, so `example.test`
55
56
  becomes `example.test.`.
56
57
 
57
- Hosted Zone creation uses background tasks to move the zone to `INSYNC`. If your test needs final
58
- state, call `await simAws.backgroundTasksComplete()` before continuing.
58
+ Hosted zone creation moves the zone to `INSYNC` in a background task. Call
59
+ `await simAws.backgroundTasksComplete()` before asserting on the final state.
59
60
 
60
61
  Hosted Zone IDs are accepted in any real Route53 shape, being a `Z` prefix followed by uppercase
61
62
  alphanumerics, up to 32 characters. A real Hosted Zone ID copied out of an AWS account, such as
@@ -65,14 +66,12 @@ alphanumerics, up to 32 characters. A real Hosted Zone ID copied out of an AWS a
65
66
 
66
67
  ## Registering a Hosted Zone with a chosen ID
67
68
 
68
- `CreateHostedZoneCommand` allocates its own Hosted Zone ID, as real Route53 does, and takes none
69
- from you. When something else already decided the ID, register the Hosted Zone as part of your test
70
- setup instead.
69
+ `CreateHostedZoneCommand` allocates the hosted zone ID. When a synthesized template already contains
70
+ an ID, register that hosted zone during test setup instead.
71
71
 
72
- The usual reason is a CDK app that looks its zone up with `HostedZone.fromLookup` instead of
73
- creating it. That bakes the real Hosted Zone ID into the synthesized template, and every
74
- `AWS::Route53::RecordSet` in the template names that ID. Registering the zone first lets the
75
- template deploy as it is, with no rewriting.
72
+ For example, `HostedZone.fromLookup` writes the resolved hosted zone ID into the synthesized
73
+ template. Registering that ID before deployment lets its `AWS::Route53::RecordSet` resources deploy
74
+ without changing the template.
76
75
 
77
76
  ```typescript sim-route53-register-hosted-zone
78
77
  /**
@@ -1701,8 +1700,9 @@ await scopedRoute53.createHostedZone(
1701
1700
  );
1702
1701
  ```
1703
1702
 
1704
- Each `SimAws` instance has its own isolated state. Create a fresh instance per test, or share one
1705
- across related local setup.
1703
+ Each `SimAws` instance has its own isolated state. Application tests should normally use the instance
1704
+ from their shared [test suite setup](https://yulinsim.dev/testing/). A fresh instance remains useful
1705
+ when a test specifically needs an empty simulated account.
1706
1706
 
1707
1707
  ## Standalone SimRoute53
1708
1708
 
@@ -1732,7 +1732,7 @@ console.log(hostedZoneCreation.HostedZone?.Id);
1732
1732
  A standalone `SimRoute53` instance has its own isolated state, standing apart from any wider
1733
1733
  `SimAws` environment. Use `SimAws` when Route53 needs to resolve names to other simulated services.
1734
1734
 
1735
- ## Available functionality
1735
+ ## Supported operations
1736
1736
 
1737
1737
  Sim Route53 currently supports:
1738
1738
 
@@ -1,13 +1,12 @@
1
1
  # Simulated S3
2
2
 
3
- Yulin includes a simulated S3 service for tests and local development.
3
+ Yulin simulates S3 buckets, objects, policies, notifications and website hosting. Use
4
+ `simAws.s3()` as part of a simulated AWS environment or create a standalone `SimS3`.
5
+ `serveSimAws` exposes the S3 API and website endpoints over localhost.
4
6
 
5
- Sim S3 can be used directly through `SimAws` or instantiated on its own as `SimS3` with isolated
6
- state. Yulin can serve a simulated S3 service on localhost.
7
+ ## Create a bucket and object
7
8
 
8
- ## Basic usage
9
-
10
- Create a simulated AWS environment, get simulated S3, create a Bucket, and put an Object into it.
9
+ Create a bucket, write an object and read it back.
11
10
 
12
11
  ```typescript sim-s3-bucket
13
12
  /**
@@ -104,15 +103,15 @@ await scopedS3.createBucket(
104
103
  );
105
104
  ```
106
105
 
107
- Within one `SimAws` instance, Bucket names are globally registered across Accounts and Regions.
108
- Creating a Bucket with a name already used in another simulated Region or Account throws an error.
106
+ Bucket names are global within a `SimAws` instance. Creating the same name in another simulated
107
+ account or region fails.
109
108
 
110
- Each `SimAws` instance has its own isolated state. Create a fresh one per test or share one across
111
- all tests, as you prefer.
109
+ Each `SimAws` instance has isolated state.
112
110
 
113
- ## Listing Buckets
111
+ ## Listing buckets
114
112
 
115
- Use `ListBucketsCommand` to inspect Buckets in the selected simulated S3 scope. Each Bucket reports the instant it was created, taken from [simulated time](https://yulinsim.dev/time/) rather than the host clock.
113
+ `ListBucketsCommand` lists buckets in the selected account and region. Each bucket reports its
114
+ creation time from the [simulated clock](https://yulinsim.dev/time/).
116
115
 
117
116
  ```typescript sim-s3-list-buckets
118
117
  /**
@@ -137,17 +136,20 @@ console.log(listBucketsOutput.Buckets?.map((bucket) => bucket.Name));
137
136
  console.log(listBucketsOutput.Buckets?.[0]?.CreationDate);
138
137
  ```
139
138
 
140
- ## Asking whether something is there
139
+ ## Checking whether a bucket or object exists
141
140
 
142
- `HeadObjectCommand` reports what a read would say about an Object without returning the Object, and `HeadBucketCommand` reports whether a Bucket is there and reachable. `HeadBucket` also reports the Region it was found in.
141
+ `HeadObjectCommand` returns object metadata without the body. `HeadBucketCommand` checks that a
142
+ bucket exists and is accessible, and reports its region.
143
143
 
144
- A HEAD response carries no body, so there is no document for an error code to travel in. Real S3 answers a `HeadObject` with `403` or `404`, and a `HeadBucket` with `400`, `403` or `404`, leaving the SDK to name the failure from the status alone. The simulator answers `404` for an absent Bucket and an absent Object alike, which an SDK client raises as `NotFound`, and `403` for a caller the permission is missing for. A read distinguishes `NoSuchBucket` from `NoSuchKey`, because a read has a body to say which.
144
+ A HEAD response has no error document. Yulin returns 404 for a missing bucket or object, which the
145
+ SDK raises as `NotFound`. It returns 403 when the caller lacks permission. `GetObject` can distinguish
146
+ `NoSuchBucket` from `NoSuchKey` because its error response has a body.
145
147
 
146
148
  `HeadObject` authorizes against `s3:GetObject` and `HeadBucket` against `s3:ListBucket`, as real S3 does, so knowing something is there needs the permission to read it.
147
149
 
148
- ## Listing Objects
150
+ ## Listing objects
149
151
 
150
- Use `ListObjectsV2Command` to list the Objects in a Bucket. The simulator supports `Prefix`,
152
+ Use `ListObjectsV2Command` to list objects in a bucket. Yulin supports `Prefix`,
151
153
  `Delimiter`, `MaxKeys`, `ContinuationToken` and `StartAfter`, and answers with `Contents`,
152
154
  `CommonPrefixes`, `KeyCount`, `IsTruncated` and `NextContinuationToken`.
153
155
 
@@ -197,18 +199,16 @@ for (const object of listedObjects) {
197
199
  }
198
200
  ```
199
201
 
200
- Listings are sorted by key, and a page holds at most 1,000 keys, as in real S3. `MaxKeys` above that
201
- is lowered to it, and the response reports the page size that was actually used. A `MaxKeys` of zero
202
- returns no keys and completes the listing, and a negative one is refused with `InvalidArgument`.
202
+ Listings sort objects by key and return at most 1,000 entries. Larger `MaxKeys` values are capped at
203
+ 1,000. Zero returns an empty complete page, and a negative value raises `InvalidArgument`.
203
204
 
204
205
  A listing that found no keys has no `Contents` at all, and the example reaches for `Contents ?? []`
205
206
  for that reason. `KeyCount` is the count either way.
206
207
 
207
208
  ### Walking a truncated listing
208
209
 
209
- A truncated response carries `NextContinuationToken`, which the next request passes as
210
- `ContinuationToken`. The token is opaque, as it is in real S3. Pass it back unchanged, read nothing
211
- out of it, and simulated S3 refuses one it did not issue.
210
+ A truncated response includes `NextContinuationToken`. Pass it unchanged as `ContinuationToken` in
211
+ the next request. Yulin rejects tokens it did not issue.
212
212
 
213
213
  ```typescript sim-s3-list-objects-v2-pagination
214
214
  /**
@@ -533,9 +533,8 @@ An Object uploaded in parts gets a different form. See
533
533
 
534
534
  ## Uploading an Object in parts
535
535
 
536
- `aws s3 cp` switches to a multipart upload above eight megabytes, and `@aws-sdk/lib-storage` uploads
537
- in parts whatever the size. Sim S3 answers the six operations that path is made of, over the SDK and
538
- over a served endpoint alike.
536
+ Yulin supports multipart upload through the SDK and served S3 endpoint. This covers the operations
537
+ used by `aws s3 cp` for files above eight megabytes and by `@aws-sdk/lib-storage`.
539
538
 
540
539
  ```bash
541
540
  aws s3 cp ./big.bin s3://widgets/big.bin # 12MB, multipart under the covers
@@ -846,9 +845,8 @@ See [Serve simulated S3 on localhost](#serve-simulated-s3-on-localhost) for sett
846
845
 
847
846
  ## Deleting Objects
848
847
 
849
- Use `DeleteObjectCommand` to remove one Object, and `DeleteObjectsCommand` to remove several in one
850
- request. Both are authorized against `s3:DeleteObject` on the Object ARN. A caller allowed to read a
851
- Bucket cannot empty it.
848
+ Use `DeleteObjectCommand` to remove one object or `DeleteObjectsCommand` to remove several. Each
849
+ object requires `s3:DeleteObject` permission on its ARN.
852
850
 
853
851
  ```typescript sim-s3-delete-object
854
852
  /**
@@ -931,9 +929,9 @@ failures come back.
931
929
 
932
930
  ## Object versioning
933
931
 
934
- A versioned Bucket keeps every write of a key instead of overwriting it, and answers a delete with a
935
- marker rather than removing anything. Turn it on with `PutBucketVersioningCommand`, or with
936
- `VersioningConfiguration` on an `AWS::S3::Bucket` resource.
932
+ A versioned bucket keeps each write as a separate version. Deleting a key adds a delete marker. Enable
933
+ versioning with `PutBucketVersioningCommand` or the `VersioningConfiguration` property of an
934
+ `AWS::S3::Bucket`.
937
935
 
938
936
  ```typescript sim-s3-object-versioning
939
937
  import {
@@ -1096,12 +1094,11 @@ A delete on a versioned Bucket raises `s3:ObjectRemoved:DeleteMarkerCreated` rat
1096
1094
 
1097
1095
  ## Object Lock
1098
1096
 
1099
- Object Lock holds a version of an Object against a delete. A version can be held by a retention
1100
- period, by a legal hold or by both, and a delete naming a held version is answered with
1101
- `AccessDenied`. One way past exists and it is narrow. A `GOVERNANCE` retention period gives way to a
1102
- request carrying `BypassGovernanceRetention` from a caller allowed to use it. A `COMPLIANCE` period
1103
- and a legal hold hold against everyone, the account root included. Turn it on with `PutObjectLockConfigurationCommand`, or with
1104
- `ObjectLockEnabled` on an `AWS::S3::Bucket` resource.
1097
+ Object Lock protects an object version with a retention period, a legal hold, or both. Deleting a
1098
+ protected version raises `AccessDenied`. A caller with `s3:BypassGovernanceRetention` may bypass
1099
+ `GOVERNANCE` retention by setting `BypassGovernanceRetention`. `COMPLIANCE` retention and legal
1100
+ holds cannot be bypassed. Enable Object Lock with `PutObjectLockConfigurationCommand` or
1101
+ `ObjectLockEnabled` on an `AWS::S3::Bucket`.
1105
1102
 
1106
1103
  Object Lock holds a version, and versioning has to be on underneath it. Turning it on over a Bucket
1107
1104
  with versioning off is refused with `InvalidBucketState`, as real S3 refuses it, and a template
@@ -1256,8 +1253,8 @@ Bucket created around the property would report a default retention it never app
1256
1253
 
1257
1254
  ## Event notifications
1258
1255
 
1259
- A simulated S3 Bucket can notify a simulated Lambda function, a simulated SQS queue or a simulated
1260
- SNS topic when an Object is created or removed. The configuration is applied with
1256
+ A simulated bucket can notify Lambda, SQS or SNS when an object is created or removed. Apply the
1257
+ configuration with
1261
1258
  `PutBucketNotificationConfigurationCommand` and read back with
1262
1259
  `GetBucketNotificationConfigurationCommand`.
1263
1260
 
@@ -1360,10 +1357,10 @@ can take the `.jpg` files under a prefix while another takes the `.png` files un
1360
1357
  The rule applies across the destination groups. A function and a queue that both want the same
1361
1358
  event are refused as readily as two functions.
1362
1359
 
1363
- `PutBucketNotificationConfigurationCommand` replaces the whole configuration rather than adding to
1364
- it. `GetBucketNotificationConfigurationCommand` answers an empty configuration for a Bucket that has
1365
- none. Note that the response carries the destination groups at the top level, while the request nests
1366
- them under `NotificationConfiguration`:
1360
+ `PutBucketNotificationConfigurationCommand` replaces the complete configuration.
1361
+ `GetBucketNotificationConfigurationCommand` returns an empty configuration when none is set. The
1362
+ request nests destination groups under `NotificationConfiguration`, while the response puts them at
1363
+ the top level:
1367
1364
 
1368
1365
  ```typescript
1369
1366
  const read = await simAws
@@ -1476,9 +1473,9 @@ function is.
1476
1473
 
1477
1474
  ### To an SQS queue
1478
1475
 
1479
- A `QueueConfigurations` entry names a queue by ARN. The whole `Records` document arrives as one
1480
- message body, and a consumer parses `record.body` to get at the event. Put a Lambda event source
1481
- mapping on the queue and the chain runs end to end after one `backgroundTasksComplete()`.
1476
+ A `QueueConfigurations` entry names a queue by ARN. S3 sends the complete `Records` document as one
1477
+ message body. Add a Lambda event source mapping to consume it, then call
1478
+ `backgroundTasksComplete()` to finish the delivery chain.
1482
1479
 
1483
1480
  The queue's `Policy` attribute has to allow `sqs:SendMessage` for the `s3.amazonaws.com` service
1484
1481
  principal. S3 supplies `aws:SourceArn` and `aws:SourceAccount`. The `ArnLike` condition CDK's
@@ -1633,10 +1630,9 @@ its own policy and its own Account's IAM are what admit the Bucket. A FIFO queue
1633
1630
 
1634
1631
  ### To an SNS topic
1635
1632
 
1636
- A `TopicConfigurations` entry names a topic by ARN. The whole `Records` document is published as the
1637
- SNS `Message`, with a `Subject` of `Amazon S3 Notification`, as real S3 publishes it. A queue
1638
- subscribed to the topic therefore has two envelopes to reach through. Parse the message body for the
1639
- SNS envelope, then parse its `Message` for the S3 event.
1633
+ A `TopicConfigurations` entry names a topic by ARN. S3 publishes the complete `Records` document as
1634
+ the SNS `Message` with the subject `Amazon S3 Notification`. A subscribed queue receives an SNS
1635
+ envelope whose `Message` contains the S3 event.
1640
1636
 
1641
1637
  The topic's `Policy` attribute has to allow `sns:Publish` for the `s3.amazonaws.com` service
1642
1638
  principal. S3 supplies `aws:SourceArn` and `aws:SourceAccount`. The `ArnLike` condition CDK's
@@ -1,14 +1,12 @@
1
1
  # Simulated EventBridge Scheduler
2
2
 
3
- Yulin includes a simulated Amazon EventBridge Scheduler for tests and local development. Schedules
4
- are held in memory and every operation is authorized by simulated IAM. Scheduler-specific types are
5
- imported from the `@kensio/yulin/scheduler` subpath.
3
+ Yulin simulates Amazon EventBridge Scheduler in memory. Schedules run when simulated time advances,
4
+ and every management operation is authorized by simulated IAM. Import Scheduler-specific types from
5
+ `@kensio/yulin/scheduler`.
6
6
 
7
- Scheduler is a separate service from [EventBridge](https://yulinsim.dev/services/eventbridge/), not a corner of it. It has its
8
- own SDK client, its own ARN shape, and its own way of reaching a target. A schedule assumes an IAM
9
- execution role, where an EventBridge rule relies on a resource policy admitting a service principal.
10
- A project using Scheduler cannot be tested against simulated EventBridge rules. That is why this
11
- exists separately.
7
+ Scheduler is separate from [EventBridge](https://yulinsim.dev/services/eventbridge/). It uses its own
8
+ SDK client and ARN format. It also assumes an execution role to invoke a target, while EventBridge
9
+ rules use the target's resource policy.
12
10
 
13
11
  ## Creating a schedule
14
12
 
@@ -56,8 +54,7 @@ IAM policy naming a schedule needs the group in it, or it matches no schedule.
56
54
 
57
55
  ## Writing the schedule expression
58
56
 
59
- Three forms, and the same parser as an [EventBridge scheduled
60
- rule](https://yulinsim.dev/services/eventbridge/#rules-that-fire-on-a-schedule) with two differences:
57
+ Scheduler accepts three expression forms:
61
58
 
62
59
  - `at(yyyy-mm-ddThh:mm:ss)` runs once, at that instant. The timezone is a separate setting on the
63
60
  schedule, outside the expression, and a trailing `Z` is refused.
@@ -71,9 +68,7 @@ rule](https://yulinsim.dev/services/eventbridge/#rules-that-fire-on-a-schedule)
71
68
 
72
69
  ## Firing a schedule
73
70
 
74
- A schedule fires on the simulation's clock. Advancing simulated time past a due
75
- instant invokes the target. Leave time alone and the target is never invoked. A nightly job takes no
76
- time at all to test.
71
+ A schedule fires on the simulation's clock. Advance time past a due instant to invoke the target.
77
72
 
78
73
  ```typescript sim-scheduler-firing
79
74
  /**
@@ -163,12 +158,11 @@ own to describe.
163
158
 
164
159
  ### The execution role
165
160
 
166
- This is the part that differs most from an [EventBridge rule](https://yulinsim.dev/services/eventbridge/), and the part that
167
- most often goes wrong in a real account. A rule reaches its target as the `events.amazonaws.com`
168
- service principal, and the target's own resource policy decides. A schedule assumes the `RoleArn` on
169
- its target, and that role's policies decide. No resource policy on the target is involved at all.
161
+ A schedule assumes the target's `RoleArn`, and that role's policies authorize delivery. An
162
+ [EventBridge rule](https://yulinsim.dev/services/eventbridge/) instead invokes as
163
+ `events.amazonaws.com` and depends on the target's resource policy.
170
164
 
171
- Two things therefore have to be right, and they are fixed in different places:
165
+ The execution role needs both:
172
166
 
173
167
  - The role's **trust policy** has to let `scheduler.amazonaws.com` assume it. A role copied from an
174
168
  EventBridge rule trusts `events.amazonaws.com` and fails here.
@@ -176,14 +170,13 @@ Two things therefore have to be right, and they are fixed in different places:
176
170
  `sqs:SendMessage`, `sns:Publish` or `ecs:RunTask`.
177
171
 
178
172
  A trust policy may also carry the condition AWS recommends against the confused deputy problem. The
179
- schedule's group ARN is supplied as `aws:SourceArn`, and the Account the schedule is in as
180
- `aws:SourceAccount`. A role scoped to one schedule group is assumable by schedules in that group and
181
- by nothing else. CDK writes that condition into the execution roles it generates for a schedule
182
- target, so a role taken from a synthesized template works here unchanged.
173
+ schedule's group ARN is supplied as `aws:SourceArn`, and the account is supplied as
174
+ `aws:SourceAccount`. A role scoped to one schedule group is assumable only by schedules in that
175
+ group. CDK writes that condition into the execution roles it generates for a schedule target, so a
176
+ role from a synthesized template works unchanged.
183
177
 
184
- When either is missing the target goes uninvoked and no error is thrown, exactly as on AWS, where the
185
- failure goes to CloudWatch and nowhere the caller can see. `advanceBy(...)` still returns normally. A
186
- test asserting on a failed invocation reads `deliveryFailures`:
178
+ If either permission is missing, `advanceBy(...)` still returns normally and the target is not
179
+ invoked. Read `deliveryFailures` to assert on the failed delivery:
187
180
 
188
181
  ```typescript sim-scheduler-delivery-failures
189
182
  /**
@@ -256,9 +249,8 @@ following delay doubles to 2, 4, 8 seconds and so on. A retry does not run while
256
249
  still. `advanceBy(...)` runs every retry that becomes due in the interval and settles their work
257
250
  before it returns.
258
251
 
259
- Scheduler does not retry a failure that cannot clear by trying the same request. A missing target,
260
- a missing execution role, an execution role that does not trust Scheduler and an IAM denial are
261
- permanent failures. They are abandoned after the initial attempt.
252
+ Scheduler retries only failures that may clear. A missing target, missing execution role, invalid
253
+ trust policy, or IAM denial is permanent and is abandoned after the initial attempt.
262
254
 
263
255
  Set `Target.DeadLetterConfig.Arn` to a standard SQS queue ARN to keep an input that Scheduler abandons.
264
256
  The execution role needs `sqs:SendMessage` on this queue as well as permission to invoke the target.
@@ -267,19 +259,17 @@ shape and include the error, schedule ARN, target ARN, scheduled time and retry
267
259
  `EXHAUSTED_RETRY_CONDITION` is `MaximumRetryAttempts` or `MaximumEventAgeInSeconds` for an exhausted
268
260
  retryable failure. A permanent failure leaves that attribute out.
269
261
 
270
- A successful DLQ send does not add an entry to `deliveryFailures`, since the configured destination
271
- received the input. A missing queue or denied `sqs:SendMessage` is recorded there instead. This keeps
272
- a misconfigured DLQ visible to a test.
262
+ A successful DLQ send leaves `deliveryFailures` empty because the configured destination received the
263
+ input. A missing queue or denied `sqs:SendMessage` is recorded there instead.
273
264
 
274
265
  ### One-time schedules and what happens after
275
266
 
276
- An `at(...)` schedule fires once and then stops. By default it stays in the Account afterwards, which
277
- surprises people who expected it to clean up. It keeps counting against the schedule quota and keeps
278
- turning up in listings. `ActionAfterCompletion: "DELETE"` is what removes it, and after that
279
- `GetSchedule` reports it gone.
267
+ An `at(...)` schedule fires once. It remains in the account unless
268
+ `ActionAfterCompletion: "DELETE"` removes it. A retained schedule continues to appear in listings
269
+ and count against the schedule quota.
280
270
 
281
- A schedule that is disabled when its only instant passes has not completed, since nothing was
282
- invoked. It is still there afterwards whatever `ActionAfterCompletion` says.
271
+ A disabled schedule remains incomplete when its only instant passes. It stays in the account
272
+ regardless of `ActionAfterCompletion`.
283
273
 
284
274
  `State: "DISABLED"` stops a recurring schedule firing while it is off, and an `UpdateSchedule`
285
275
  enabling it picks up from the next due instant. What it missed is never replayed. An update that
@@ -287,9 +277,8 @@ changes the expression reschedules from the new one.
287
277
 
288
278
  ## Running an ECS task on a schedule
289
279
 
290
- A target whose ARN names an ECS cluster runs a [simulated ECS](https://yulinsim.dev/services/ecs/) task, in place of being
291
- invoked with a payload. That is the shape a nightly batch job usually has. A container runs, does
292
- its work and stops.
280
+ A target whose ARN names an ECS cluster runs a [simulated ECS](https://yulinsim.dev/services/ecs/)
281
+ task. Use `EcsParameters` to select the task definition and use `Input` for task overrides.
293
282
 
294
283
  ```typescript sim-scheduler-ecs-target
295
284
  /**
@@ -404,8 +393,8 @@ target with no `Input` runs the task with no overrides.
404
393
 
405
394
  [Simulated ECS](https://yulinsim.dev/services/ecs/) decides which containers actually run. A container
406
395
  with a binding runs its handler, and a container without one is recorded as not simulated.
407
- A target naming a task definition with nothing bound therefore records a task that never started,
408
- and the schedule counts as invoked.
396
+ A target naming a task definition without a bound container records a task that never started, and
397
+ the schedule counts as invoked.
409
398
 
410
399
  ## Updating and deleting
411
400
 
@@ -457,8 +446,8 @@ console.log(described.ScheduleExpression); // "rate(30 minutes)"
457
446
  console.log(described.Description); // undefined, and not by accident
458
447
  ```
459
448
 
460
- `UpdateSchedule` carries the whole of a schedule, and anything an earlier request set and this one
461
- leaves out is gone. That is real behaviour and a common surprise. The schedule has to exist.
449
+ `UpdateSchedule` replaces the full schedule definition. Any optional value omitted from the update
450
+ is removed. The schedule must already exist.
462
451
  Updating one that is absent raises `ResourceNotFoundException`. EventBridge's `PutRule` creates it.
463
452
 
464
453
  `CreateSchedule` for a name that already exists raises `ConflictException`. A deployment running it
@@ -618,10 +607,10 @@ against the `RoleArn` on the target.
618
607
 
619
608
  ## Deploying from a CloudFormation template
620
609
 
621
- `AWS::Scheduler::Schedule` deploys through [simulated CloudFormation](https://yulinsim.dev/services/cloudformation/). A stack
622
- that declares its schedules can be exercised end to end, with no SDK calls of its own. Everything the
623
- Resource carries lines up with `CreateSchedule`, and a target ARN or execution role resolved by
624
- `Fn::GetAtt` from the same template works as it would in a real deployment.
610
+ `AWS::Scheduler::Schedule` deploys through [simulated
611
+ CloudFormation](https://yulinsim.dev/services/cloudformation/). Its properties follow
612
+ `CreateSchedule`, and the target ARN or execution role can use `Fn::GetAtt` references to resources
613
+ in the same template.
625
614
 
626
615
  ```typescript sim-scheduler-cloudformation
627
616
  /**
@@ -786,7 +775,7 @@ anyway. Read the record back from `stack.getResource("<logicalId>")?.ignoredProp
786
775
  Tearing the stack down removes the group. Its schedules go with it, whether or not they are
787
776
  Resources of the same stack.
788
777
 
789
- ## Available functionality
778
+ ## Supported operations
790
779
 
791
780
  - `CreateSchedule`, `GetSchedule`, `UpdateSchedule`, `DeleteSchedule` and `ListSchedules`.
792
781
  - `at(...)`, `rate(...)` and six-field `cron(...)` expressions, fired by advancing the simulation's
@@ -839,7 +828,7 @@ Resources of the same stack.
839
828
  - A target `EventBridgeParameters`, `KinesisParameters`, `SageMakerPipelineParameters` and
840
829
  `SqsParameters` are refused outright, as is `EcsParameters` on a target whose ARN names something
841
830
  other than an ECS cluster. A `DeadLetterConfig` must name a standard SQS queue because simulated
842
- SQS does not support FIFO queues.
831
+ SQS supports only standard queues.
843
832
  - An ECS target's `EcsParameters` takes `TaskDefinitionArn` and `TaskCount`, and takes and ignores
844
833
  `LaunchType`, `PlatformVersion`, `NetworkConfiguration` and `CapacityProviderStrategy`, since
845
834
  there is no placement and no network here for them to apply to. Anything else it can carry, such
@@ -849,5 +838,5 @@ Resources of the same stack.
849
838
  on an ECS target, where every other target type takes any text.
850
839
  - A `TaskCount` above one runs that many simulated tasks, and a bound container handler runs once
851
840
  for each of them, in this process and one after another.
852
- - `KmsKeyArn` is refused, and `ClientToken` is accepted and ignored. Schedule management requests
853
- are not retried, so the token has no request to make idempotent.
841
+ - `KmsKeyArn` is refused, and `ClientToken` is accepted and ignored. Yulin makes each schedule
842
+ management request once, so the token has no retry to make idempotent.
@@ -1,7 +1,7 @@
1
1
  # Simulated Secrets Manager
2
2
 
3
- Yulin includes a simulated AWS Secrets Manager for tests and local development. Secrets are stored
4
- in memory, versioned by staging label, and every operation is authorized by simulated IAM.
3
+ Yulin simulates AWS Secrets Manager in memory. Secrets have encrypted versions and staging labels,
4
+ and simulated IAM authorizes every operation.
5
5
 
6
6
  Secrets Manager-specific types are imported from the `@kensio/yulin/secretsmanager` subpath.
7
7
 
@@ -45,19 +45,14 @@ on read.
45
45
 
46
46
  ## Encryption and KMS permissions
47
47
 
48
- Every version is encrypted through simulated KMS when it is written and decrypted when
49
- `GetSecretValue` reads it. There is no flag for reading a secret without decrypting it. The read
50
- either returns the plaintext or fails.
48
+ Every secret version is encrypted through simulated KMS. `GetSecretValue` decrypts the version and
49
+ either returns its plaintext or fails.
51
50
 
52
- A secret naming no `KmsKeyId` uses the `aws/secretsmanager` AWS managed key, which asks the caller
53
- for no KMS permission at all. Secrets Manager supplies `kms:ViaService`, and that key's policy allows
54
- the account's principals to use it through Secrets Manager. A Lambda role granted only
55
- `secretsmanager:GetSecretValue` therefore reads the secret, as it does on real AWS.
51
+ A secret without `KmsKeyId` uses the `aws/secretsmanager` AWS managed key. Its policy permits use
52
+ through Secrets Manager, so callers do not need a separate KMS permission.
56
53
 
57
- Pass `KmsKeyId` to encrypt under a customer managed key instead, and the caller's own permissions on
58
- that key start to matter. Secrets Manager uses envelope encryption, asking KMS for a data key per
59
- version. A write needs `kms:GenerateDataKey` and a read needs `kms:Decrypt`. A role granted the
60
- secret but not the key fails here, ahead of a deployment.
54
+ Pass `KmsKeyId` to use a customer managed key. Writing a version requires `kms:GenerateDataKey`, and
55
+ reading it requires `kms:Decrypt`, in addition to the relevant Secrets Manager permission.
61
56
 
62
57
  ```typescript sim-secrets-manager-customer-key
63
58
  /**
@@ -141,10 +136,9 @@ they were made with and stay readable, as they do on real AWS.
141
136
 
142
137
  ## Secret ARNs and IAM policies
143
138
 
144
- Real Secrets Manager appends a hyphen and six random characters to the secret name in its ARN. A
145
- secret named `db-creds` gets an ARN ending `:secret:db-creds-AbCdEf`, and sim Secrets Manager does
146
- the same. A policy naming the bare ARN therefore matches nothing, and a policy has to end in
147
- `-??????` or a wildcard.
139
+ Secret ARNs end with a hyphen and six random characters. A secret named `db-creds`, for example,
140
+ gets an ARN ending in `:secret:db-creds-AbCdEf`. An IAM resource pattern for the secret must include
141
+ that suffix, such as `-??????` or `-*`.
148
142
 
149
143
  ```typescript sim-secrets-manager-iam-policy
150
144
  /**
@@ -214,17 +208,16 @@ nothing, here as there.
214
208
 
215
209
  ## Naming a secret
216
210
 
217
- Every operation takes its target as a `SecretId`, in any of the three forms real Secrets Manager
218
- accepts. Those are the friendly name, the full ARN including the suffix, and the partial ARN without
219
- it.
211
+ `SecretId` accepts the friendly name, the full ARN with its random suffix, or the partial ARN without
212
+ the suffix.
220
213
 
221
214
  An ARN naming another account or region resolves to no secret at all. Its name is never read out and
222
215
  looked up locally, and a foreign ARN cannot reach a secret that happens to share a name.
223
216
 
224
217
  ## Versions and staging labels
225
218
 
226
- Every write creates a version, leaving the earlier ones in place. `AWSCURRENT` names the version a
227
- plain read returns, and writing a new current version demotes the previous one to `AWSPREVIOUS`.
219
+ Every write creates a version. `AWSCURRENT` marks the version returned by a plain read. Writing a new
220
+ current version moves `AWSPREVIOUS` to the former current version.
228
221
 
229
222
  ```typescript sim-secrets-manager-staging-labels
230
223
  /**
@@ -273,12 +266,9 @@ label. A version that has lost every label is on its way out of existence, and i
273
266
 
274
267
  ## Deletion and the recovery window
275
268
 
276
- `DeleteSecret` schedules deletion for later. The recovery window is 7 to 30 days, defaulting to 30.
277
- During that window the secret is still there. It can be described and restored, it refuses to be
278
- read or written, and it still holds its name.
279
-
280
- Holding the name is what a redeployed stack hits. Advancing the simulated clock past the window frees
281
- it.
269
+ `DeleteSecret` schedules deletion after a recovery window of 7 to 30 days, defaulting to 30. During
270
+ that window the secret can be described or restored, but it cannot be read or changed. Its name also
271
+ remains reserved. Advance simulated time past the window to complete deletion.
282
272
 
283
273
  ```typescript sim-secrets-manager-deletion
284
274
  /**
@@ -435,14 +425,14 @@ console.log(credentials.username); // "app"
435
425
  console.log(credentials.password?.length); // 24
436
426
  ```
437
427
 
438
- Generated passwords are random. A test reads the value back out of the simulation the way a deployed
439
- application does.
428
+ Generated passwords are random. Read the deployed value through Secrets Manager instead of asserting
429
+ on an exact password.
440
430
 
441
431
  ## Reading a secret with a dynamic reference
442
432
 
443
- A template reads a secret that already exists through a `{{resolve:secretsmanager:...}}` dynamic
444
- reference. The reference is replaced with the secret's value as the resource holding it is created.
445
- CDK emits one from `SecretValue.secretsManager`.
433
+ A `{{resolve:secretsmanager:...}}` dynamic reference reads an existing secret while CloudFormation
434
+ creates the resource containing the reference. CDK emits this form for
435
+ `SecretValue.secretsManager`.
446
436
 
447
437
  The whole form is
448
438
  `{{resolve:secretsmanager:secret-id:secret-string:json-key:version-stage:version-id}}`. Only the
@@ -554,11 +544,10 @@ another resource of the same stack creates is only there in time when the templa
554
544
  Resource properties are reported as they resolved, including this one. Real CloudFormation keeps a
555
545
  resolved secret out of its own logs and events, and sim CloudFormation has no such protection.
556
546
 
557
- ### A reference the simulation cannot answer
547
+ ### Unresolved references
558
548
 
559
- Simulated CloudFormation deploys what it can. A reference naming a secret that was never created
560
- resolves to `dummy-value-for-<secret-id>`, and the stack carries on deploying. A template reading a
561
- secret a test does not care about is still worth deploying for everything else in it.
549
+ If Yulin cannot resolve a reference, it substitutes `dummy-value-for-<secret-id>` and continues the
550
+ deployment.
562
551
 
563
552
  The substitution is recorded on
564
553
  [`stack.ignoredProperties`](https://yulinsim.dev/services/cloudformation/#properties-a-resource-was-created-without),
@@ -596,9 +585,7 @@ The same applies to `SimSdk` interception. Intercepting `SecretsManagerClient` r
596
585
  code into the simulation, served in process. See
597
586
  [AWS SDK interception](https://yulinsim.dev/sdk/ "Simulated AWS SDK docs").
598
587
 
599
- ## Available functionality
600
-
601
- Sim Secrets Manager currently supports:
588
+ ## Supported operations
602
589
 
603
590
  - `CreateSecretCommand`, holding either a string or binary
604
591
  - `GetSecretValueCommand`, by staging label or by version id
@@ -619,8 +606,6 @@ Sim Secrets Manager currently supports:
619
606
 
620
607
  ## Limitations
621
608
 
622
- Current documented limitations:
623
-
624
609
  - A `KmsKeyId` is checked when a version is written under it, not when it is set on its own. An
625
610
  `UpdateSecret` changing only the key accepts a key that is absent, and the next write of a value
626
611
  fails.