diff --git a/docs/docs/04-standard-library/01-cloud/function.md b/docs/docs/04-standard-library/01-cloud/function.md
index 98f2315a6b2..968671f5d38 100644
--- a/docs/docs/04-standard-library/01-cloud/function.md
+++ b/docs/docs/04-standard-library/01-cloud/function.md
@@ -45,15 +45,35 @@ new cloud.Function(inflight () => {
### Simulator (`sim`)
-The sim implementation of `cloud.Function` uses JavaScript's function
+The sim implementation of `cloud.Function` runs the inflight code as a JavaScript function.
### AWS (`tf-aws` and `awscdk`)
-The AWS implementation of `cloud.Function` uses [Amazon Lambda](https://aws.amazon.com/lambda/).
+The AWS implementation of `cloud.Function` uses [AWS Lambda](https://aws.amazon.com/lambda/).
+
+To add extra IAM permissions to the function, you can use the `aws.Function` class as shown below.
+
+```ts playground
+bring aws;
+bring cloud;
+
+let f = new cloud.Function(inflight () => {
+ log("Hello world!");
+});
+if let lambdaFn = aws.Function.from(f) {
+ lambdaFn.addPolicyStatements(
+ aws.PolicyStatement {
+ actions: ["ses:sendEmail"],
+ effect: aws.Effect.ALLOW,
+ resources: ["*"],
+ },
+ );
+}
+```
### Azure (`tf-azure`)
-The Azure implementation of `cloud.Function` uses [Azure Function](https://azure.microsoft.com/en-us/products/function).
+The Azure implementation of `cloud.Function` uses [Azure Functions](https://azure.microsoft.com/en-us/products/functions).
🚧 `invoke` API is not supported yet (tracking issue: [#1371](https://github.com/winglang/wing/issues/1371))
diff --git a/docs/docs/04-standard-library/05-aws/api-reference.md b/docs/docs/04-standard-library/05-aws/api-reference.md
index ea8e592f8f9..77132e95adb 100644
--- a/docs/docs/04-standard-library/05-aws/api-reference.md
+++ b/docs/docs/04-standard-library/05-aws/api-reference.md
@@ -160,17 +160,14 @@ Add an environment variable to the function.
##### `addPolicyStatements`
```wing
-addPolicyStatements(policies: MutArray): void
+addPolicyStatements(...policies: Array): void
```
Add policy statements to the function's IAM role.
-TODO: update this to accept a variadic parameter (...policies)
-https://github.com/winglang/wing/issues/397
-
###### `policies`Required
-- *Type:* MutArray<PolicyStatement>
+- *Type:* PolicyStatement
---
diff --git a/examples/tests/valid/dynamo.main.w b/examples/tests/valid/dynamo.main.w
index 62e4b2d8e4b..97f89cb4479 100644
--- a/examples/tests/valid/dynamo.main.w
+++ b/examples/tests/valid/dynamo.main.w
@@ -45,11 +45,11 @@ class DynamoTable {
pub bind(host: std.IInflightHost, ops: Array) {
if let host = aws.Function.from(host) {
if ops.contains("putItem") {
- host.addPolicyStatements([aws.PolicyStatement {
+ host.addPolicyStatements(aws.PolicyStatement {
actions: ["dynamodb:PutItem"],
resources: [this.table.arn],
effect: aws.Effect.ALLOW,
- }]);
+ });
}
}
}
diff --git a/examples/tests/valid/dynamo_awscdk.main.w b/examples/tests/valid/dynamo_awscdk.main.w
index 5be0801c0e9..8a77d436c6c 100644
--- a/examples/tests/valid/dynamo_awscdk.main.w
+++ b/examples/tests/valid/dynamo_awscdk.main.w
@@ -43,19 +43,19 @@ class DynamoTable {
pub bind(host: std.IInflightHost, ops: Array) {
if let host = aws.Function.from(host) {
if ops.contains("putItem") {
- host.addPolicyStatements([aws.PolicyStatement {
+ host.addPolicyStatements(aws.PolicyStatement {
actions: ["dynamodb:PutItem"],
resources: [this.table.tableArn],
effect: aws.Effect.ALLOW,
- }]);
+ });
}
if ops.contains("getItem") {
- host.addPolicyStatements([aws.PolicyStatement {
+ host.addPolicyStatements(aws.PolicyStatement {
actions: ["dynamodb:GetItem"],
resources: [this.table.tableArn],
effect: aws.Effect.ALLOW,
- }]);
+ });
}
}
}
diff --git a/libs/wingsdk/src/cloud/function.md b/libs/wingsdk/src/cloud/function.md
index 6313711cc4f..813412f6b75 100644
--- a/libs/wingsdk/src/cloud/function.md
+++ b/libs/wingsdk/src/cloud/function.md
@@ -45,15 +45,35 @@ new cloud.Function(inflight () => {
### Simulator (`sim`)
-The sim implementation of `cloud.Function` uses JavaScript's function
+The sim implementation of `cloud.Function` runs the inflight code as a JavaScript function.
### AWS (`tf-aws` and `awscdk`)
-The AWS implementation of `cloud.Function` uses [Amazon Lambda](https://aws.amazon.com/lambda/).
+The AWS implementation of `cloud.Function` uses [AWS Lambda](https://aws.amazon.com/lambda/).
+
+To add extra IAM permissions to the function, you can use the `aws.Function` class as shown below.
+
+```ts playground
+bring aws;
+bring cloud;
+
+let f = new cloud.Function(inflight () => {
+ log("Hello world!");
+});
+if let lambdaFn = aws.Function.from(f) {
+ lambdaFn.addPolicyStatements(
+ aws.PolicyStatement {
+ actions: ["ses:sendEmail"],
+ effect: aws.Effect.ALLOW,
+ resources: ["*"],
+ },
+ );
+}
+```
### Azure (`tf-azure`)
-The Azure implementation of `cloud.Function` uses [Azure Function](https://azure.microsoft.com/en-us/products/function).
+The Azure implementation of `cloud.Function` uses [Azure Functions](https://azure.microsoft.com/en-us/products/functions).
🚧 `invoke` API is not supported yet (tracking issue: [#1371](https://github.com/winglang/wing/issues/1371))
diff --git a/libs/wingsdk/src/shared-aws/function.ts b/libs/wingsdk/src/shared-aws/function.ts
index 773df3ebad8..20bc0759cc6 100644
--- a/libs/wingsdk/src/shared-aws/function.ts
+++ b/libs/wingsdk/src/shared-aws/function.ts
@@ -12,11 +12,8 @@ export interface IAwsFunction {
/**
* Add policy statements to the function's IAM role.
- *
- * TODO: update this to accept a variadic parameter (...policies)
- * https://github.com/winglang/wing/issues/397
*/
- addPolicyStatements(policies: PolicyStatement[]): void;
+ addPolicyStatements(...policies: PolicyStatement[]): void;
}
/**
diff --git a/libs/wingsdk/src/target-awscdk/bucket.ts b/libs/wingsdk/src/target-awscdk/bucket.ts
index f27430fba47..77598b91d92 100644
--- a/libs/wingsdk/src/target-awscdk/bucket.ts
+++ b/libs/wingsdk/src/target-awscdk/bucket.ts
@@ -186,7 +186,7 @@ export class Bucket extends cloud.Bucket {
}
host.addPolicyStatements(
- calculateBucketPermissions(this.bucket.bucketArn, ops)
+ ...calculateBucketPermissions(this.bucket.bucketArn, ops)
);
// The bucket name needs to be passed through an environment variable since
diff --git a/libs/wingsdk/src/target-awscdk/counter.ts b/libs/wingsdk/src/target-awscdk/counter.ts
index d75a2533a44..88e57a77b4f 100644
--- a/libs/wingsdk/src/target-awscdk/counter.ts
+++ b/libs/wingsdk/src/target-awscdk/counter.ts
@@ -32,7 +32,7 @@ export class Counter extends cloud.Counter {
}
host.addPolicyStatements(
- calculateCounterPermissions(this.table.tableArn, ops)
+ ...calculateCounterPermissions(this.table.tableArn, ops)
);
host.addEnvironment(this.envName(), this.table.tableName);
diff --git a/libs/wingsdk/src/target-awscdk/function.ts b/libs/wingsdk/src/target-awscdk/function.ts
index 1b0d2358295..16212930faf 100644
--- a/libs/wingsdk/src/target-awscdk/function.ts
+++ b/libs/wingsdk/src/target-awscdk/function.ts
@@ -57,12 +57,10 @@ export class Function extends cloud.Function implements IAwsFunction {
}
if (ops.includes(cloud.FunctionInflightMethods.INVOKE)) {
- host.addPolicyStatements([
- {
- actions: ["lambda:InvokeFunction"],
- resources: [`${this.function.functionArn}`],
- },
- ]);
+ host.addPolicyStatements({
+ actions: ["lambda:InvokeFunction"],
+ resources: [`${this.function.functionArn}`],
+ });
}
// The function name needs to be passed through an environment variable since
@@ -97,7 +95,7 @@ export class Function extends cloud.Function implements IAwsFunction {
/**
* Add a policy statement to the Lambda role.
*/
- public addPolicyStatements(statements: PolicyStatement[]) {
+ public addPolicyStatements(...statements: PolicyStatement[]) {
for (const statement of statements) {
this.function.addToRolePolicy(new CdkPolicyStatement(statement));
}
diff --git a/libs/wingsdk/src/target-awscdk/queue.ts b/libs/wingsdk/src/target-awscdk/queue.ts
index fd4636cb5fc..e9c6e37b137 100644
--- a/libs/wingsdk/src/target-awscdk/queue.ts
+++ b/libs/wingsdk/src/target-awscdk/queue.ts
@@ -81,7 +81,7 @@ export class Queue extends cloud.Queue {
const env = this.envName();
host.addPolicyStatements(
- calculateQueuePermissions(this.queue.queueArn, ops)
+ ...calculateQueuePermissions(this.queue.queueArn, ops)
);
// The queue url needs to be passed through an environment variable since
diff --git a/libs/wingsdk/src/target-awscdk/secret.ts b/libs/wingsdk/src/target-awscdk/secret.ts
index 16471526138..927b3579375 100644
--- a/libs/wingsdk/src/target-awscdk/secret.ts
+++ b/libs/wingsdk/src/target-awscdk/secret.ts
@@ -47,7 +47,7 @@ export class Secret extends cloud.Secret {
}
host.addPolicyStatements(
- calculateSecretPermissions(this.arnForPolicies, ops)
+ ...calculateSecretPermissions(this.arnForPolicies, ops)
);
host.addEnvironment(this.envName(), this.secret.secretArn);
diff --git a/libs/wingsdk/src/target-awscdk/topic.ts b/libs/wingsdk/src/target-awscdk/topic.ts
index 435dad4a5b6..b56b5d61d1c 100644
--- a/libs/wingsdk/src/target-awscdk/topic.ts
+++ b/libs/wingsdk/src/target-awscdk/topic.ts
@@ -75,7 +75,7 @@ export class Topic extends cloud.Topic {
}
host.addPolicyStatements(
- calculateTopicPermissions(this.topic.topicArn, ops)
+ ...calculateTopicPermissions(this.topic.topicArn, ops)
);
host.addEnvironment(this.envName(), this.topic.topicArn);
diff --git a/libs/wingsdk/src/target-tf-aws/bucket.ts b/libs/wingsdk/src/target-tf-aws/bucket.ts
index e08c6eb47ad..fb966f619ae 100644
--- a/libs/wingsdk/src/target-tf-aws/bucket.ts
+++ b/libs/wingsdk/src/target-tf-aws/bucket.ts
@@ -113,7 +113,9 @@ export class Bucket extends cloud.Bucket {
throw new Error("buckets can only be bound by tfaws.Function for now");
}
- host.addPolicyStatements(calculateBucketPermissions(this.bucket.arn, ops));
+ host.addPolicyStatements(
+ ...calculateBucketPermissions(this.bucket.arn, ops)
+ );
// The bucket name needs to be passed through an environment variable since
// it may not be resolved until deployment time.
diff --git a/libs/wingsdk/src/target-tf-aws/counter.ts b/libs/wingsdk/src/target-tf-aws/counter.ts
index 8e88f15bdb7..6ed9c21e36d 100644
--- a/libs/wingsdk/src/target-tf-aws/counter.ts
+++ b/libs/wingsdk/src/target-tf-aws/counter.ts
@@ -42,7 +42,9 @@ export class Counter extends cloud.Counter {
throw new Error("counters can only be bound by tfaws.Function for now");
}
- host.addPolicyStatements(calculateCounterPermissions(this.table.arn, ops));
+ host.addPolicyStatements(
+ ...calculateCounterPermissions(this.table.arn, ops)
+ );
host.addEnvironment(this.envName(), this.table.name);
diff --git a/libs/wingsdk/src/target-tf-aws/function.ts b/libs/wingsdk/src/target-tf-aws/function.ts
index f097174c3e3..94319a1bdad 100644
--- a/libs/wingsdk/src/target-tf-aws/function.ts
+++ b/libs/wingsdk/src/target-tf-aws/function.ts
@@ -229,12 +229,10 @@ export class Function extends cloud.Function implements IAwsFunction {
}
if (ops.includes(cloud.FunctionInflightMethods.INVOKE)) {
- host.addPolicyStatements([
- {
- actions: ["lambda:InvokeFunction"],
- resources: [`${this.function.arn}`],
- },
- ]);
+ host.addPolicyStatements({
+ actions: ["lambda:InvokeFunction"],
+ resources: [`${this.function.arn}`],
+ });
}
// The function name needs to be passed through an environment variable since
@@ -269,7 +267,7 @@ export class Function extends cloud.Function implements IAwsFunction {
/**
* Add a policy statement to the Lambda role.
*/
- public addPolicyStatements(statements: PolicyStatement[]) {
+ public addPolicyStatements(...statements: PolicyStatement[]) {
// we do lazy initialization here because addPolicyStatements() might be called through the
// constructor chain of the Function base class which means that our constructor might not have
// been called yet... yes, ugly.
diff --git a/libs/wingsdk/src/target-tf-aws/queue.ts b/libs/wingsdk/src/target-tf-aws/queue.ts
index a547e88645b..df9c5cf8aa0 100644
--- a/libs/wingsdk/src/target-tf-aws/queue.ts
+++ b/libs/wingsdk/src/target-tf-aws/queue.ts
@@ -65,18 +65,16 @@ export class Queue extends cloud.Queue {
throw new Error("Queue only supports creating tfaws.Function right now");
}
- fn.addPolicyStatements([
- {
- actions: [
- "sqs:ReceiveMessage",
- "sqs:ChangeMessageVisibility",
- "sqs:GetQueueUrl",
- "sqs:DeleteMessage",
- "sqs:GetQueueAttributes",
- ],
- resources: [this.queue.arn],
- },
- ]);
+ fn.addPolicyStatements({
+ actions: [
+ "sqs:ReceiveMessage",
+ "sqs:ChangeMessageVisibility",
+ "sqs:GetQueueUrl",
+ "sqs:DeleteMessage",
+ "sqs:GetQueueAttributes",
+ ],
+ resources: [this.queue.arn],
+ });
new LambdaEventSourceMapping(this, "EventSourceMapping", {
functionName: fn._functionName,
@@ -100,7 +98,7 @@ export class Queue extends cloud.Queue {
const env = this.envName();
- host.addPolicyStatements(calculateQueuePermissions(this.queue.arn, ops));
+ host.addPolicyStatements(...calculateQueuePermissions(this.queue.arn, ops));
// The queue url needs to be passed through an environment variable since
// it may not be resolved until deployment time.
diff --git a/libs/wingsdk/src/target-tf-aws/redis.ts b/libs/wingsdk/src/target-tf-aws/redis.ts
index 34f2ede9471..1f2a57e6ead 100644
--- a/libs/wingsdk/src/target-tf-aws/redis.ts
+++ b/libs/wingsdk/src/target-tf-aws/redis.ts
@@ -102,12 +102,10 @@ export class Redis extends ex.Redis {
// Ops do not matter here since the client connects directly to the cluster.
// The only thing that we need to use AWS API for is to get the cluster endpoint
// from the cluster ID.
- host.addPolicyStatements([
- {
- actions: ["elasticache:Describe*"],
- resources: [this.clusterArn],
- },
- ]);
+ host.addPolicyStatements({
+ actions: ["elasticache:Describe*"],
+ resources: [this.clusterArn],
+ });
host.addEnvironment(env, this.clusterId);
host.addNetworkConfig({
diff --git a/libs/wingsdk/src/target-tf-aws/secret.ts b/libs/wingsdk/src/target-tf-aws/secret.ts
index 0a204800fb6..604f72589fd 100644
--- a/libs/wingsdk/src/target-tf-aws/secret.ts
+++ b/libs/wingsdk/src/target-tf-aws/secret.ts
@@ -54,7 +54,9 @@ export class Secret extends cloud.Secret {
throw new Error("secrets can only be bound by tfaws.Function for now");
}
- host.addPolicyStatements(calculateSecretPermissions(this.secret.arn, ops));
+ host.addPolicyStatements(
+ ...calculateSecretPermissions(this.secret.arn, ops)
+ );
host.addEnvironment(this.envName(), this.secret.arn);
diff --git a/libs/wingsdk/src/target-tf-aws/table.ts b/libs/wingsdk/src/target-tf-aws/table.ts
index ba37fb13e8f..1b64fb03fd7 100644
--- a/libs/wingsdk/src/target-tf-aws/table.ts
+++ b/libs/wingsdk/src/target-tf-aws/table.ts
@@ -60,47 +60,37 @@ export class Table extends ex.Table {
ops.includes(ex.TableInflightMethods.INSERT) ||
ops.includes(ex.TableInflightMethods.UPSERT)
) {
- host.addPolicyStatements([
- {
- actions: ["dynamodb:PutItem"],
- resources: [this.table.arn],
- },
- ]);
+ host.addPolicyStatements({
+ actions: ["dynamodb:PutItem"],
+ resources: [this.table.arn],
+ });
}
if (ops.includes(ex.TableInflightMethods.UPDATE)) {
- host.addPolicyStatements([
- {
- actions: ["dynamodb:UpdateItem"],
- resources: [this.table.arn],
- },
- ]);
+ host.addPolicyStatements({
+ actions: ["dynamodb:UpdateItem"],
+ resources: [this.table.arn],
+ });
}
if (ops.includes(ex.TableInflightMethods.DELETE)) {
- host.addPolicyStatements([
- {
- actions: ["dynamodb:DeleteItem"],
- resources: [this.table.arn],
- },
- ]);
+ host.addPolicyStatements({
+ actions: ["dynamodb:DeleteItem"],
+ resources: [this.table.arn],
+ });
}
if (ops.includes(ex.TableInflightMethods.GET)) {
- host.addPolicyStatements([
- {
- actions: ["dynamodb:GetItem"],
- resources: [this.table.arn],
- },
- ]);
+ host.addPolicyStatements({
+ actions: ["dynamodb:GetItem"],
+ resources: [this.table.arn],
+ });
}
if (ops.includes(ex.TableInflightMethods.LIST)) {
- host.addPolicyStatements([
- {
- actions: ["dynamodb:Scan"],
- resources: [this.table.arn],
- },
- ]);
+ host.addPolicyStatements({
+ actions: ["dynamodb:Scan"],
+ resources: [this.table.arn],
+ });
}
host.addEnvironment(this.envName(), this.table.name);
diff --git a/libs/wingsdk/src/target-tf-aws/topic.ts b/libs/wingsdk/src/target-tf-aws/topic.ts
index 5948bcf882d..742718587dc 100644
--- a/libs/wingsdk/src/target-tf-aws/topic.ts
+++ b/libs/wingsdk/src/target-tf-aws/topic.ts
@@ -139,7 +139,7 @@ export class Topic extends cloud.Topic {
throw new Error("topics can only be bound by tfaws.Function for now");
}
- host.addPolicyStatements(calculateTopicPermissions(this.topic.arn, ops));
+ host.addPolicyStatements(...calculateTopicPermissions(this.topic.arn, ops));
host.addEnvironment(this.envName(), this.topic.arn);