@kensio/yulin 1.21.7 → 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.
- package/README.md +22 -2
- package/dist/service/ses/command/authorize/sim-ses-authorizer.d.ts +9 -0
- package/dist/service/ses/command/authorize/sim-ses-authorizer.js +18 -2
- package/dist/service/ses/command/send/sim-ses-send-email.js +2 -1
- package/docs/README.md +7 -0
- package/docs/ai-skill/README.md +6 -1
- package/docs/sdk/README.md +15 -0
- package/docs/services/acm/README.md +24 -40
- package/docs/services/apigateway/README.md +52 -71
- package/docs/services/apigatewayv2/README.md +55 -74
- package/docs/services/athena/README.md +17 -26
- package/docs/services/backup/README.md +29 -39
- package/docs/services/bedrock/README.md +38 -52
- package/docs/services/cloudformation/README.md +43 -55
- package/docs/services/cloudfront/README.md +69 -95
- package/docs/services/cloudwatch/README.md +40 -54
- package/docs/services/cognito/README.md +30 -45
- package/docs/services/dynamodb/README.md +34 -51
- package/docs/services/ecr/README.md +36 -77
- package/docs/services/ecs/README.md +26 -46
- package/docs/services/elbv2/README.md +19 -29
- package/docs/services/eventbridge/README.md +14 -18
- package/docs/services/firehose/README.md +24 -32
- package/docs/services/glue/README.md +41 -78
- package/docs/services/iam/README.md +13 -15
- package/docs/services/kinesis/README.md +53 -93
- package/docs/services/kms/README.md +22 -32
- package/docs/services/lambda/README.md +53 -79
- package/docs/services/logs/README.md +41 -50
- package/docs/services/organizations/README.md +50 -85
- package/docs/services/personalize/README.md +28 -44
- package/docs/services/rekognition/README.md +26 -38
- package/docs/services/route53/README.md +17 -17
- package/docs/services/s3/README.md +47 -51
- package/docs/services/scheduler/README.md +41 -52
- package/docs/services/secretsmanager/README.md +27 -42
- package/docs/services/ses/README.md +24 -34
- package/docs/services/sns/README.md +18 -26
- package/docs/services/sqs/README.md +14 -14
- package/docs/services/ssm/README.md +13 -17
- package/docs/services/stepfunctions/README.md +18 -20
- package/docs/services/sts/README.md +32 -45
- package/docs/services/wafv2/README.md +12 -17
- package/docs/testing/README.md +228 -0
- package/docs/time/README.md +10 -0
- package/llms.txt +1 -0
- package/package.json +1 -1
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
# Simulated Organizations
|
|
2
2
|
|
|
3
|
-
Yulin simulates AWS Organizations service control policies
|
|
4
|
-
organization around an account forbids something before a deployment does.
|
|
3
|
+
Yulin simulates AWS Organizations service control policies (SCPs) and organization structure.
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
identity and resource policies. An SCP therefore applies to a CloudFormation deployment, an
|
|
10
|
-
intercepted SDK client, and a direct service call alike.
|
|
5
|
+
An SCP limits permissions granted by identity and resource policies. Attach one to the organization
|
|
6
|
+
root, an organizational unit or an account. An account inherits policies from every node on its path
|
|
7
|
+
from the root. Simulated IAM applies them to direct calls, intercepted clients and CloudFormation.
|
|
11
8
|
|
|
12
9
|
## Attach a policy to an organizational unit
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
under that unit inherits it. Units nest, and the root sits above all of them.
|
|
11
|
+
Create an organizational unit and attach an SCP to it. Accounts below the unit inherit the policy.
|
|
16
12
|
|
|
17
13
|
```typescript sim-organizations-organizational-unit
|
|
18
14
|
/**
|
|
@@ -44,16 +40,13 @@ const decision = simAws.account("123456789012").iam().authorize({
|
|
|
44
40
|
console.log(decision.value); // "ExplicitDeny"
|
|
45
41
|
```
|
|
46
42
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
`organizations.root()` is the node above everything, and a policy attached there covers every
|
|
50
|
-
account in the organization.
|
|
43
|
+
Pass a parent as the second argument to `createOrganizationalUnit` to nest units. With no parent, the
|
|
44
|
+
new unit sits below `organizations.root()`.
|
|
51
45
|
|
|
52
46
|
## Every level has to allow the action
|
|
53
47
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
able to do neither.
|
|
48
|
+
Every node on the path must allow the action. An allow at one level cannot supply an allow missing
|
|
49
|
+
at another. A deny at any level rejects the request.
|
|
57
50
|
|
|
58
51
|
```typescript sim-organizations-every-level-allows
|
|
59
52
|
/**
|
|
@@ -89,15 +82,12 @@ console.log(decision.value); // "ImplicitDeny"
|
|
|
89
82
|
console.log(decision.serviceControlPolicy.unallowedLevels); // [ "Workloads" ]
|
|
90
83
|
```
|
|
91
84
|
|
|
92
|
-
`unallowedLevels`
|
|
93
|
-
denial that takes longest to track down.
|
|
94
|
-
|
|
95
|
-
A `Deny` at any level ends the request whatever another level allows.
|
|
85
|
+
`unallowedLevels` identifies the nodes with no matching allow.
|
|
96
86
|
|
|
97
87
|
## The management account
|
|
98
88
|
|
|
99
|
-
`setManagementAccount`
|
|
100
|
-
|
|
89
|
+
Use `setManagementAccount` to exempt one account from SCP evaluation. Its identity and resource
|
|
90
|
+
policies still apply.
|
|
101
91
|
|
|
102
92
|
```typescript sim-organizations-management-account
|
|
103
93
|
/**
|
|
@@ -126,9 +116,8 @@ console.log(decision.serviceControlPolicy.isApplied); // false
|
|
|
126
116
|
|
|
127
117
|
## Attach a service control policy to an Account
|
|
128
118
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
`simAws.organizations()`, not from an account scope.
|
|
119
|
+
An SCP attached directly to an account applies only to that account. Organization state belongs to
|
|
120
|
+
the whole `SimAws` instance and is available through `simAws.organizations()`.
|
|
132
121
|
|
|
133
122
|
```typescript sim-organizations-attach-scp
|
|
134
123
|
/**
|
|
@@ -159,17 +148,15 @@ console.log(decision.serviceControlPolicy.isDenied); // true
|
|
|
159
148
|
console.log(decision.serviceControlPolicy.denyStatements[0]?.Sid); // "DenyBucketCreation"
|
|
160
149
|
```
|
|
161
150
|
|
|
162
|
-
|
|
163
|
-
|
|
151
|
+
New organization nodes receive the AWS-managed `FullAWSAccess` policy. A deny-list SCP can then
|
|
152
|
+
block one action while leaving other actions allowed.
|
|
164
153
|
|
|
165
|
-
An account
|
|
166
|
-
and resource policies decide its requests as they did before.
|
|
154
|
+
An account outside the organization is unaffected by SCPs.
|
|
167
155
|
|
|
168
156
|
## Catch a deployment the policy denies
|
|
169
157
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
applies to a member account's root the same way AWS does.
|
|
158
|
+
CloudFormation creates resources through each service's authorized command path. A deployment with
|
|
159
|
+
no caller runs as the account root, and SCPs apply to that root.
|
|
173
160
|
|
|
174
161
|
```typescript sim-organizations-scp-deployment
|
|
175
162
|
/**
|
|
@@ -213,14 +200,13 @@ const failed = simAws
|
|
|
213
200
|
console.log(failed?.status); // "CREATE_FAILED"
|
|
214
201
|
```
|
|
215
202
|
|
|
216
|
-
|
|
217
|
-
|
|
203
|
+
When an SCP denies creation, the resource enters `CREATE_FAILED` and the deployment rejects. The
|
|
204
|
+
error names the policy.
|
|
218
205
|
|
|
219
206
|
## Name the principal a deployment runs as
|
|
220
207
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
statement conditioned on `aws:PrincipalArn` then has a deploy role to match against.
|
|
208
|
+
Pass `caller` when the deployment should run as a role. SCP conditions on `aws:PrincipalArn` then
|
|
209
|
+
evaluate against that role.
|
|
224
210
|
|
|
225
211
|
```typescript sim-organizations-scp-deploy-role
|
|
226
212
|
/**
|
|
@@ -285,17 +271,15 @@ const stack = await simAws.cloudFormation().deployTemplate({
|
|
|
285
271
|
console.log(stack.getResource("ReportsBucket")?.status); // "CREATE_COMPLETE"
|
|
286
272
|
```
|
|
287
273
|
|
|
288
|
-
|
|
289
|
-
denies the root, and the account root is who a bare `createRole` runs as.
|
|
274
|
+
Create the role before attaching a policy that would deny the setup call.
|
|
290
275
|
|
|
291
276
|
## Name the caller the rest of a test reads as
|
|
292
277
|
|
|
293
|
-
A deployment
|
|
294
|
-
the
|
|
295
|
-
on every read.
|
|
278
|
+
A deployment caller applies only to that deployment. Other calls still use the account root unless
|
|
279
|
+
the simulation has a default caller.
|
|
296
280
|
|
|
297
|
-
`defaultCaller` on `SimAws`
|
|
298
|
-
|
|
281
|
+
Set `defaultCaller` on `SimAws` to choose the principal for unattributed calls. An explicit `caller`
|
|
282
|
+
still takes precedence.
|
|
299
283
|
|
|
300
284
|
```typescript sim-organizations-scp-default-caller
|
|
301
285
|
/**
|
|
@@ -369,17 +353,13 @@ console.log(read.Parameter?.Value); // "reports-bucket"
|
|
|
369
353
|
console.log(identity.Arn); // "arn:aws:iam::123456789012:role/Administrator"
|
|
370
354
|
```
|
|
371
355
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
Naming a default caller says who an unattributed call comes from, and leaves the root's own identity
|
|
376
|
-
access where it was. A test about root behaviour names `simAws.account().rootPrincipal` and gets the
|
|
377
|
-
root. Under the policy above that call is denied, which is what the statement is written to do.
|
|
356
|
+
Create and configure the default caller before attaching policies that would deny those setup calls.
|
|
357
|
+
Pass `simAws.account().rootPrincipal` explicitly when a test needs to make a request as root.
|
|
378
358
|
|
|
379
359
|
## Write an allow list instead of a deny list
|
|
380
360
|
|
|
381
|
-
`detachFullAwsAccess`
|
|
382
|
-
|
|
361
|
+
Call `detachFullAwsAccess` to use an allow-list SCP. The remaining policies must explicitly allow an
|
|
362
|
+
action.
|
|
383
363
|
|
|
384
364
|
```typescript sim-organizations-scp-allow-list
|
|
385
365
|
/**
|
|
@@ -407,16 +387,13 @@ console.log(decision.denialReason);
|
|
|
407
387
|
// "because no service control policy allows the s3:GetObject action"
|
|
408
388
|
```
|
|
409
389
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
Detaching `FullAWSAccess` on its own leaves the account holding no policy, and every action is then
|
|
414
|
-
denied. AWS behaves the same way, and warns about it.
|
|
390
|
+
SCPs still limit an account root. Removing `FullAWSAccess` without adding another allow policy denies
|
|
391
|
+
every action.
|
|
415
392
|
|
|
416
393
|
## Deploy an organization from CloudFormation
|
|
417
394
|
|
|
418
|
-
|
|
419
|
-
|
|
395
|
+
Simulated CloudFormation supports the organization, organizational unit, account and policy
|
|
396
|
+
resource types.
|
|
420
397
|
|
|
421
398
|
```typescript sim-organizations-cloudformation
|
|
422
399
|
/**
|
|
@@ -470,17 +447,13 @@ const decision = simAws.account("123456789012").iam().authorize({
|
|
|
470
447
|
console.log(decision.value); // "ExplicitDeny"
|
|
471
448
|
```
|
|
472
449
|
|
|
473
|
-
`Content`
|
|
474
|
-
|
|
475
|
-
or none of them. A target this organization has never heard of fails the resource before anything is
|
|
476
|
-
attached.
|
|
450
|
+
`Content` accepts an object or JSON text. `TargetIds` accepts one target or a list of roots, units and
|
|
451
|
+
accounts. An unknown target fails the resource before the policy is attached anywhere.
|
|
477
452
|
|
|
478
|
-
A
|
|
479
|
-
|
|
480
|
-
worth declaring for `RootId`, which is what a unit hangs off.
|
|
453
|
+
A `SimAws` instance starts with one organization. `AWS::Organizations::Organization` adopts it and
|
|
454
|
+
exposes its `RootId`.
|
|
481
455
|
|
|
482
|
-
`AWS::Organizations::Account`
|
|
483
|
-
back with `Ref` or `Fn::GetAtt AccountId`.
|
|
456
|
+
`AWS::Organizations::Account` generates an account ID. Read it with `Ref` or `Fn::GetAtt AccountId`.
|
|
484
457
|
|
|
485
458
|
These are the properties read from each resource:
|
|
486
459
|
|
|
@@ -491,10 +464,8 @@ These are the properties read from each resource:
|
|
|
491
464
|
| `AWS::Organizations::Account` | `AccountName`, `Email`, `ParentIds` | `Tags`, `RoleName` |
|
|
492
465
|
| `AWS::Organizations::Policy` | `Name`, `Type`, `Content`, `TargetIds` | `Tags`, `Description` |
|
|
493
466
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
policies from more than one stack keeps the others. A unit that still holds something when it goes
|
|
497
|
-
hands what it holds to its parent, so every Account keeps a path to the root.
|
|
467
|
+
Stack teardown removes resources created by that stack. Policies from other stacks remain attached.
|
|
468
|
+
Accounts and child units move to the deleted unit's parent.
|
|
498
469
|
|
|
499
470
|
## Reading a denial
|
|
500
471
|
|
|
@@ -510,21 +481,16 @@ sides, through `decision.serviceControlPolicy`:
|
|
|
510
481
|
| `denyStatements` | The matching `Deny` statements. |
|
|
511
482
|
| `allowStatements` | The matching `Allow` statements. |
|
|
512
483
|
|
|
513
|
-
`decision.denialReason`
|
|
514
|
-
simulated service passes it through to the error it throws.
|
|
484
|
+
`decision.denialReason` contains the text used by service access-denied errors.
|
|
515
485
|
|
|
516
|
-
`
|
|
517
|
-
account, in the order they were evaluated, including `FullAWSAccess` where it is still attached.
|
|
486
|
+
`serviceControlPoliciesFor(accountId)` returns the policies in evaluation order.
|
|
518
487
|
|
|
519
|
-
`serviceControlPolicySetFor(accountId).levels`
|
|
520
|
-
root first. That grouping is what sim IAM evaluates.
|
|
488
|
+
`serviceControlPolicySetFor(accountId).levels` groups policies by node, starting at the root.
|
|
521
489
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
`serviceControlPolicySetFor(accountId).applies` tells the two apart, and so does
|
|
527
|
-
`decision.serviceControlPolicy.isApplied`.
|
|
490
|
+
An empty policy list can mean that the account is outside the organization, is the management
|
|
491
|
+
account or has no policies. The first two are exempt. The last is denied every action. Check
|
|
492
|
+
`serviceControlPolicySetFor(accountId).applies` or `decision.serviceControlPolicy.isApplied` to
|
|
493
|
+
distinguish them.
|
|
528
494
|
|
|
529
495
|
## Available functionality
|
|
530
496
|
|
|
@@ -567,7 +533,6 @@ Simulated Organizations supports:
|
|
|
567
533
|
| Service-linked roles | Evaluated like any other principal. AWS exempts a service-linked role from SCPs. |
|
|
568
534
|
| Other policy types | Resource control policies, declarative policies, tag policies, backup policies and AI services opt-out policies are not simulated. |
|
|
569
535
|
| The Organizations SDK | `CreatePolicy`, `AttachPolicy`, `ListAccounts` and the rest of the API are not handled. Policies are attached through the accessor. |
|
|
570
|
-
| CloudFormation | `AWS::Organizations::Organization`, `::OrganizationalUnit`, `::Account` and `::Policy` are not created from a template. |
|
|
571
536
|
| Organization condition keys | `aws:PrincipalOrgID` and `aws:PrincipalOrgPaths` are not populated. A condition naming either fails to match. |
|
|
572
537
|
| Service principals | A request whose caller is a service principal or anonymous belongs to no Account and is subject to no policy. |
|
|
573
538
|
| Condition operator coverage | The operators above are evaluated. Anything else fails closed and the statement holding it matches nothing. |
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
# Simulated Personalize
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
the request gave them, and reach `ACTIVE` straight away.
|
|
3
|
+
Yulin simulates the Personalize resources and API calls used to serve recommendations. It does not
|
|
4
|
+
train a model or derive results from datasets. Tests declare the recommendations that a campaign or
|
|
5
|
+
recommender should return. Created resources become `ACTIVE` immediately.
|
|
7
6
|
|
|
8
7
|
Personalize-specific types are imported from the `@kensio/yulin/personalize` subpath.
|
|
9
8
|
|
|
10
9
|
## Building the chain to a campaign
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
the campaign serves it.
|
|
11
|
+
A campaign is built from a resource chain. A dataset group contains the datasets, a solution selects
|
|
12
|
+
a recipe, a solution version represents the trained model, and a campaign serves that version.
|
|
15
13
|
|
|
16
14
|
```typescript sim-personalize-campaign-chain
|
|
17
15
|
/**
|
|
@@ -73,9 +71,8 @@ expects.
|
|
|
73
71
|
|
|
74
72
|
## Recommendations from a campaign
|
|
75
73
|
|
|
76
|
-
A campaign
|
|
77
|
-
|
|
78
|
-
under test makes the calls it would make against AWS.
|
|
74
|
+
A campaign returns results declared during test setup. Application code still sends the same
|
|
75
|
+
Personalize Runtime commands it sends to AWS.
|
|
79
76
|
|
|
80
77
|
The two runtime operations live on `simAws.personalizeRuntime()`, and an intercepted
|
|
81
78
|
`PersonalizeRuntimeClient` reaches the same place. They arrive from a separate SDK package
|
|
@@ -140,9 +137,8 @@ const recommended = await simAws.personalizeRuntime().getRecommendations(
|
|
|
140
137
|
console.log(recommended.itemList?.map((item) => item.itemId).join(" "));
|
|
141
138
|
```
|
|
142
139
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
entry differently.
|
|
140
|
+
Declare results per campaign through `recommendations()` and `rankings()`. Two campaigns in the same
|
|
141
|
+
dataset group can return different results for the same input.
|
|
146
142
|
|
|
147
143
|
An item rule is read first where the request carries an item, then a user rule, then the default.
|
|
148
144
|
That order follows the recipes. `aws-similar-items` requires an `itemId` and looks at no user, and
|
|
@@ -152,9 +148,8 @@ would have used. Matching is exact, with no pattern syntax.
|
|
|
152
148
|
`numResults` cuts a declared list to length. A request no rule matches gets the campaign's default,
|
|
153
149
|
and an empty `itemList` where no default is declared.
|
|
154
150
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
score.
|
|
151
|
+
Declare an item as an ID or as an ID with a score. An item declared without a score is returned
|
|
152
|
+
without one.
|
|
158
153
|
|
|
159
154
|
```typescript sim-personalize-recommendation-scores
|
|
160
155
|
/**
|
|
@@ -228,10 +223,8 @@ Runtime does.
|
|
|
228
223
|
|
|
229
224
|
## Datasets and schemas
|
|
230
225
|
|
|
231
|
-
A dataset belongs to a dataset group and has one of five types.
|
|
232
|
-
|
|
233
|
-
dataset group therefore holds one dataset of each type, and two dataset groups can each hold an
|
|
234
|
-
`INTERACTIONS` dataset without colliding.
|
|
226
|
+
A dataset belongs to a dataset group and has one of five types. Its ARN contains the group and type,
|
|
227
|
+
not the requested name. Each group can contain one dataset of each type.
|
|
235
228
|
|
|
236
229
|
```typescript sim-personalize-dataset
|
|
237
230
|
/**
|
|
@@ -289,8 +282,8 @@ domain dataset group refuses them here too.
|
|
|
289
282
|
|
|
290
283
|
## Recording events
|
|
291
284
|
|
|
292
|
-
An event tracker
|
|
293
|
-
group
|
|
285
|
+
An event tracker records the item interactions sent through `PutEvents`. Create it for a dataset
|
|
286
|
+
group, then pass its tracking ID to each request.
|
|
294
287
|
|
|
295
288
|
```typescript sim-personalize-event-tracker
|
|
296
289
|
/**
|
|
@@ -464,10 +457,9 @@ console.log(group.domain);
|
|
|
464
457
|
|
|
465
458
|
## Recommenders and their use cases
|
|
466
459
|
|
|
467
|
-
A recommender
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
through the same `recommendations()` rules.
|
|
460
|
+
A recommender belongs directly to a domain dataset group and selects one of ten AWS use cases. It
|
|
461
|
+
does not use a solution or solution version. Pass its ARN to `GetRecommendations` and declare its
|
|
462
|
+
results with the same `recommendations()` API used for campaigns.
|
|
471
463
|
|
|
472
464
|
```typescript sim-personalize-recommender
|
|
473
465
|
/**
|
|
@@ -525,9 +517,8 @@ Real Personalize trains for hours and retrains every seven days.
|
|
|
525
517
|
|
|
526
518
|
### The ten use cases
|
|
527
519
|
|
|
528
|
-
The recipe ARN
|
|
529
|
-
|
|
530
|
-
it. That refusal is the part of the domain path worth simulating, and everything else here is state.
|
|
520
|
+
The recipe ARN selects the use case. Each use case defines whether `itemId` and `userId` are
|
|
521
|
+
required, optional, or unused. Requests missing a required parameter are rejected.
|
|
531
522
|
|
|
532
523
|
| Use case | Recipe ARN suffix | `itemId` | `userId` |
|
|
533
524
|
| ---------------------------------- | ---------------------------------------------- | -------- | -------- |
|
|
@@ -555,9 +546,6 @@ A parameter marked unused is ignored rather than matched on. A `Top picks for yo
|
|
|
555
546
|
an `itemId` as well as its `userId` is answered from the user rule, since that is the tier real
|
|
556
547
|
Personalize would have used. An optional one is matched where the request carries it.
|
|
557
548
|
|
|
558
|
-
These are the requirements AWS documents against each use case. Both pages are worth reading before
|
|
559
|
-
writing a request, since two of them differ from the e-commerce use case they otherwise mirror.
|
|
560
|
-
|
|
561
549
|
### Starting and stopping
|
|
562
550
|
|
|
563
551
|
`StopRecommender` leaves the recommender in place and stops it serving. `GetRecommendations` against
|
|
@@ -602,8 +590,7 @@ and solutions gone. A group still holding one is reported as `ResourceInUseExcep
|
|
|
602
590
|
|
|
603
591
|
`AWS::Personalize::DatasetGroup`, `AWS::Personalize::Schema`, `AWS::Personalize::Dataset`,
|
|
604
592
|
`AWS::Personalize::Solution` and `AWS::Personalize::EventTracker` deploy into simulated Personalize.
|
|
605
|
-
A project
|
|
606
|
-
deploys, with no hand-written test setup.
|
|
593
|
+
A project can deploy its synthesized template without hand-written Personalize setup.
|
|
607
594
|
|
|
608
595
|
Each one goes through the ordinary create command. A template and an SDK caller get the same
|
|
609
596
|
validation, the same refusals and the same ARN.
|
|
@@ -710,19 +697,16 @@ wiring one resource into another reads `Fn::GetAtt`. An event tracker publishes
|
|
|
710
697
|
does not publish fails the deploy, since answering one would let a template deploy here and fail on
|
|
711
698
|
AWS.
|
|
712
699
|
|
|
713
|
-
###
|
|
700
|
+
### Resources without CloudFormation types
|
|
714
701
|
|
|
715
|
-
CloudFormation has no `AWS::Personalize::Campaign`
|
|
716
|
-
|
|
717
|
-
the CLI or the console. A deployed stack gets as far as a solution and stops there. A test creates
|
|
718
|
-
the solution version and the campaign itself, as the example above does. This is real Personalize
|
|
719
|
-
behaviour and worth knowing before reading it as a gap in the simulation.
|
|
702
|
+
CloudFormation has no `AWS::Personalize::Campaign` or `AWS::Personalize::Recommender` type. Create
|
|
703
|
+
these resources through the SDK after deploying the stack, as the example above does.
|
|
720
704
|
|
|
721
705
|
The domain path stops in the same place. `Domain` is a property of `AWS::Personalize::DatasetGroup`,
|
|
722
706
|
and a template can declare a Domain dataset group. No `AWS::Personalize::Recommender` type exists to
|
|
723
707
|
put a recommender on it.
|
|
724
708
|
|
|
725
|
-
###
|
|
709
|
+
### Skipped resource types
|
|
726
710
|
|
|
727
711
|
`AWS::Personalize::BatchInferenceJob`, `AWS::Personalize::BatchSegmentJob`,
|
|
728
712
|
`AWS::Personalize::DataDeletionJob`, `AWS::Personalize::MetricAttribution` and
|
|
@@ -763,9 +747,9 @@ console.log(group?.name, group?.status);
|
|
|
763
747
|
|
|
764
748
|
## Deleting resources
|
|
765
749
|
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
750
|
+
Delete resources from the campaign end of the chain. A dataset group that still contains datasets,
|
|
751
|
+
solutions, or an event tracker raises `ResourceInUseException`. A solution still used by a campaign
|
|
752
|
+
raises the same error.
|
|
769
753
|
|
|
770
754
|
Deleting an event tracker leaves the events it accepted recorded, as real Personalize leaves the
|
|
771
755
|
interactions it wrote in the dataset behind it.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Simulated Rekognition
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Yulin simulates Rekognition by returning results declared for an image name or content hash. It does
|
|
4
|
+
not analyze the image. Tests can define labels, moderation results, faces, and face matches while
|
|
5
|
+
application code uses the normal Rekognition commands.
|
|
6
6
|
|
|
7
7
|
Rekognition-specific types are imported from the `@kensio/yulin/rekognition` subpath.
|
|
8
8
|
|
|
@@ -67,9 +67,8 @@ const detected = await simAws
|
|
|
67
67
|
|
|
68
68
|
## Detecting labels in an image
|
|
69
69
|
|
|
70
|
-
`DetectLabels`
|
|
71
|
-
|
|
72
|
-
label is reported as written.
|
|
70
|
+
`DetectLabels` returns the objects, scenes, and concepts declared for an image. Each label contains
|
|
71
|
+
only the parents, aliases, categories, and instances in its declaration.
|
|
73
72
|
|
|
74
73
|
```typescript sim-rekognition-detect-labels
|
|
75
74
|
/**
|
|
@@ -131,19 +130,16 @@ console.log(detected.LabelModelVersion); // "3.0"
|
|
|
131
130
|
Labels come back in descending order of confidence, which is the order real Rekognition reports them
|
|
132
131
|
in. A declared instance with no confidence of its own takes its label's.
|
|
133
132
|
|
|
134
|
-
An image no rule
|
|
135
|
-
|
|
136
|
-
bounding box AWS documents it with. It is a real Rekognition response, though which labels an
|
|
137
|
-
unconfigured image gets is a simulator convention rather than what AWS would return for it.
|
|
133
|
+
An image that matches no rule gets a built-in `Mobile Phone` result based on the AWS
|
|
134
|
+
`DetectLabels` example response. This default is a Yulin convention. AWS results depend on the image.
|
|
138
135
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
ontology to check a name against or to expand one from.
|
|
136
|
+
Yulin does not validate or expand general detection labels. Declaring `Cat` without parents returns
|
|
137
|
+
`Cat` without parents.
|
|
142
138
|
|
|
143
139
|
## Detecting faces in an image
|
|
144
140
|
|
|
145
|
-
`DetectFaces`
|
|
146
|
-
|
|
141
|
+
`DetectFaces` returns the faces declared for an image, including their positions and requested
|
|
142
|
+
attributes.
|
|
147
143
|
|
|
148
144
|
```typescript sim-rekognition-detect-faces
|
|
149
145
|
/**
|
|
@@ -204,8 +200,7 @@ Faces come back in the order they were declared. An attribute with no confidence
|
|
|
204
200
|
the face's, and a face detected at 99.4 is reported as smiling at 99.4. A face declared with no
|
|
205
201
|
confidence at all is detected at the built-in one.
|
|
206
202
|
|
|
207
|
-
|
|
208
|
-
usually does:
|
|
203
|
+
Use `{ faces: [] }` for an image with no faces. Two built-in results cover common face-count tests:
|
|
209
204
|
|
|
210
205
|
```typescript
|
|
211
206
|
import {
|
|
@@ -219,10 +214,8 @@ faces.onName("incoming/landscape.png", simRekognitionNoFaces);
|
|
|
219
214
|
faces.onName("incoming/crowd.png", simRekognitionSeveralFaces);
|
|
220
215
|
```
|
|
221
216
|
|
|
222
|
-
An image no rule
|
|
223
|
-
|
|
224
|
-
documents it with. It is a real Rekognition response, though which face an unconfigured image gets is
|
|
225
|
-
a simulator convention rather than what AWS would return for it.
|
|
217
|
+
An image that matches no rule gets the face from the AWS `DetectFaces` example response, including
|
|
218
|
+
its attributes and 30 landmarks. This default is a Yulin convention.
|
|
226
219
|
|
|
227
220
|
## Choosing the facial attributes
|
|
228
221
|
|
|
@@ -305,11 +298,10 @@ excludes the chin.
|
|
|
305
298
|
|
|
306
299
|
## Declaring results
|
|
307
300
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
`
|
|
311
|
-
|
|
312
|
-
anything at all.
|
|
301
|
+
Declare results separately for each operation. Use `moderation()` for `DetectModerationLabels`,
|
|
302
|
+
`labels()` for `DetectLabels`, `faces()` for `DetectFaces`, and `faceMatches()` for
|
|
303
|
+
`SearchFacesByImage`. Each API accepts rules for an exact S3 object name, an exact content hash, or a
|
|
304
|
+
default result.
|
|
313
305
|
|
|
314
306
|
```typescript sim-rekognition-moderation-rules
|
|
315
307
|
/**
|
|
@@ -340,8 +332,8 @@ moderation.onHash(simRekognitionImageHash(fixture), {
|
|
|
340
332
|
});
|
|
341
333
|
```
|
|
342
334
|
|
|
343
|
-
|
|
344
|
-
|
|
335
|
+
Rules use exact matching. Hash rules take precedence over name rules, which take precedence over the
|
|
336
|
+
default.
|
|
345
337
|
|
|
346
338
|
A name is the `Name` in the request, the S3 object key. It is matched on its own, with the Bucket
|
|
347
339
|
left out, so a rule for a key applies to that key in whichever Bucket the request names. An image
|
|
@@ -412,9 +404,8 @@ refused where the rule is written.
|
|
|
412
404
|
|
|
413
405
|
## Sample images
|
|
414
406
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
application generating its own object keys testable, since the test never has to know the key.
|
|
407
|
+
Yulin includes five small images with predeclared hash rules. Application code can upload one under
|
|
408
|
+
any object key and receive a known result without registering another rule.
|
|
418
409
|
|
|
419
410
|
| Image | Format | Detected as |
|
|
420
411
|
| -------------------------------------------------- | ------ | ------------------------------------------------- |
|
|
@@ -477,9 +468,8 @@ simAws
|
|
|
477
468
|
.onHash(simRekognitionImageHash(sample), { labels: [] });
|
|
478
469
|
```
|
|
479
470
|
|
|
480
|
-
The images are
|
|
481
|
-
|
|
482
|
-
image is looked at.
|
|
471
|
+
The images are valid 16 by 16 PNG and JPEG files. Rekognition checks their file signatures but does
|
|
472
|
+
not inspect their visual content.
|
|
483
473
|
|
|
484
474
|
## Moderation labels come back with their parents
|
|
485
475
|
|
|
@@ -772,7 +762,7 @@ ever. Filter the notification configuration by prefix or suffix, as this one doe
|
|
|
772
762
|
|
|
773
763
|
## Face collections
|
|
774
764
|
|
|
775
|
-
A collection
|
|
765
|
+
A collection stores indexed faces so an application can search for the same person later.
|
|
776
766
|
|
|
777
767
|
```typescript sim-rekognition-collections
|
|
778
768
|
/**
|
|
@@ -970,9 +960,7 @@ An image is read from a Bucket in another Account when that Bucket's policy allo
|
|
|
970
960
|
real Rekognition reads across Accounts. A Bucket in another Region is refused, as real Rekognition
|
|
971
961
|
reads only Buckets in its own Region.
|
|
972
962
|
|
|
973
|
-
##
|
|
974
|
-
|
|
975
|
-
Simulated Rekognition currently supports:
|
|
963
|
+
## Supported operations
|
|
976
964
|
|
|
977
965
|
- `DetectModerationLabelsCommand`, `DetectLabelsCommand` and `DetectFacesCommand`, for an image
|
|
978
966
|
supplied as `Image.Bytes` or as `Image.S3Object`
|