@kensio/yulin 1.20.15 → 1.20.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/dist/sdk/module/sim-sdk-module-client-interceptor.d.ts +5 -0
- package/dist/sdk/module/sim-sdk-module-client-interceptor.js +14 -0
- package/dist/sdk/module/sim-sdk-static-client-factory.d.ts +26 -0
- package/dist/sdk/module/sim-sdk-static-client-factory.js +59 -0
- package/dist/sdk/send-patch.d.ts +8 -0
- package/dist/sdk/send-patch.js +11 -0
- package/dist/service/aws/caller/sim-aws-caller-resolver.d.ts +28 -6
- package/dist/service/aws/caller/sim-aws-caller-resolver.js +18 -11
- package/dist/service/aws/caller/sim-aws-caller.d.ts +9 -0
- package/dist/service/aws/caller/sim-aws-resolved-caller.d.ts +19 -0
- package/dist/service/aws/caller/sim-aws-resolved-caller.js +26 -0
- package/dist/service/aws/factory/sim-aws-account-region-service-builder.d.ts +6 -0
- package/dist/service/aws/factory/sim-aws-account-region-service-builder.js +3 -0
- package/dist/service/aws/factory/sim-aws-account-service-cache.d.ts +6 -0
- package/dist/service/aws/factory/sim-aws-account-service-cache.js +5 -0
- package/dist/service/aws/factory/sim-aws-service-factory.d.ts +5 -0
- package/dist/service/aws/factory/sim-aws-service-factory.js +6 -0
- package/dist/service/aws/sim-aws-properties.d.ts +15 -0
- package/dist/service/aws/sim-aws.js +2 -1
- package/dist/service/iam/authorize/context/sim-iam-auth-z-caller-context-builder.d.ts +30 -7
- package/dist/service/iam/authorize/context/sim-iam-auth-z-caller-context-builder.js +20 -11
- package/dist/service/iam/authorize/context/sim-iam-auth-z-context-builder.d.ts +2 -1
- package/dist/service/iam/authorize/context/sim-iam-auth-z-context-builder.js +5 -1
- package/dist/service/iam/authorize/match/sim-iam-policy-principal-matcher.d.ts +10 -0
- package/dist/service/iam/authorize/match/sim-iam-policy-principal-matcher.js +15 -3
- package/dist/service/iam/authorize/sim-iam-account-auth-z.d.ts +11 -4
- package/dist/service/iam/authorize/sim-iam-account-auth-z.js +5 -3
- package/dist/service/iam/authorize/sim-iam-authorizer.d.ts +2 -1
- package/dist/service/iam/authorize/sim-iam-authorizer.js +1 -0
- package/dist/service/iam/role/sim-iam-role-with-policy.factory.d.ts +9 -0
- package/dist/service/iam/role/sim-iam-role-with-policy.factory.js +4 -2
- package/dist/service/iam/sim-iam-account-parts.d.ts +8 -0
- package/dist/service/iam/sim-iam-account-parts.js +1 -0
- package/dist/service/sts/auth-z/assume-role-auth-z-coordinator.d.ts +9 -2
- package/dist/service/sts/auth-z/assume-role-auth-z-coordinator.js +2 -2
- package/dist/service/sts/auth-z/assume-role-source-account-auth-z.d.ts +10 -4
- package/dist/service/sts/auth-z/assume-role-source-account-auth-z.js +8 -7
- package/dist/service/sts/auth-z/assume-role-target-auth-z.d.ts +2 -2
- package/dist/service/sts/auth-z/assume-role-trust-policy-authorizer.d.ts +6 -2
- package/dist/service/sts/auth-z/assume-role-trust-policy-authorizer.js +14 -11
- package/dist/service/sts/command/assume-role/assume-role.handler.d.ts +5 -1
- package/dist/service/sts/command/assume-role/assume-role.handler.js +5 -2
- package/dist/service/sts/command/get-caller-identity/get-caller-identity.handler.d.ts +5 -1
- package/dist/service/sts/command/get-caller-identity/get-caller-identity.handler.js +4 -1
- package/dist/service/sts/service-role/sim-service-role.js +5 -1
- package/dist/service/sts/sim-sts.d.ts +9 -1
- package/dist/service/sts/sim-sts.js +4 -0
- package/docs/README.md +54 -0
- package/docs/ai-skill/README.md +69 -0
- package/docs/cli/README.md +284 -0
- package/docs/factories/README.md +140 -0
- package/docs/lint/README.md +176 -0
- package/docs/non-aws-dependencies/README.md +261 -0
- package/docs/sdk/README.md +272 -0
- package/docs/serve/README.md +1126 -0
- package/docs/services/acm/README.md +823 -0
- package/docs/services/apigateway/README.md +1919 -0
- package/docs/services/apigatewayv2/README.md +2678 -0
- package/docs/services/athena/README.md +1044 -0
- package/docs/services/bedrock/README.md +350 -0
- package/docs/services/cloudformation/README.md +3440 -0
- package/docs/services/cloudfront/README.md +2874 -0
- package/docs/services/cloudwatch/README.md +420 -0
- package/docs/services/cognito/README.md +4923 -0
- package/docs/services/dynamodb/README.md +3784 -0
- package/docs/services/ecr/README.md +302 -0
- package/docs/services/ecs/README.md +2010 -0
- package/docs/services/elbv2/README.md +1897 -0
- package/docs/services/eventbridge/README.md +1110 -0
- package/docs/services/firehose/README.md +805 -0
- package/docs/services/glue/README.md +501 -0
- package/docs/services/iam/README.md +1283 -0
- package/docs/services/kinesis/README.md +454 -0
- package/docs/services/kms/README.md +659 -0
- package/docs/services/lambda/README.md +3645 -0
- package/docs/services/logs/README.md +868 -0
- package/docs/services/organizations/README.md +574 -0
- package/docs/services/personalize/README.md +835 -0
- package/docs/services/rekognition/README.md +1070 -0
- package/docs/services/route53/README.md +1783 -0
- package/docs/services/s3/README.md +3024 -0
- package/docs/services/scheduler/README.md +806 -0
- package/docs/services/secretsmanager/README.md +667 -0
- package/docs/services/ses/README.md +1011 -0
- package/docs/services/sns/README.md +1904 -0
- package/docs/services/sqs/README.md +1185 -0
- package/docs/services/ssm/README.md +1072 -0
- package/docs/services/stepfunctions/README.md +1332 -0
- package/docs/services/sts/README.md +245 -0
- package/docs/services/wafv2/README.md +1378 -0
- package/docs/terraform/README.md +248 -0
- package/docs/time/README.md +284 -0
- package/llms.txt +59 -0
- package/package.json +7 -4
package/README.md
CHANGED
|
@@ -22,6 +22,8 @@ npm i -D @kensio/yulin
|
|
|
22
22
|
- [ACM](https://yulinsim.dev/services/acm/ "Simulated ACM docs")
|
|
23
23
|
- [API Gateway HTTP APIs](https://yulinsim.dev/services/apigatewayv2/ "Simulated API Gateway HTTP API docs")
|
|
24
24
|
- [API Gateway REST APIs](https://yulinsim.dev/services/apigateway/ "Simulated API Gateway REST API docs")
|
|
25
|
+
- [Athena](https://yulinsim.dev/services/athena/ "Simulated Amazon Athena docs")
|
|
26
|
+
- [Bedrock](https://yulinsim.dev/services/bedrock/ "Simulated Amazon Bedrock docs")
|
|
25
27
|
- [CloudFormation](https://yulinsim.dev/services/cloudformation/ "Simulated CloudFormation docs")
|
|
26
28
|
- [CloudFront](https://yulinsim.dev/services/cloudfront/ "Simulated CloudFront docs")
|
|
27
29
|
- [CloudWatch metrics](https://yulinsim.dev/services/cloudwatch/ "Simulated CloudWatch metrics docs")
|
|
@@ -29,12 +31,16 @@ npm i -D @kensio/yulin
|
|
|
29
31
|
- [DynamoDB](https://yulinsim.dev/services/dynamodb/ "Simulated DynamoDB docs")
|
|
30
32
|
- [ECR](https://yulinsim.dev/services/ecr/ "Simulated ECR docs")
|
|
31
33
|
- [ECS](https://yulinsim.dev/services/ecs/ "Simulated ECS docs")
|
|
34
|
+
- [Elastic Load Balancing](https://yulinsim.dev/services/elbv2/ "Simulated Application Load Balancer docs")
|
|
32
35
|
- [EventBridge](https://yulinsim.dev/services/eventbridge/ "Simulated EventBridge docs")
|
|
33
36
|
- [Glue](https://yulinsim.dev/services/glue/ "Simulated Glue Data Catalog docs")
|
|
34
37
|
- [IAM](https://yulinsim.dev/services/iam/ "Simulated IAM docs")
|
|
38
|
+
- [Kinesis Data Firehose](https://yulinsim.dev/services/firehose/ "Simulated Kinesis Data Firehose docs")
|
|
39
|
+
- [Kinesis Data Streams](https://yulinsim.dev/services/kinesis/ "Simulated Kinesis Data Streams docs")
|
|
35
40
|
- [KMS](https://yulinsim.dev/services/kms/ "Simulated KMS docs")
|
|
36
41
|
- [Lambda](https://yulinsim.dev/services/lambda/ "Simulated Lambda docs")
|
|
37
42
|
- [CloudWatch Logs](https://yulinsim.dev/services/logs/ "Simulated CloudWatch Logs docs")
|
|
43
|
+
- [Organizations](https://yulinsim.dev/services/organizations/ "Simulated Organizations service control policies docs")
|
|
38
44
|
- [Personalize](https://yulinsim.dev/services/personalize/ "Simulated Amazon Personalize docs")
|
|
39
45
|
- [Rekognition](https://yulinsim.dev/services/rekognition/ "Simulated Rekognition docs")
|
|
40
46
|
- [Route53](https://yulinsim.dev/services/route53/ "Simulated Route53 docs")
|
|
@@ -54,10 +60,17 @@ npm i -D @kensio/yulin
|
|
|
54
60
|
- [AI skill](https://yulinsim.dev/ai-skill/ "Yulin AI skill docs")
|
|
55
61
|
- [The AWS CLI](https://yulinsim.dev/cli/ "The AWS CLI against simulated AWS docs")
|
|
56
62
|
- [AWS SDK interception](https://yulinsim.dev/sdk/ "Simulated AWS SDK docs")
|
|
63
|
+
- [Event factories](https://yulinsim.dev/factories/ "Test factories for AWS event shapes docs")
|
|
64
|
+
- [Linting CloudFront Functions JS2](https://yulinsim.dev/lint/ "CloudFront Functions JS2 lint config docs")
|
|
65
|
+
- [Non-AWS dependencies](https://yulinsim.dev/non-aws-dependencies/ "Dependencies Yulin does not simulate docs")
|
|
57
66
|
- [Serving on localhost](https://yulinsim.dev/serve/ "Serving simulated AWS on localhost docs")
|
|
58
67
|
- [Simulated time](https://yulinsim.dev/time/ "Simulated time docs")
|
|
59
68
|
- [Terraform](https://yulinsim.dev/terraform/ "Deploying Terraform into simulated AWS docs")
|
|
60
69
|
|
|
70
|
+
Every page listed above also ships inside the package as markdown, documenting the version
|
|
71
|
+
installed. `node_modules/@kensio/yulin/llms.txt` indexes them, and a coding agent with no network
|
|
72
|
+
reach can read them from there.
|
|
73
|
+
|
|
61
74
|
## Usage
|
|
62
75
|
|
|
63
76
|
### Intercept AWS SDK clients
|
|
@@ -40,6 +40,11 @@ export declare class SimSdkModuleClientInterceptor {
|
|
|
40
40
|
*
|
|
41
41
|
* Reflect.construct with the incoming new target preserves subclassing and
|
|
42
42
|
* instanceof against the real class.
|
|
43
|
+
*
|
|
44
|
+
* The class's own static methods are wrapped as well, so a client built by
|
|
45
|
+
* a static factory such as `DynamoDBDocumentClient.from` is patched too.
|
|
46
|
+
* Such a factory constructs from the class binding it closes over rather
|
|
47
|
+
* than through this proxy, so the construct trap never sees it.
|
|
43
48
|
*/
|
|
44
49
|
private wrapClientClass;
|
|
45
50
|
/**
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { installSendPatch } from "../send-patch.js";
|
|
2
|
+
import { SimSdkStaticClientFactories } from "./sim-sdk-static-client-factory.js";
|
|
2
3
|
/**
|
|
3
4
|
* Intercepts the SDK client classes exported by an AWS SDK package module.
|
|
4
5
|
*
|
|
@@ -56,16 +57,29 @@ export class SimSdkModuleClientInterceptor {
|
|
|
56
57
|
*
|
|
57
58
|
* Reflect.construct with the incoming new target preserves subclassing and
|
|
58
59
|
* instanceof against the real class.
|
|
60
|
+
*
|
|
61
|
+
* The class's own static methods are wrapped as well, so a client built by
|
|
62
|
+
* a static factory such as `DynamoDBDocumentClient.from` is patched too.
|
|
63
|
+
* Such a factory constructs from the class binding it closes over rather
|
|
64
|
+
* than through this proxy, so the construct trap never sees it.
|
|
59
65
|
*/
|
|
60
66
|
wrapClientClass(clientClass) {
|
|
61
67
|
const sendHandler = this.sendHandler;
|
|
62
68
|
const configureArguments = (constructorArguments) => this.regionDefaultedArguments(constructorArguments);
|
|
69
|
+
const staticFactories = new SimSdkStaticClientFactories(sendHandler);
|
|
63
70
|
return new Proxy(clientClass, {
|
|
64
71
|
construct(target, constructorArguments, newTarget) {
|
|
65
72
|
const instance = Reflect.construct(target, configureArguments(constructorArguments), newTarget);
|
|
66
73
|
installSendPatch(instance, sendHandler);
|
|
67
74
|
return instance;
|
|
68
75
|
},
|
|
76
|
+
get(target, property, receiver) {
|
|
77
|
+
const value = Reflect.get(target, property, receiver);
|
|
78
|
+
if (typeof value !== "function" || !Object.hasOwn(target, property)) {
|
|
79
|
+
return value;
|
|
80
|
+
}
|
|
81
|
+
return staticFactories.wrap(value);
|
|
82
|
+
},
|
|
69
83
|
});
|
|
70
84
|
}
|
|
71
85
|
/**
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type SimSdkSendHandler } from "../send-patch.js";
|
|
2
|
+
/**
|
|
3
|
+
* The wrapped static methods of one intercepted SDK client class.
|
|
4
|
+
*
|
|
5
|
+
* A static factory such as `DynamoDBDocumentClient.from` constructs from the
|
|
6
|
+
* class binding it closes over rather than through the class the calling code
|
|
7
|
+
* holds, so the client it builds is never seen by the interception's construct
|
|
8
|
+
* trap. Wrapping the method send-patches that client on the way back out.
|
|
9
|
+
*
|
|
10
|
+
* Each method is wrapped once, so the class keeps handing out the same
|
|
11
|
+
* function for the same static.
|
|
12
|
+
*/
|
|
13
|
+
export declare class SimSdkStaticClientFactories {
|
|
14
|
+
private readonly sendHandler;
|
|
15
|
+
private readonly wrappers;
|
|
16
|
+
constructor(sendHandler: SimSdkSendHandler);
|
|
17
|
+
/**
|
|
18
|
+
* The patching wrapper for one static method.
|
|
19
|
+
*/
|
|
20
|
+
wrap(method: object): unknown;
|
|
21
|
+
/**
|
|
22
|
+
* A Proxy rather than a plain function keeps the method's own identity
|
|
23
|
+
* surface, such as its name, length and any properties hung off it.
|
|
24
|
+
*/
|
|
25
|
+
private wrapMethod;
|
|
26
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { hasSendPatch, installSendPatch, } from "../send-patch.js";
|
|
2
|
+
/**
|
|
3
|
+
* The wrapped static methods of one intercepted SDK client class.
|
|
4
|
+
*
|
|
5
|
+
* A static factory such as `DynamoDBDocumentClient.from` constructs from the
|
|
6
|
+
* class binding it closes over rather than through the class the calling code
|
|
7
|
+
* holds, so the client it builds is never seen by the interception's construct
|
|
8
|
+
* trap. Wrapping the method send-patches that client on the way back out.
|
|
9
|
+
*
|
|
10
|
+
* Each method is wrapped once, so the class keeps handing out the same
|
|
11
|
+
* function for the same static.
|
|
12
|
+
*/
|
|
13
|
+
export class SimSdkStaticClientFactories {
|
|
14
|
+
sendHandler;
|
|
15
|
+
wrappers = new WeakMap();
|
|
16
|
+
constructor(sendHandler) {
|
|
17
|
+
this.sendHandler = sendHandler;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The patching wrapper for one static method.
|
|
21
|
+
*/
|
|
22
|
+
wrap(method) {
|
|
23
|
+
const wrapped = this.wrappers.get(method) ?? this.wrapMethod(method);
|
|
24
|
+
this.wrappers.set(method, wrapped);
|
|
25
|
+
return wrapped;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A Proxy rather than a plain function keeps the method's own identity
|
|
29
|
+
* surface, such as its name, length and any properties hung off it.
|
|
30
|
+
*/
|
|
31
|
+
wrapMethod(method) {
|
|
32
|
+
const sendHandler = this.sendHandler;
|
|
33
|
+
return new Proxy(method, {
|
|
34
|
+
apply(target, thisArgument, callArguments) {
|
|
35
|
+
const result = Reflect.apply(target, thisArgument, callArguments);
|
|
36
|
+
if (isUnpatchedClient(result)) {
|
|
37
|
+
installSendPatch(result, sendHandler);
|
|
38
|
+
}
|
|
39
|
+
return result;
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Whether a static method's return value is a client still to be patched.
|
|
46
|
+
*
|
|
47
|
+
* A factory building through the intercepted class itself has already been
|
|
48
|
+
* patched by the construct trap, so patching again is skipped rather than
|
|
49
|
+
* rejected as a double interception.
|
|
50
|
+
*/
|
|
51
|
+
function isUnpatchedClient(value) {
|
|
52
|
+
if (typeof value !== "object" || value === null) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
if (typeof value.send !== "function") {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
return !hasSendPatch(value);
|
|
59
|
+
}
|
package/dist/sdk/send-patch.d.ts
CHANGED
|
@@ -29,3 +29,11 @@ export interface SimSdkSendPatch {
|
|
|
29
29
|
* inherited send resolves again.
|
|
30
30
|
*/
|
|
31
31
|
export declare function installSendPatch(target: object, handler: SimSdkSendHandler): SimSdkSendPatch;
|
|
32
|
+
/**
|
|
33
|
+
* Whether a simulated send patch is currently installed on a target.
|
|
34
|
+
*
|
|
35
|
+
* Only an own patched send counts, which is the property installSendPatch
|
|
36
|
+
* writes, so an instance inheriting a patched send from a patched prototype
|
|
37
|
+
* reports false.
|
|
38
|
+
*/
|
|
39
|
+
export declare function hasSendPatch(target: object): boolean;
|
package/dist/sdk/send-patch.js
CHANGED
|
@@ -50,6 +50,17 @@ export function installSendPatch(target, handler) {
|
|
|
50
50
|
},
|
|
51
51
|
};
|
|
52
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Whether a simulated send patch is currently installed on a target.
|
|
55
|
+
*
|
|
56
|
+
* Only an own patched send counts, which is the property installSendPatch
|
|
57
|
+
* writes, so an instance inheriting a patched send from a patched prototype
|
|
58
|
+
* reports false.
|
|
59
|
+
*/
|
|
60
|
+
export function hasSendPatch(target) {
|
|
61
|
+
const send = Object.getOwnPropertyDescriptor(target, "send")?.value;
|
|
62
|
+
return typeof send === "function" && installedSends.has(send);
|
|
63
|
+
}
|
|
53
64
|
/**
|
|
54
65
|
* Name a patch target for diagnostics: the client's class name for instances
|
|
55
66
|
* and prototypes alike, when it has one.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SimAwsCaller, SimAwsPrincipal, SimCredentialCaller } from "./sim-aws-caller.js";
|
|
1
|
+
import type { SimAwsCaller, SimAwsDefaultCaller, SimAwsPrincipal, SimCredentialCaller } from "./sim-aws-caller.js";
|
|
2
2
|
import type { SimIamCredentialIdentity } from "../../iam/credential/sim-aws-credentials.js";
|
|
3
3
|
export interface SimAwsCredentialIdentityResolver {
|
|
4
4
|
resolveCredentials(credentials: SimCredentialCaller["credentials"], now?: Date): SimIamCredentialIdentity;
|
|
@@ -17,19 +17,41 @@ export interface SimAwsResolvedCaller {
|
|
|
17
17
|
readonly accountId?: string | undefined;
|
|
18
18
|
readonly service?: string | undefined;
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* What resolving a caller needs beyond the caller itself.
|
|
22
|
+
*/
|
|
23
|
+
export interface SimAwsCallerResolverProperties {
|
|
24
|
+
/**
|
|
25
|
+
* Authenticates a caller that presents credentials.
|
|
26
|
+
*/
|
|
27
|
+
readonly credentialIdentityResolver?: SimAwsCredentialIdentityResolver | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* The caller a request naming none of its own is attributed to.
|
|
30
|
+
*
|
|
31
|
+
* A simulation sets this to say who its unattributed calls come from. It is
|
|
32
|
+
* consulted ahead of the operation default. A simulation that names no
|
|
33
|
+
* default caller keeps the Account root fallback.
|
|
34
|
+
*/
|
|
35
|
+
readonly defaultCaller?: SimAwsDefaultCaller | undefined;
|
|
36
|
+
}
|
|
20
37
|
/**
|
|
21
38
|
* Resolves caller input at a simulated AWS operation boundary.
|
|
22
39
|
*
|
|
23
|
-
* An omitted caller resolves to the
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* taken as it stands.
|
|
40
|
+
* An omitted caller resolves to the simulation's default caller, and to the
|
|
41
|
+
* supplied operation default where there is none. Explicit anonymity is
|
|
42
|
+
* preserved. Credential callers are authenticated before a resolved caller is
|
|
43
|
+
* returned, and a caller already resolved elsewhere is taken as it stands.
|
|
27
44
|
*/
|
|
28
45
|
export declare class SimAwsCallerResolver {
|
|
29
46
|
private readonly credentialIdentityResolver?;
|
|
30
|
-
|
|
47
|
+
private readonly defaultCaller?;
|
|
48
|
+
constructor(properties?: SimAwsCallerResolverProperties);
|
|
31
49
|
/**
|
|
32
50
|
* Resolve and normalize a simulated AWS caller.
|
|
51
|
+
*
|
|
52
|
+
* The request's own caller is used where it has one. A request without one
|
|
53
|
+
* falls back to the simulation's default caller, and then to the operation
|
|
54
|
+
* default the call site supplies.
|
|
33
55
|
*/
|
|
34
56
|
resolve(caller: SimAwsCaller | undefined, defaultPrincipal: SimAwsPrincipal): SimAwsResolvedCaller;
|
|
35
57
|
private normalized;
|
|
@@ -2,29 +2,36 @@ import { assertDefined } from "../../../util/type-guard/defined.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* Resolves caller input at a simulated AWS operation boundary.
|
|
4
4
|
*
|
|
5
|
-
* An omitted caller resolves to the
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* taken as it stands.
|
|
5
|
+
* An omitted caller resolves to the simulation's default caller, and to the
|
|
6
|
+
* supplied operation default where there is none. Explicit anonymity is
|
|
7
|
+
* preserved. Credential callers are authenticated before a resolved caller is
|
|
8
|
+
* returned, and a caller already resolved elsewhere is taken as it stands.
|
|
9
9
|
*/
|
|
10
10
|
export class SimAwsCallerResolver {
|
|
11
11
|
credentialIdentityResolver;
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
defaultCaller;
|
|
13
|
+
constructor(properties = {}) {
|
|
14
|
+
this.credentialIdentityResolver = properties.credentialIdentityResolver;
|
|
15
|
+
this.defaultCaller = properties.defaultCaller;
|
|
14
16
|
}
|
|
15
17
|
/**
|
|
16
18
|
* Resolve and normalize a simulated AWS caller.
|
|
19
|
+
*
|
|
20
|
+
* The request's own caller is used where it has one. A request without one
|
|
21
|
+
* falls back to the simulation's default caller, and then to the operation
|
|
22
|
+
* default the call site supplies.
|
|
17
23
|
*/
|
|
18
24
|
resolve(caller, defaultPrincipal) {
|
|
19
|
-
|
|
20
|
-
|
|
25
|
+
const stated = caller ?? this.defaultCaller;
|
|
26
|
+
if (stated?.kind === "resolved") {
|
|
27
|
+
return this.normalized(stated.principal, stated.identityPolicyPrincipal);
|
|
21
28
|
}
|
|
22
|
-
if (
|
|
29
|
+
if (stated?.kind === "credentials") {
|
|
23
30
|
assertDefined(this.credentialIdentityResolver, "Simulated credential callers require an IAM credential resolver");
|
|
24
|
-
const identity = this.credentialIdentityResolver.resolveCredentials(
|
|
31
|
+
const identity = this.credentialIdentityResolver.resolveCredentials(stated.credentials);
|
|
25
32
|
return this.normalized(identity.principal, identity.identityPolicyPrincipal);
|
|
26
33
|
}
|
|
27
|
-
const principal =
|
|
34
|
+
const principal = stated ?? defaultPrincipal;
|
|
28
35
|
return this.normalized(principal, principal);
|
|
29
36
|
}
|
|
30
37
|
normalized(principal, identityPolicyPrincipal) {
|
|
@@ -52,3 +52,12 @@ export interface SimResolvedCaller {
|
|
|
52
52
|
* Caller accepted by simulated AWS service operations.
|
|
53
53
|
*/
|
|
54
54
|
export type SimAwsCaller = SimAwsPrincipal | SimCredentialCaller | SimResolvedCaller;
|
|
55
|
+
/**
|
|
56
|
+
* Caller a simulation attributes a request that names none of its own to.
|
|
57
|
+
*
|
|
58
|
+
* A principal, or a caller something else has already resolved. Credentials
|
|
59
|
+
* are left out because the Account that issued a key is the only thing able to
|
|
60
|
+
* authenticate it, while a default is held for a whole simulation. A key from
|
|
61
|
+
* one Account would fail wherever another Account decided the request.
|
|
62
|
+
*/
|
|
63
|
+
export type SimAwsDefaultCaller = SimAwsPrincipal | SimResolvedCaller;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { SimAwsPrincipal, SimResolvedCaller } from "./sim-aws-caller.js";
|
|
2
|
+
import { type SimAwsResolvedCaller } from "./sim-aws-caller-resolver.js";
|
|
3
|
+
/**
|
|
4
|
+
* State an already-resolved caller as the caller of another request.
|
|
5
|
+
*
|
|
6
|
+
* A resolver answers with a SimAwsResolvedCaller, and a service that goes on
|
|
7
|
+
* to ask IAM about the same caller has to pass one back in. Both principals
|
|
8
|
+
* travel together, so an assumed-role session keeps the Role its policies come
|
|
9
|
+
* from instead of arriving as a session ARN that owns none.
|
|
10
|
+
*/
|
|
11
|
+
export declare function simAwsCallerFor(caller: SimAwsResolvedCaller): SimResolvedCaller;
|
|
12
|
+
/**
|
|
13
|
+
* Resolve a principal that needs nothing authenticated.
|
|
14
|
+
*
|
|
15
|
+
* A service principal, or an ARN something else has already established, is
|
|
16
|
+
* its own answer. This is the short way to the SimAwsResolvedCaller that an
|
|
17
|
+
* authorization boundary asks for.
|
|
18
|
+
*/
|
|
19
|
+
export declare function simAwsResolvedCallerOf(principal: SimAwsPrincipal): SimAwsResolvedCaller;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { SimAwsCallerResolver, } from "./sim-aws-caller-resolver.js";
|
|
2
|
+
/**
|
|
3
|
+
* State an already-resolved caller as the caller of another request.
|
|
4
|
+
*
|
|
5
|
+
* A resolver answers with a SimAwsResolvedCaller, and a service that goes on
|
|
6
|
+
* to ask IAM about the same caller has to pass one back in. Both principals
|
|
7
|
+
* travel together, so an assumed-role session keeps the Role its policies come
|
|
8
|
+
* from instead of arriving as a session ARN that owns none.
|
|
9
|
+
*/
|
|
10
|
+
export function simAwsCallerFor(caller) {
|
|
11
|
+
return {
|
|
12
|
+
kind: "resolved",
|
|
13
|
+
principal: caller.principal,
|
|
14
|
+
identityPolicyPrincipal: caller.identityPolicyPrincipal,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Resolve a principal that needs nothing authenticated.
|
|
19
|
+
*
|
|
20
|
+
* A service principal, or an ARN something else has already established, is
|
|
21
|
+
* its own answer. This is the short way to the SimAwsResolvedCaller that an
|
|
22
|
+
* authorization boundary asks for.
|
|
23
|
+
*/
|
|
24
|
+
export function simAwsResolvedCallerOf(principal) {
|
|
25
|
+
return new SimAwsCallerResolver().resolve(principal, principal);
|
|
26
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { BackgroundCompleter, BackgroundScheduler } from "../../../util/background/background.js";
|
|
2
2
|
import type { SimAwsAccountRegionContainer } from "../sim-aws-account-region-scope.js";
|
|
3
3
|
import type { SimAws } from "../sim-aws.js";
|
|
4
|
+
import type { SimAwsDefaultCaller } from "../caller/sim-aws-caller.js";
|
|
4
5
|
import { SimCloudFormation } from "../../cloudformation/index.js";
|
|
5
6
|
import { SimCloudWatch } from "../../cloudwatch/index.js";
|
|
6
7
|
import { SimCognitoIdentityProvider } from "../../cognito/index.js";
|
|
@@ -30,6 +31,10 @@ interface SimAwsAccountRegionServiceBuilderProperties {
|
|
|
30
31
|
readonly lambdaUrlRegistry: SimLambdaUrlRegistry;
|
|
31
32
|
readonly accountServices: SimAwsAccountServiceCache;
|
|
32
33
|
readonly messageLog: SimAwsMessageLog;
|
|
34
|
+
/**
|
|
35
|
+
* The caller this simulation attributes a request naming none to.
|
|
36
|
+
*/
|
|
37
|
+
readonly defaultCaller?: SimAwsDefaultCaller | undefined;
|
|
33
38
|
}
|
|
34
39
|
/**
|
|
35
40
|
* Builder for simulated AWS services scoped to one Account and Region.
|
|
@@ -61,6 +66,7 @@ export declare class SimAwsAccountRegionServiceBuilder {
|
|
|
61
66
|
private readonly lambdaUrlRegistry;
|
|
62
67
|
private readonly accountServices;
|
|
63
68
|
private readonly messageLog;
|
|
69
|
+
private readonly defaultCaller?;
|
|
64
70
|
constructor(properties: SimAwsAccountRegionServiceBuilderProperties);
|
|
65
71
|
/** Create simulated ACM for an Account Region scope. */
|
|
66
72
|
/** Create simulated CloudFormation for an Account Region scope. */
|
|
@@ -55,6 +55,7 @@ export class SimAwsAccountRegionServiceBuilder {
|
|
|
55
55
|
lambdaUrlRegistry;
|
|
56
56
|
accountServices;
|
|
57
57
|
messageLog;
|
|
58
|
+
defaultCaller;
|
|
58
59
|
constructor(properties) {
|
|
59
60
|
this.simAws = properties.simAws;
|
|
60
61
|
this.background = properties.background;
|
|
@@ -63,6 +64,7 @@ export class SimAwsAccountRegionServiceBuilder {
|
|
|
63
64
|
this.lambdaUrlRegistry = properties.lambdaUrlRegistry;
|
|
64
65
|
this.accountServices = properties.accountServices;
|
|
65
66
|
this.messageLog = properties.messageLog;
|
|
67
|
+
this.defaultCaller = properties.defaultCaller;
|
|
66
68
|
}
|
|
67
69
|
/** Create simulated ACM for an Account Region scope. */
|
|
68
70
|
/** Create simulated CloudFormation for an Account Region scope. */
|
|
@@ -269,6 +271,7 @@ export class SimAwsAccountRegionServiceBuilder {
|
|
|
269
271
|
accountRegionScope: scope.accountRegionScope,
|
|
270
272
|
background: this.background,
|
|
271
273
|
iamResolver: this.iamRegistry,
|
|
274
|
+
defaultCaller: this.defaultCaller,
|
|
272
275
|
});
|
|
273
276
|
}
|
|
274
277
|
/**
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { BackgroundCompleter, BackgroundScheduler } from "../../../util/background/background.js";
|
|
2
2
|
import type { SimAwsAccountRegionContainer } from "../sim-aws-account-region-scope.js";
|
|
3
3
|
import type { SimAws } from "../sim-aws.js";
|
|
4
|
+
import type { SimAwsDefaultCaller } from "../caller/sim-aws-caller.js";
|
|
4
5
|
import type { SimAcmRegistry } from "../../acm/registry/sim-acm-registry.js";
|
|
5
6
|
import type { SimCloudFrontRegistry } from "../../cloudfront/registry/sim-cloud-front-registry.js";
|
|
6
7
|
import { SimCloudFront } from "../../cloudfront/sim-cloudfront.js";
|
|
@@ -25,6 +26,10 @@ interface SimAwsAccountServiceCacheProperties {
|
|
|
25
26
|
readonly iamRegistry: SimIamRegistry;
|
|
26
27
|
readonly accessKeyRegistry: SimIamAccessKeyRegistry;
|
|
27
28
|
readonly scpResolver: SimIamServiceControlPolicyResolver;
|
|
29
|
+
/**
|
|
30
|
+
* The caller this simulation attributes a request naming none to.
|
|
31
|
+
*/
|
|
32
|
+
readonly defaultCaller?: SimAwsDefaultCaller | undefined;
|
|
28
33
|
}
|
|
29
34
|
/**
|
|
30
35
|
* Account-level cache for simulated AWS service instances.
|
|
@@ -55,6 +60,7 @@ export declare class SimAwsAccountServiceCache {
|
|
|
55
60
|
private readonly iamRegistry;
|
|
56
61
|
private readonly accessKeyRegistry;
|
|
57
62
|
private readonly scpResolver;
|
|
63
|
+
private readonly defaultCaller?;
|
|
58
64
|
private readonly route53Registry;
|
|
59
65
|
private readonly kmsRegistry;
|
|
60
66
|
private readonly serviceHosts;
|
|
@@ -38,6 +38,7 @@ export class SimAwsAccountServiceCache {
|
|
|
38
38
|
iamRegistry;
|
|
39
39
|
accessKeyRegistry;
|
|
40
40
|
scpResolver;
|
|
41
|
+
defaultCaller;
|
|
41
42
|
route53Registry;
|
|
42
43
|
kmsRegistry;
|
|
43
44
|
serviceHosts;
|
|
@@ -57,6 +58,7 @@ export class SimAwsAccountServiceCache {
|
|
|
57
58
|
this.cloudFrontRegistry = properties.cloudFrontRegistry;
|
|
58
59
|
this.iamRegistry = properties.iamRegistry;
|
|
59
60
|
this.scpResolver = properties.scpResolver;
|
|
61
|
+
this.defaultCaller = properties.defaultCaller;
|
|
60
62
|
this.accessKeyRegistry = properties.accessKeyRegistry;
|
|
61
63
|
this.route53Registry = properties.route53Registry;
|
|
62
64
|
this.kmsRegistry = properties.kmsRegistry;
|
|
@@ -114,6 +116,9 @@ export class SimAwsAccountServiceCache {
|
|
|
114
116
|
// What the Account's organization allows it to do is decided outside
|
|
115
117
|
// the Account, so IAM asks simulated Organizations about it.
|
|
116
118
|
scpResolver: this.scpResolver,
|
|
119
|
+
// Who a request naming no caller comes from is decided for the
|
|
120
|
+
// whole simulation. Every Account in it applies the same default.
|
|
121
|
+
defaultCaller: this.defaultCaller,
|
|
117
122
|
// Access keys are indexed simulation-wide as they are issued, so a
|
|
118
123
|
// signed request naming only a key id can be traced to this Account.
|
|
119
124
|
credentialRegistry: new SimIamCredentialRegistry({
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { BackgroundCompleter, BackgroundScheduler } from "../../../util/background/background.js";
|
|
2
2
|
import type { SimAwsAccountRegionContainer } from "../sim-aws-account-region-scope.js";
|
|
3
3
|
import type { SimAws } from "../sim-aws.js";
|
|
4
|
+
import type { SimAwsDefaultCaller } from "../caller/sim-aws-caller.js";
|
|
4
5
|
import type { SimAcm } from "../../acm/sim-acm.js";
|
|
5
6
|
import type { SimApiGateway } from "../../apigateway/index.js";
|
|
6
7
|
import type { SimApiGatewayV2 } from "../../apigatewayv2/index.js";
|
|
@@ -45,6 +46,10 @@ import { SimAwsMessageLog } from "../message/sim-aws-message-log.js";
|
|
|
45
46
|
interface SimAwsServiceFactoryProperties {
|
|
46
47
|
readonly simAws: SimAws;
|
|
47
48
|
readonly background: BackgroundScheduler & BackgroundCompleter;
|
|
49
|
+
/**
|
|
50
|
+
* The caller this simulation attributes a call naming none to.
|
|
51
|
+
*/
|
|
52
|
+
readonly defaultCaller?: SimAwsDefaultCaller | undefined;
|
|
48
53
|
}
|
|
49
54
|
/**
|
|
50
55
|
* Factory for simulated AWS services used by one SimAws instance.
|
|
@@ -104,10 +104,16 @@ export class SimAwsServiceFactory {
|
|
|
104
104
|
iamRegistry: this.iamRegistry,
|
|
105
105
|
accessKeyRegistry: this.requestAuth.accessKeyRegistry,
|
|
106
106
|
scpResolver: this.organizations,
|
|
107
|
+
// Simulated IAM applies this wherever a request names no caller of its
|
|
108
|
+
// own, in place of the Account root it would otherwise be decided as.
|
|
109
|
+
defaultCaller: properties.defaultCaller,
|
|
107
110
|
});
|
|
108
111
|
this.accountRegionServices = new SimAwsAccountRegionServiceBuilder({
|
|
109
112
|
simAws: properties.simAws,
|
|
110
113
|
background: properties.background,
|
|
114
|
+
// STS reports and evaluates the same default. An unattributed
|
|
115
|
+
// GetCallerIdentity answers with the principal everything else uses.
|
|
116
|
+
defaultCaller: properties.defaultCaller,
|
|
111
117
|
registries: this.registries,
|
|
112
118
|
iamRegistry: this.iamRegistry,
|
|
113
119
|
lambdaUrlRegistry: this.lambdaUrlRegistry,
|
|
@@ -2,6 +2,7 @@ import type { BackgroundCompleter, BackgroundScheduler } from "../../util/backgr
|
|
|
2
2
|
import type { SimClock } from "../../util/clock/sim-clock.js";
|
|
3
3
|
import type { SimIamSigV4ExpectedScope } from "../iam/sigv4/sim-iam-sigv4-expected-scope.js";
|
|
4
4
|
import type { SimAwsAccountId } from "./sim-aws-account.js";
|
|
5
|
+
import type { SimAwsDefaultCaller } from "./caller/sim-aws-caller.js";
|
|
5
6
|
import type { AwsRegionName } from "./sim-aws-region.js";
|
|
6
7
|
/**
|
|
7
8
|
* Everything caller resolution needs besides the request itself.
|
|
@@ -28,6 +29,20 @@ export interface SimAwsProperties {
|
|
|
28
29
|
*/
|
|
29
30
|
readonly defaultAccountId?: SimAwsAccountId | string;
|
|
30
31
|
readonly defaultRegionName?: AwsRegionName;
|
|
32
|
+
/**
|
|
33
|
+
* The principal this simulation attributes a call naming no caller to.
|
|
34
|
+
*
|
|
35
|
+
* Every simulated operation takes a `caller`, and one is set for a
|
|
36
|
+
* deployment through `deployTemplate` and `deployCdkOut`. This says who the
|
|
37
|
+
* calls that name none are, such as the role an operator reads the account
|
|
38
|
+
* through. An explicit caller always wins, as does the ambient caller of a
|
|
39
|
+
* `runAs` block.
|
|
40
|
+
*
|
|
41
|
+
* Left out, a call naming no caller is decided as the root principal of the
|
|
42
|
+
* Account it reaches. A service control policy denying that root then denies
|
|
43
|
+
* the call. That is the reason to name a default.
|
|
44
|
+
*/
|
|
45
|
+
readonly defaultCaller?: SimAwsDefaultCaller;
|
|
31
46
|
readonly background?: BackgroundScheduler & BackgroundCompleter;
|
|
32
47
|
/**
|
|
33
48
|
* Clock this simulation's timestamps start from, defaulting to the real
|
|
@@ -34,7 +34,7 @@ export class SimAws extends SimAwsServiceAccessors {
|
|
|
34
34
|
requestAuthentication;
|
|
35
35
|
constructor(properties = {}) {
|
|
36
36
|
super();
|
|
37
|
-
const { defaultAccountId = DEFAULT_SIM_AWS_ACCOUNT_ID, defaultRegionName = DEFAULT_SIM_AWS_REGION_NAME, clock, background: suppliedBackground, } = properties;
|
|
37
|
+
const { defaultAccountId = DEFAULT_SIM_AWS_ACCOUNT_ID, defaultRegionName = DEFAULT_SIM_AWS_REGION_NAME, clock, defaultCaller, background: suppliedBackground, } = properties;
|
|
38
38
|
const timekeeping = new SimAwsTimekeeping({
|
|
39
39
|
clock,
|
|
40
40
|
background: suppliedBackground,
|
|
@@ -47,6 +47,7 @@ export class SimAws extends SimAwsServiceAccessors {
|
|
|
47
47
|
this.serviceFactory = new SimAwsServiceFactory({
|
|
48
48
|
simAws: this,
|
|
49
49
|
background,
|
|
50
|
+
defaultCaller,
|
|
50
51
|
});
|
|
51
52
|
this.iamRegistry = this.serviceFactory.iamRegistry;
|
|
52
53
|
this.scopes = new SimAwsScopeRegistry({ simAws: this });
|
|
@@ -1,28 +1,51 @@
|
|
|
1
1
|
import { type SimAwsCredentialIdentityResolver, type SimAwsResolvedCaller } from "../../../aws/caller/sim-aws-caller-resolver.js";
|
|
2
|
-
import type { SimAwsCaller, SimAwsPrincipal } from "../../../aws/caller/sim-aws-caller.js";
|
|
2
|
+
import type { SimAwsCaller, SimAwsDefaultCaller, SimAwsPrincipal } from "../../../aws/caller/sim-aws-caller.js";
|
|
3
3
|
import type { SimIamAuthZPolicySource } from "./sim-iam-auth-z-context.js";
|
|
4
4
|
export interface SimIamAuthZCallerContext {
|
|
5
5
|
readonly caller: SimAwsResolvedCaller;
|
|
6
6
|
readonly rootPolicySources: readonly SimIamAuthZPolicySource[];
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* What building a caller context needs beyond the request's own caller.
|
|
10
|
+
*/
|
|
11
|
+
export interface SimIamAuthZCallerContextBuilderProperties {
|
|
12
|
+
/**
|
|
13
|
+
* The root principal of the Account deciding the request.
|
|
14
|
+
*
|
|
15
|
+
* This is both the last fallback for a request that names no caller and the
|
|
16
|
+
* principal holding the Account's intrinsic unrestricted access. The default
|
|
17
|
+
* caller stands apart from it. Naming a default says who an unattributed
|
|
18
|
+
* call comes from, and leaves the root's own access where AWS puts it.
|
|
19
|
+
*/
|
|
20
|
+
readonly accountRootPrincipal: SimAwsPrincipal;
|
|
21
|
+
readonly credentialIdentityResolver: SimAwsCredentialIdentityResolver;
|
|
22
|
+
/**
|
|
23
|
+
* The caller this simulation attributes an unattributed request to.
|
|
24
|
+
*/
|
|
25
|
+
readonly defaultCaller?: SimAwsDefaultCaller | undefined;
|
|
26
|
+
}
|
|
8
27
|
/**
|
|
9
28
|
* Resolves the caller and any policy sources implied by that caller.
|
|
10
29
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
30
|
+
* A request that omits a caller is decided as the simulation's default caller,
|
|
31
|
+
* and as the Account root where the simulation named none. An explicit
|
|
32
|
+
* anonymous caller falls back to neither.
|
|
14
33
|
*/
|
|
15
34
|
export declare class SimIamAuthZCallerContextBuilder {
|
|
16
35
|
private readonly callerResolver;
|
|
17
|
-
private readonly
|
|
18
|
-
|
|
36
|
+
private readonly accountRootPrincipal;
|
|
37
|
+
private readonly accountRootArn?;
|
|
38
|
+
constructor(properties: SimIamAuthZCallerContextBuilderProperties);
|
|
19
39
|
/**
|
|
20
40
|
* Resolve request caller data and add the simulated root policy when
|
|
21
41
|
* applicable.
|
|
22
42
|
*/
|
|
23
43
|
build(caller: SimAwsCaller | undefined): SimIamAuthZCallerContext;
|
|
24
44
|
/**
|
|
25
|
-
* Give the
|
|
45
|
+
* Give the Account's root principal unrestricted identity access.
|
|
46
|
+
*
|
|
47
|
+
* The comparison names the root principal explicitly, so a simulation with a
|
|
48
|
+
* default caller keeps this access on the root where AWS has it.
|
|
26
49
|
*/
|
|
27
50
|
private rootPolicySources;
|
|
28
51
|
}
|