@kensio/yulin 1.21.5 → 1.21.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/dist/service/cloudformation/resource/cfn/sim-cfn-default-resource-value-adapter.d.ts +8 -1
  2. package/dist/service/cloudformation/resource/cfn/sim-cfn-default-resource-value-adapter.js +9 -2
  3. package/dist/service/cloudformation/resource/cfn/sim-cfn-resource-value-adapter.d.ts +6 -1
  4. package/dist/service/cloudformation/resource/cfn/sim-cfn-resource-value-adapter.js +2 -1
  5. package/dist/service/cloudformation/resource/create/sim-cfn-resource-create-operation.d.ts +4 -0
  6. package/dist/service/cloudformation/resource/create/sim-cfn-resource-create-operation.js +6 -0
  7. package/dist/service/cloudformation/resource/sim-cfn-resource-record.d.ts +19 -0
  8. package/dist/service/cloudformation/resource/sim-cfn-resource-record.js +26 -0
  9. package/dist/service/cloudformation/resource/sim-cfn-resource.js +1 -0
  10. package/dist/service/cloudformation/resource/unsupported/sim-cfn-named-skip.d.ts +26 -0
  11. package/dist/service/cloudformation/resource/unsupported/sim-cfn-named-skip.js +31 -0
  12. package/dist/service/cloudfront/cfn/cache-policy/sim-cfn-cf-cache-policy-creator.d.ts +5 -2
  13. package/dist/service/cloudfront/cfn/cache-policy/sim-cfn-cf-cache-policy-creator.js +10 -2
  14. package/dist/service/cloudfront/cfn/origin-access-control/sim-cfn-cf-oac-creator.d.ts +5 -2
  15. package/dist/service/cloudfront/cfn/origin-access-control/sim-cfn-cf-oac-creator.js +10 -2
  16. package/dist/service/cloudfront/cfn/origin-request-policy/sim-cfn-cf-orp-creator.d.ts +5 -2
  17. package/dist/service/cloudfront/cfn/origin-request-policy/sim-cfn-cf-orp-creator.js +10 -2
  18. package/dist/service/cloudfront/cfn/policy/sim-cfn-cf-policy-creators.d.ts +33 -0
  19. package/dist/service/cloudfront/cfn/policy/sim-cfn-cf-policy-creators.js +39 -0
  20. package/dist/service/cloudfront/cfn/response-headers-policy/sim-cfn-cf-rh-policy-creator.d.ts +5 -2
  21. package/dist/service/cloudfront/cfn/response-headers-policy/sim-cfn-cf-rh-policy-creator.js +10 -2
  22. package/dist/service/cloudfront/cfn/sim-cfn-cf-authorizer.d.ts +40 -0
  23. package/dist/service/cloudfront/cfn/sim-cfn-cf-authorizer.js +50 -0
  24. package/dist/service/cloudfront/cfn/sim-cfn-cloudfront-resource-factory.d.ts +1 -4
  25. package/dist/service/cloudfront/cfn/sim-cfn-cloudfront-resource-factory.js +14 -46
  26. package/dist/service/cloudfront/sim-cloudfront-commands.d.ts +6 -0
  27. package/dist/service/cloudfront/sim-cloudfront-commands.js +7 -0
  28. package/dist/service/cloudfront/sim-cloudfront.d.ts +6 -0
  29. package/dist/service/cloudfront/sim-cloudfront.js +7 -0
  30. package/dist/service/dynamodb/document/sim-dynamodb-document-command-paths.d.ts +8 -0
  31. package/dist/service/dynamodb/document/sim-dynamodb-document-command-paths.js +62 -0
  32. package/dist/service/dynamodb/document/sim-dynamodb-document-routes.d.ts +1 -1
  33. package/dist/service/dynamodb/document/sim-dynamodb-document-routes.js +3 -1
  34. package/dist/service/eventbridge/cfn/bus/sim-cfn-event-bus-creator.js +1 -0
  35. package/dist/service/eventbridge/cfn/bus/sim-cfn-event-bus-properties.d.ts +4 -0
  36. package/dist/service/eventbridge/cfn/bus/sim-cfn-event-bus-properties.js +26 -1
  37. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-creator.js +3 -1
  38. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-properties.d.ts +0 -7
  39. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-properties.js +0 -20
  40. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-unsimulated-properties.d.ts +13 -0
  41. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-unsimulated-properties.js +59 -0
  42. package/dist/service/eventbridge/cfn/sim-cfn-event-bridge-resource-error.d.ts +1 -1
  43. package/dist/service/eventbridge/cfn/sim-cfn-event-bridge-resource-error.js +1 -1
  44. package/dist/service/iam/authorize/sim-iam-action-authorizer.d.ts +8 -3
  45. package/dist/service/iam/authorize/sim-iam-action-authorizer.js +13 -4
  46. package/dist/service/iam/cfn/role/sim-cfn-iam-role-creator.js +1 -0
  47. package/dist/service/iam/cfn/role/sim-cfn-iam-role-properties-parser.d.ts +1 -0
  48. package/dist/service/iam/cfn/role/sim-cfn-iam-role-properties-parser.js +21 -14
  49. package/dist/service/iam/cfn/{sim-cfn-iam-optional-string.d.ts → sim-cfn-iam-property.d.ts} +10 -2
  50. package/dist/service/iam/cfn/sim-cfn-iam-property.js +31 -0
  51. package/dist/service/iam/cfn/user/sim-cfn-iam-user-properties-parser.js +1 -1
  52. package/dist/service/iam/command/role/create-role/create-role-record-factory.js +3 -0
  53. package/dist/service/iam/command/role/create-role/create-role.command.d.ts +10 -0
  54. package/dist/service/iam/command/role/get-role/get-role.command.d.ts +2 -0
  55. package/dist/service/iam/command/role/get-role/get-role.handler.js +2 -0
  56. package/dist/service/iam/command/role/sim-iam-role-command-handlers.js +15 -1
  57. package/dist/service/iam/role/sim-iam-role-boundary.d.ts +24 -0
  58. package/dist/service/iam/role/sim-iam-role-boundary.js +24 -0
  59. package/dist/service/iam/role/sim-iam-role-with-policy.factory.d.ts +1 -0
  60. package/dist/service/iam/role/sim-iam-role.d.ts +10 -0
  61. package/dist/service/iam/serve/sim-iam-query-entity.d.ts +6 -1
  62. package/dist/service/iam/serve/sim-iam-query-entity.js +10 -4
  63. package/dist/service/iam/serve/sim-iam-query-role-operations.js +15 -3
  64. package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-properties.js +1 -1
  65. package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-property-rules.d.ts +3 -2
  66. package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-property-rules.js +25 -3
  67. package/dist/service/lambda/cfn/function/sim-cfn-lambda-runtime-skip.d.ts +6 -0
  68. package/dist/service/lambda/cfn/function/sim-cfn-lambda-runtime-skip.js +9 -2
  69. package/dist/service/route53/command/create-hosted-zone/sim-route53-zone-id.js +23 -1
  70. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-creator.js +1 -0
  71. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-properties.d.ts +9 -4
  72. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-properties.js +18 -6
  73. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-property-names.d.ts +10 -0
  74. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-property-names.js +16 -1
  75. package/dist/service/ssm/cfn/parameter/sim-cfn-ssm-parameter-creator.js +1 -1
  76. package/dist/service/ssm/cfn/parameter/sim-cfn-ssm-parameter-properties.d.ts +11 -6
  77. package/dist/service/ssm/cfn/parameter/sim-cfn-ssm-parameter-properties.js +18 -9
  78. package/docs/README.md +33 -4
  79. package/docs/ai-skill/README.md +52 -54
  80. package/docs/cli/README.md +84 -94
  81. package/docs/factories/README.md +42 -54
  82. package/docs/lint/README.md +41 -67
  83. package/docs/non-aws-dependencies/README.md +72 -168
  84. package/docs/sdk/README.md +97 -98
  85. package/docs/serve/README.md +192 -898
  86. package/docs/services/cloudformation/README.md +88 -23
  87. package/docs/services/cloudfront/README.md +109 -0
  88. package/docs/services/dynamodb/README.md +128 -8
  89. package/docs/services/eventbridge/README.md +10 -2
  90. package/docs/services/iam/README.md +125 -2
  91. package/docs/services/lambda/README.md +7 -1
  92. package/docs/services/route53/README.md +11 -0
  93. package/docs/services/sns/README.md +13 -7
  94. package/docs/services/ssm/README.md +6 -4
  95. package/docs/terraform/README.md +108 -126
  96. package/docs/time/README.md +80 -120
  97. package/llms.txt +1 -1
  98. package/package.json +1 -1
  99. package/dist/service/iam/cfn/sim-cfn-iam-optional-string.js +0 -17
@@ -28,3 +28,13 @@ export declare const attributePropertyNames: ReadonlySet<string>;
28
28
  * become fifteen separate attributes.
29
29
  */
30
30
  export declare const unsimulatedPropertyReasons: ReadonlyMap<string, string>;
31
+ /**
32
+ * The real AWS::SNS::Topic properties this simulation has nothing to act on
33
+ * and no reason to fail a stack over.
34
+ *
35
+ * `Tags` is the whole list. The topic is created without them and the omission
36
+ * is recorded against the Resource. A topic behaves the same way with a tag
37
+ * and without one, and a CDK app calling `Tags.of(app).add(...)` tags every
38
+ * topic in it.
39
+ */
40
+ export declare const ignoredPropertyReasons: ReadonlyMap<string, string>;
@@ -47,5 +47,20 @@ export const unsimulatedPropertyReasons = new Map([
47
47
  "DeliveryStatusLogging",
48
48
  "delivery status logging writes to CloudWatch Logs, which is not simulated",
49
49
  ],
50
- ["Tags", "no simulated service reads a topic tag"],
50
+ ]);
51
+ /**
52
+ * The real AWS::SNS::Topic properties this simulation has nothing to act on
53
+ * and no reason to fail a stack over.
54
+ *
55
+ * `Tags` is the whole list. The topic is created without them and the omission
56
+ * is recorded against the Resource. A topic behaves the same way with a tag
57
+ * and without one, and a CDK app calling `Tags.of(app).add(...)` tags every
58
+ * topic in it.
59
+ */
60
+ export const ignoredPropertyReasons = new Map([
61
+ [
62
+ "Tags",
63
+ "AWS::SNS::Topic property Tags is not simulated, so the topic is created " +
64
+ "without them. No simulated service reads a topic tag.",
65
+ ],
51
66
  ]);
@@ -28,6 +28,7 @@ export class SimCfnSsmParameterCreator {
28
28
  properties,
29
29
  });
30
30
  const name = parameterProperties.name();
31
+ parameterProperties.recordIgnoredTags();
31
32
  await this.ssm.putParameter({
32
33
  input: {
33
34
  Name: name,
@@ -38,7 +39,6 @@ export class SimCfnSsmParameterCreator {
38
39
  AllowedPattern: parameterProperties.allowedPattern(),
39
40
  DataType: parameterProperties.dataType(),
40
41
  Policies: parameterProperties.policies(),
41
- Tags: parameterProperties.tags(),
42
42
  },
43
43
  }, options);
44
44
  const parameter = this.ssm.findParameter(name);
@@ -1,6 +1,5 @@
1
1
  import type { SimCfnResource } from "../../../cloudformation/resource/sim-cfn-resource.js";
2
2
  import type { SimCfnTemplateValueRecord } from "../../../cloudformation/template/value/sim-cfn-template-value.js";
3
- import type { SimSsmTag } from "../../command/parameter/parameter.command.js";
4
3
  interface SimCfnSsmParameterPropertiesProperties {
5
4
  readonly resource: SimCfnResource;
6
5
  readonly properties: SimCfnTemplateValueRecord;
@@ -60,13 +59,19 @@ export declare class SimCfnSsmParameterProperties {
60
59
  */
61
60
  policies(): string | undefined;
62
61
  /**
63
- * The parameter Tags, which PutParameter refuses.
62
+ * Record the tags the parameter is written without.
64
63
  *
65
- * CloudFormation carries these as a map of names to values for this
66
- * Resource type, rather than the list of Key/Value pairs most Resource
67
- * types use, so they are turned into the list shape PutParameter takes.
64
+ * `Tags` is the one difference from `PutParameter`, which refuses it
65
+ * outright. A template's tags are usually the whole stack's, and a CDK app
66
+ * calling `Tags.of(app).add(...)` tags every parameter in it. The parameter
67
+ * holds the same value either way, so the deploy stands and the omission is
68
+ * recorded.
69
+ *
70
+ * The shape is still read, because CloudFormation carries these as a map of
71
+ * names to values for this Resource type and a template AWS refuses should
72
+ * not deploy here.
68
73
  */
69
- tags(): readonly SimSsmTag[] | undefined;
74
+ recordIgnoredTags(): void;
70
75
  private string;
71
76
  private stringValue;
72
77
  private propertyError;
@@ -88,23 +88,32 @@ export class SimCfnSsmParameterProperties {
88
88
  return this.string(this.properties["Policies"], "Policies");
89
89
  }
90
90
  /**
91
- * The parameter Tags, which PutParameter refuses.
91
+ * Record the tags the parameter is written without.
92
92
  *
93
- * CloudFormation carries these as a map of names to values for this
94
- * Resource type, rather than the list of Key/Value pairs most Resource
95
- * types use, so they are turned into the list shape PutParameter takes.
93
+ * `Tags` is the one difference from `PutParameter`, which refuses it
94
+ * outright. A template's tags are usually the whole stack's, and a CDK app
95
+ * calling `Tags.of(app).add(...)` tags every parameter in it. The parameter
96
+ * holds the same value either way, so the deploy stands and the omission is
97
+ * recorded.
98
+ *
99
+ * The shape is still read, because CloudFormation carries these as a map of
100
+ * names to values for this Resource type and a template AWS refuses should
101
+ * not deploy here.
96
102
  */
97
- tags() {
103
+ recordIgnoredTags() {
98
104
  const tags = this.properties["Tags"];
99
105
  if (tags === undefined) {
100
- return undefined;
106
+ return;
101
107
  }
102
108
  if (typeof tags !== "object" || tags === null || Array.isArray(tags)) {
103
109
  throw this.propertyError("Tags must be an object");
104
110
  }
105
- return Object.entries(tags).map(([key, value]) => {
106
- return { Key: key, Value: this.stringValue(value, `Tags.${key}`) };
107
- });
111
+ for (const [key, value] of Object.entries(tags)) {
112
+ this.stringValue(value, `Tags.${key}`);
113
+ }
114
+ this.resource.ignoreProperty("Tags", "AWS::SSM::Parameter property Tags is not simulated, so the parameter " +
115
+ "is written without them. Nothing reads them back and no " +
116
+ "aws:ResourceTag condition key matches them.");
108
117
  }
109
118
  string(value, name) {
110
119
  if (value === undefined) {
package/docs/README.md CHANGED
@@ -1,7 +1,36 @@
1
- # Simulated AWS usage documentation
1
+ # Yulin documentation
2
2
 
3
- This directory contains area-specific documentation for Yulin. Each page explains the simulated
4
- behaviour and includes example code that can be copied into tests or local development scripts.
3
+ Yulin runs simulated AWS services inside a Node.js process. Tests can use AWS SDK clients,
4
+ CloudFormation templates, or direct service calls without connecting to AWS. Each `SimAws` instance
5
+ holds its own state in memory.
6
+
7
+ Yulin implements selected AWS behaviour. The service pages describe what each simulation supports
8
+ and where it differs from AWS.
9
+
10
+ ## Install Yulin
11
+
12
+ ```bash
13
+ npm install --save-dev @kensio/yulin
14
+ ```
15
+
16
+ ## Choose how to use Yulin
17
+
18
+ Start with [AWS SDK interception](https://yulinsim.dev/sdk/) when the code under test already uses an
19
+ AWS SDK client. Yulin intercepts the client's `send` calls and returns responses from a simulated
20
+ service. The application code continues to use the AWS SDK normally.
21
+
22
+ Use [event factories](https://yulinsim.dev/factories/) when a test calls a handler directly and only
23
+ needs an AWS event object. The factories fill in fields that the test does not care about.
24
+
25
+ Use [CloudFormation](https://yulinsim.dev/services/cloudformation/) to build a simulation from a
26
+ template. This also works with templates synthesized by AWS CDK and AWS SAM.
27
+
28
+ Use the [localhost server](https://yulinsim.dev/serve/) when the code runs in another process or
29
+ sends HTTP requests. The [AWS CLI guide](https://yulinsim.dev/cli/) explains how to point AWS CLI
30
+ commands at the same endpoint.
31
+
32
+ Read [simulated time](https://yulinsim.dev/time/) when a test needs to advance a schedule, expire a
33
+ credential, or run other work that depends on time passing.
5
34
 
6
35
  ## Service documentation
7
36
 
@@ -42,7 +71,7 @@ behaviour and includes example code that can be copied into tests or local devel
42
71
  - [STS](https://yulinsim.dev/services/sts/ "Simulated STS usage docs")
43
72
  - [WAFv2](https://yulinsim.dev/services/wafv2/ "Simulated WAFv2 usage docs")
44
73
 
45
- ## Feature documentation
74
+ ## Feature guides
46
75
 
47
76
  - [AI skill](https://yulinsim.dev/ai-skill/ "Yulin AI skill usage docs")
48
77
  - [The AWS CLI](https://yulinsim.dev/cli/ "The AWS CLI against simulated AWS usage docs")
@@ -1,69 +1,67 @@
1
- # AI skill
1
+ # AI skill for Yulin
2
2
 
3
- Yulin has an AI skill that teaches a coding agent how to test AWS code with the simulator well. It
4
- is `yulin-aws-simulation`, a `SKILL.md` written to the
5
- [Agent Skills specification](https://agentskills.io/specification) and installable into Claude Code,
6
- Codex CLI, Cursor, VS Code and anything else that reads one. It covers the part that lives outside
7
- the API.
3
+ The `yulin-aws-simulation` skill gives coding agents instructions for using Yulin in tests and local
4
+ development.
8
5
 
9
- These docs and the skill answer different questions. A page here says what a simulated service does
10
- and what its commands take. The skill says what to do with that. An AI agent reaching for Yulin
11
- without it tends to build a harness around the simulator, leave hand-rolled stubs in place beside
12
- it, or write an `instanceof` check against an SDK exception class that passes in production and
13
- fails against the simulation.
6
+ ## Install the skill
14
7
 
15
- ## Install
8
+ Install it in the current project's `.agents/skills/` directory:
16
9
 
17
10
  ```bash
18
11
  npx @kensio/skills add yulin-aws-simulation
19
12
  ```
20
13
 
21
- That copies the skill into `.agents/skills/`, the directory Codex CLI, Cursor, VS Code and Gemini
22
- CLI read. `--agent claude` puts it in `.claude/skills/`, and `--user` installs it under your home
23
- directory for every project.
14
+ Codex CLI, Cursor, VS Code, and Gemini CLI read skills from that directory. To install the skill for
15
+ Claude Code, add `--agent claude`. Add `--user` to install it for every project under your user
16
+ account.
24
17
 
25
- As a Claude Code plugin:
18
+ Claude Code can also install the skill from the Kensio plugin marketplace:
26
19
 
27
20
  ```bash
28
21
  claude plugin marketplace add KensioSoftware/kensio.ai
29
22
  claude plugin install yulin-aws-simulation@kensio
30
23
  ```
31
24
 
32
- It is also on npm as `@kensio/yulin-aws-simulation`, and every
33
- [kensio.ai release](https://github.com/KensioSoftware/kensio.ai/releases) carries it as a zip for a
34
- machine with no registry reach.
35
-
36
- ## What it covers
37
-
38
- - Using `SimAws` and `SimSdk` directly, and spotting the helper class or `setupSimulatedAws()`
39
- wrapper that starts to grow around them.
40
- - One synthesized CDK template behind the tests, the dev server and production, deployed with
41
- `deployTemplateFile` or `deployCdkOut`.
42
- - When to register a resource at a chosen id, and when to deploy the stack that creates it.
43
- - Interception over hand-rolled stubs, down to the requests a fake accepts and the simulation
44
- refuses.
45
- - Freezing the clock, then advancing it on purpose.
46
- - Assertions that read the simulation back.
47
- - Why service errors match by `name` and not by `instanceof`.
48
- - Deploying an expensive stack once per test file.
49
- - Running a handler as a real simulated Lambda, under its execution role, its declared environment
50
- and its own log group.
51
- - Refusals as a feature, and gaps raised upstream.
52
-
53
- ## Reading the API alongside it
54
-
55
- The skill sends the AI agent to these docs for anything API-shaped, and
56
- [llms.txt](https://yulinsim.dev/llms.txt) is the index it uses. Every page here is available as
57
- plain markdown by appending `llms.txt` to its URL, one file per guide and one per simulated service.
58
- That index works with or without the skill installed.
59
-
60
- The same pages ship inside the package. An installed project holds them under
61
- `node_modules/@kensio/yulin/docs/`, indexed by `node_modules/@kensio/yulin/llms.txt`, and they
62
- document the version in that package rather than the current release. An agent with no network
63
- reach has them, and so does one working on a project held a few versions back. Ripgrep and most
64
- editor search skip `node_modules` by default. An agent finds these files when something names the
65
- path for it.
66
-
67
- The skill lives at
68
- [kensio.ai/skills/yulin-aws-simulation](https://kensio.ai/skills/yulin-aws-simulation), versioned
69
- separately from Yulin and licensed Apache-2.0.
25
+ The skill is also published as the `@kensio/yulin-aws-simulation` npm package. Each
26
+ [kensio.ai release](https://github.com/KensioSoftware/kensio.ai/releases) includes a zip archive for
27
+ installations that cannot reach a package registry.
28
+
29
+ ## What the skill teaches
30
+
31
+ The skill tells an agent how to:
32
+
33
+ - use `SimAws` and `SimSdk` directly
34
+ - deploy the same synthesized CDK template in tests and local development
35
+ - choose between deploying a resource and registering one directly
36
+ - intercept AWS SDK clients without keeping separate hand-written stubs
37
+ - control simulated time
38
+ - inspect simulated state in assertions
39
+ - match simulated service errors by `name`
40
+ - share an expensive deployment across tests in one file
41
+ - invoke code through a simulated Lambda function with its configured role and environment
42
+ - treat unsupported behaviour as a gap to report, not behaviour to guess
43
+
44
+ ## Give the agent access to the API docs
45
+
46
+ The skill covers testing choices. The service guides document Yulin's APIs and supported AWS
47
+ behaviour.
48
+
49
+ The skill points agents to [yulinsim.dev/llms.txt](https://yulinsim.dev/llms.txt). That file indexes
50
+ plain Markdown versions of every guide on the documentation site. Append `llms.txt` to a page URL to
51
+ read that page as Markdown.
52
+
53
+ The npm package includes the same documentation under `node_modules/@kensio/yulin/docs/`. Its index
54
+ is `node_modules/@kensio/yulin/llms.txt`. These files match the installed Yulin version and remain
55
+ available without network access. Some search tools skip `node_modules` unless the path is given
56
+ explicitly.
57
+
58
+ ## Limitations
59
+
60
+ - The skill does not replace the service guides. An agent still needs the relevant guide when it
61
+ works with a service command, event shape, or limitation.
62
+ - The skill is versioned separately from Yulin. The documentation included in the installed Yulin
63
+ package is the reference for that package version.
64
+
65
+ The skill source is available at
66
+ [kensio.ai/skills/yulin-aws-simulation](https://kensio.ai/skills/yulin-aws-simulation) under the
67
+ Apache-2.0 licence.
@@ -1,15 +1,11 @@
1
- # AWS CLI
1
+ # Use the AWS CLI with Yulin
2
2
 
3
- The real `aws` CLI reaches a served simulated environment over a local endpoint URL, and twenty of
4
- Yulin's twenty-five SDK-facing services answer it.
3
+ Point the AWS CLI at a served `SimAws` instance to run supported commands against simulated AWS.
5
4
 
6
- [Serving on localhost](https://yulinsim.dev/serve/) is the reference for what each service serves. This page
7
- covers the way in from a shell.
5
+ ## Start a local endpoint
8
6
 
9
- ## An endpoint and a key to sign with
10
-
11
- Serving binds a simulated environment to a port. A served request runs as whoever signed it, and the
12
- access key to sign the first one comes from simulated IAM in the process that built the environment:
7
+ Create an IAM user and access key in the simulation, then pass the same `SimAws` instance to
8
+ `serveSimAws`:
13
9
 
14
10
  ```typescript sim-cli-endpoint
15
11
  /**
@@ -53,12 +49,11 @@ console.log(
53
49
  console.log(`export AWS_DEFAULT_REGION=${simAws.defaultRegionName}`);
54
50
  ```
55
51
 
56
- Pin the port when the URL has to stay the same between runs. Without one the server takes whatever
57
- is free.
52
+ Set `port` when scripts need a stable endpoint. If you omit it, Yulin chooses an available port.
58
53
 
59
- ## Configuring the CLI
54
+ ## Configure the CLI
60
55
 
61
- Four environment variables are the whole configuration:
56
+ Export the endpoint, simulated credentials, and Region printed by the setup script:
62
57
 
63
58
  ```bash
64
59
  export AWS_ENDPOINT_URL=http://localhost:8787
@@ -67,8 +62,8 @@ export AWS_SECRET_ACCESS_KEY=RzIvKRp1sd5yXfEifA1twsUTd4GlHL5JpzvECpox
67
62
  export AWS_DEFAULT_REGION=us-east-1
68
63
  ```
69
64
 
70
- `sts get-caller-identity` is the call to check the wiring with. It reports the principal behind the
71
- key that signed the request:
65
+ Run `sts get-caller-identity` to check the connection. It returns the simulated principal that owns
66
+ the access key:
72
67
 
73
68
  ```bash
74
69
  aws sts get-caller-identity
@@ -79,16 +74,15 @@ aws sts get-caller-identity
79
74
  }
80
75
  ```
81
76
 
82
- The credentials have to come from simulated IAM. Any other key is refused with `403 Forbidden`, and
83
- an unsigned request reaches nothing.
77
+ The credentials must come from simulated IAM. Yulin rejects an unknown key with `403 Forbidden`.
78
+ It also rejects unsigned AWS API requests.
84
79
 
85
- A Region is required, as it is against real AWS. Changing it moves the CLI between simulated
86
- Regions, and a Queue created under `eu-west-2` is invisible to `AWS_DEFAULT_REGION=us-east-1`.
80
+ A Region is required. Changing `AWS_DEFAULT_REGION` selects another simulated Region. For example,
81
+ a queue created in `eu-west-2` is absent from `us-east-1`.
87
82
 
88
- ### A named profile instead
83
+ ### Use a named profile
89
84
 
90
- A profile in the CLI's own config file carries the same four values. The simulation then stays out
91
- of the ambient environment:
85
+ You can put the endpoint and credentials in the AWS CLI config:
92
86
 
93
87
  ```ini
94
88
  [profile sim]
@@ -98,12 +92,12 @@ aws_access_key_id = AKIAVEXOWARWMKBOA0MP
98
92
  aws_secret_access_key = RzIvKRp1sd5yXfEifA1twsUTd4GlHL5JpzvECpox
99
93
  ```
100
94
 
101
- `aws --profile sim sts get-caller-identity` then reaches the simulation while a bare `aws` still
102
- goes to real AWS. The profile has to carry credentials of its own. Once `--profile` is given the CLI
103
- stops reading `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` from the environment.
95
+ Now `aws --profile sim sts get-caller-identity` reaches Yulin. The profile must contain its own
96
+ credentials because the CLI stops reading `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` after you
97
+ pass `--profile`.
104
98
 
105
- `role_arn` and `source_profile` work too. The CLI assumes the simulated Role for itself and signs
106
- with the session it gets back:
99
+ Profiles with `role_arn` and `source_profile` also work. The CLI calls simulated STS and signs later
100
+ requests with the returned role session:
107
101
 
108
102
  ```ini
109
103
  [profile reader]
@@ -113,10 +107,10 @@ role_arn = arn:aws:iam::888888888888:role/Reader
113
107
  source_profile = sim
114
108
  ```
115
109
 
116
- ## Building the rest of the identities from the shell
110
+ ## Create more simulated identities
117
111
 
118
- Only the first key has to come from the process that built the simulation. `aws iam` builds
119
- everything after it:
112
+ Only the first access key needs to come from the setup process. Use `aws iam` to create more users
113
+ and keys through the endpoint:
120
114
 
121
115
  ```bash
122
116
  aws iam create-user --user-name shopper
@@ -125,8 +119,8 @@ aws iam put-user-policy --user-name shopper --policy-name read-buckets \
125
119
  aws iam create-access-key --user-name shopper
126
120
  ```
127
121
 
128
- `create-access-key` answers with the secret once. Signing with the new key reports the new User, and
129
- simulated IAM authorizes every request against the policy it was given:
122
+ `create-access-key` returns the secret once. Requests signed with the new key run as the new user and
123
+ are checked against its simulated IAM policies:
130
124
 
131
125
  ```bash
132
126
  aws s3api create-bucket --bucket nope
@@ -136,8 +130,8 @@ arn:aws:iam::888888888888:user/shopper is not authorized to perform: s3:CreateBu
136
130
  arn:aws:s3:::nope
137
131
  ```
138
132
 
139
- `aws sts assume-role` answers with temporary credentials. Export the three values it returns and the
140
- rest of the session runs as the Role:
133
+ `aws sts assume-role` returns temporary credentials. Export the access key, secret key, and session
134
+ token to run later commands as the role:
141
135
 
142
136
  ```bash
143
137
  aws sts assume-role --role-arn arn:aws:iam::888888888888:role/Reader --role-session-name probe
@@ -146,17 +140,12 @@ export AWS_SECRET_ACCESS_KEY=jm2N56vfVtLgJEo11OtbIXbgnJBgxpUMrszPrQdl
146
140
  export AWS_SESSION_TOKEN=11568oBDksY9czECUMiAWk9tzmvG7zlQNjtLI1WmhZFS...
147
141
  ```
148
142
 
149
- The expiry is stamped from the simulation's own clock, and
150
- [advancing it](https://yulinsim.dev/time/) past the expiry stops the session authenticating.
151
-
152
- ## What answers
143
+ The credentials expire according to [simulated time](https://yulinsim.dev/time/). Requests fail once
144
+ the `SimAws` clock passes their expiry.
153
145
 
154
- Twenty simulated services answer the endpoint. S3, STS, IAM, ELBv2, SNS, CloudFormation and Lambda,
155
- along with the AWS JSON protocol services: DynamoDB, DynamoDB Streams, SQS, Cognito Identity
156
- Provider, EventBridge, ECS, SSM, ACM, CloudWatch, CloudWatch Logs, KMS, Secrets Manager and
157
- Rekognition.
146
+ ## Run service commands
158
147
 
159
- A quick tour of the ones a shell reaches for most:
148
+ Use ordinary AWS CLI commands after the endpoint is configured:
160
149
 
161
150
  ```bash
162
151
  aws s3 cp ./index.html s3://widgets/index.html
@@ -168,16 +157,12 @@ aws secretsmanager get-secret-value --secret-id shop/db --query SecretString --o
168
157
  aws logs describe-log-groups --query 'logGroups[].logGroupName' --output text
169
158
  ```
170
159
 
171
- `--query`, `--output text` and the rest of the CLI's own machinery work throughout, because they run
172
- client-side over an ordinary AWS response.
160
+ Client-side CLI options such as `--query` and `--output text` work with simulated responses.
173
161
 
174
- [The serve docs](https://yulinsim.dev/serve/#which-services-answer) list the operations each service
175
- implements. Anything outside those lists is refused as `NotImplemented`.
162
+ The [localhost server guide](https://yulinsim.dev/serve/#which-services-answer) lists the operations
163
+ available for each service. Yulin returns `NotImplemented` for other operations.
176
164
 
177
- ## CLI traps
178
-
179
- Each of these is CLI behaviour, and each catches people out against real AWS too. They are collected
180
- here because a simulated endpoint is often where someone meets them first.
165
+ ## Commands that need extra configuration
181
166
 
182
167
  ### `--payload` needs `--cli-binary-format`
183
168
 
@@ -189,7 +174,7 @@ aws lambda invoke --function-name orders --payload '{"id":1}' out.json
189
174
  aws: [ERROR]: Invalid base64: "{"id":1}"
190
175
  ```
191
176
 
192
- Pass `--cli-binary-format raw-in-base64-out` and the same call runs the function:
177
+ Pass `--cli-binary-format raw-in-base64-out` to send the JSON payload:
193
178
 
194
179
  ```bash
195
180
  aws lambda invoke --function-name orders --payload '{"id":1}' \
@@ -197,22 +182,21 @@ aws lambda invoke --function-name orders --payload '{"id":1}' \
197
182
  cat out.json
198
183
  ```
199
184
 
200
- `--invocation-type Event` answers `202` and runs the handler on the background scheduler. A script
201
- reading what the function did waits on `simAws.backgroundTasksComplete()` first.
185
+ `--invocation-type Event` returns `202` before the handler runs. Code in the server process can call
186
+ `simAws.backgroundTasksComplete()` before inspecting the result.
202
187
 
203
188
  ### S3 addressing style
204
189
 
205
- The CLI needs nothing here. Its default `auto` style sends path-style requests to a custom endpoint,
206
- which is what this endpoint routes. An SDK client is the one that needs `forcePathStyle: true`.
190
+ The CLI's default `auto` addressing style sends path-style requests to custom endpoints. Yulin
191
+ supports that form. AWS SDK clients need `forcePathStyle: true` when they use the served endpoint.
207
192
 
208
- Forcing `addressing_style = virtual` in the config file breaks it. The Bucket moves into a hostname
209
- the endpoint has no route for, and `list-objects-v2` comes back empty while `head-object` comes back
210
- `404`.
193
+ Do not set `addressing_style = virtual` for the CLI profile. Yulin does not route virtual-hosted S3
194
+ API requests through the general endpoint.
211
195
 
212
196
  ### `aws cloudformation deploy` uses change sets
213
197
 
214
- `deploy` is a CLI-side wrapper over `CreateChangeSet`, and simulated CloudFormation implements four
215
- operations that do not include it:
198
+ The CLI implements `aws cloudformation deploy` with change sets. Yulin does not serve
199
+ `CreateChangeSet`, so the command fails:
216
200
 
217
201
  ```bash
218
202
  aws cloudformation deploy --stack-name site --template-file template.json
@@ -221,26 +205,25 @@ aws: [ERROR]: An error occurred (NotImplemented) when calling the CreateChangeSe
221
205
  Simulated CloudFormation does not serve CreateChangeSet
222
206
  ```
223
207
 
224
- `create-stack` and `describe-stacks` do work. A deployment starts in the background and
225
- `create-stack` is answered before the Resources exist, as real CloudFormation answers it.
208
+ Use `create-stack` and `describe-stacks` instead. `create-stack` returns while resource creation runs
209
+ in the background.
226
210
 
227
- ### Presigning needs the S3 service hostname
211
+ ### Presigned S3 URLs
228
212
 
229
- `aws s3 presign` signs whatever endpoint the CLI is configured with, and a URL built over the
230
- general endpoint has no Bucket in it for the endpoint to route on. Point the one command at
231
- simulated S3's own hostname on the served port:
213
+ Run `aws s3 presign` against the configured endpoint:
232
214
 
233
215
  ```bash
234
- aws --endpoint-url http://s3.us-east-1.sim-aws.localhost:8787 s3 presign s3://widgets/one.txt
216
+ aws s3 presign s3://widgets/one.txt
235
217
  ```
236
218
 
237
- The URL that comes back is fetchable by anything, including `curl` and a browser. The same hostname
238
- serves [presigned URLs built by the SDK](https://yulinsim.dev/services/s3/#presigned-urls).
219
+ The returned URL includes a signed credential scope, which Yulin uses to route the request to S3.
220
+ It works with `curl`, a browser, or another HTTP client. The S3 guide also covers
221
+ [presigned URLs built with the SDK](https://yulinsim.dev/services/s3/#presigned-urls).
239
222
 
240
223
  ### A bad key looks like an XML parse failure
241
224
 
242
- STS, IAM and ELBv2 speak the AWS Query protocol and expect an XML body. The endpoint answers a
243
- rejected signature as JSON. The CLI reports the body it could not parse:
225
+ STS, IAM, and ELBv2 return XML responses. Yulin currently returns a rejected signature as JSON for
226
+ these services, so the CLI reports an XML parsing error:
244
227
 
245
228
  ```bash
246
229
  aws sts get-caller-identity
@@ -250,18 +233,38 @@ XML received. Further retries may succeed:
250
233
  b'{"Message":"Forbidden"}'
251
234
  ```
252
235
 
253
- `Forbidden` in the quoted body is the real answer. The other seventeen services report the same
254
- rejection as a plain `403`.
236
+ The `{"Message":"Forbidden"}` body means that the access key or signature was rejected. Other served
237
+ services report the rejection as a plain `403`.
238
+
239
+ ## Available functionality
240
+
241
+ The served AWS API supports CLI operations for these services:
242
+
243
+ - ACM
244
+ - CloudFormation
245
+ - CloudWatch metrics and CloudWatch Logs
246
+ - Cognito Identity Provider
247
+ - DynamoDB and DynamoDB Streams
248
+ - ECS and Elastic Load Balancing v2
249
+ - EventBridge
250
+ - IAM and STS
251
+ - KMS and Secrets Manager
252
+ - Lambda
253
+ - Rekognition
254
+ - S3
255
+ - SNS and SQS
256
+ - SSM Parameter Store
257
+
258
+ Profiles and role assumption work with the endpoint. Client-side features such as JMESPath queries
259
+ and output formatting work with simulated responses.
255
260
 
256
261
  ## Limitations
257
262
 
258
- - Five services are refused with `501 Not Implemented`. Route 53 and CloudFront speak REST-XML, and
259
- API Gateway v2, SES v2 and EventBridge Scheduler speak REST-JSON. Every one of them is reachable
260
- in process through `SimAws` and through [SDK interception](https://yulinsim.dev/sdk/). Simulated ECR is
261
- refused the same way and has no AWS API surface at all, since its images are registered in
262
- process.
263
- - An operation a served service has not implemented is refused as `NotImplemented`. That is a
264
- separate answer from the protocol refusal above. `aws iam list-users` reports
263
+ - Services absent from the list above are not available through the general AWS API endpoint. Use
264
+ `SimAws` directly or [SDK interception](https://yulinsim.dev/sdk/) where the service supports it.
265
+ Simulated ECR exposes only an in-process API.
266
+ - An unsupported operation on a served service returns `NotImplemented`. For example,
267
+ `aws iam list-users` reports
265
268
  `Simulated IAM does not serve ListUsers`, and `aws lambda list-functions` names the path it
266
269
  arrived at.
267
270
  - `aws cloudwatch get-metric-statistics` and `aws cloudwatch get-metric-data` fail with
@@ -269,16 +272,3 @@ rejection as a plain `403`.
269
272
  seconds and the endpoint hands that number to the simulation where a `Date` is expected. Both
270
273
  reads work in process and through SDK interception. `put-metric-data` and `list-metrics` are
271
274
  unaffected.
272
- - `aws s3 cp` and `aws s3 sync` corrupt a **download** above the CLI's 8MB threshold
273
- ([#717](https://github.com/KensioSoftware/yulin/issues/717)). The CLI splits
274
- the download into ranged GETs, simulated S3 ignores `Range` and returns the whole Object for each
275
- one, and the parts land on top of each other. A 12MB Object arrives as a 20MB file. Uploads above
276
- the threshold are fine, and so is any download under it. Two ways round it, both verified.
277
- `aws s3api get-object` issues one unranged GET. Raising the threshold in the config file keeps
278
- `aws s3 cp` on a single GET too.
279
-
280
- ```ini
281
- [profile sim]
282
- s3 =
283
- multipart_threshold = 5GB
284
- ```