Skip to content

Commit

Permalink
fix(sdk)!: change addPolicyStatements to take variadic parameter (#4190)
Browse files Browse the repository at this point in the history
Resolves a small TODO we had in our SDK that we had from prior to the language having variadics. I also added some docs about how to use `aws.Function`.

BREAKING CHANGE: The parameter to `addPolicyStatements` on `aws.Function` is now variadic, so instead of calling `addPolicyStatements([policy1, policy2])` you must omit the array brackets, calling `addPolicyStatements(policy1, policy2)`.

## Checklist

- [x] Title matches [Winglang's style guide](https://www.winglang.io/contributing/start-here/pull_requests#how-are-pull-request-titles-formatted)
- [x] Description explains motivation and solution
- [x] Tests added (always)
- [x] Docs updated (only required for features)
- [ ] Added `pr/e2e-full` label if this feature requires end-to-end testing

*By submitting this pull request, I confirm that my contribution is made under the terms of the [Wing Cloud Contribution License](https://github.com/winglang/wing/blob/main/CONTRIBUTION_LICENSE.md)*.
  • Loading branch information
Chriscbr authored Sep 15, 2023
1 parent 3f09a3e commit 430ec75
Show file tree
Hide file tree
Showing 20 changed files with 115 additions and 93 deletions.
26 changes: 23 additions & 3 deletions docs/docs/04-standard-library/01-cloud/function.md
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down
7 changes: 2 additions & 5 deletions docs/docs/04-standard-library/05-aws/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,17 +160,14 @@ Add an environment variable to the function.
##### `addPolicyStatements` <a name="addPolicyStatements" id="@winglang/sdk.aws.IAwsFunction.addPolicyStatements"></a>

```wing
addPolicyStatements(policies: MutArray<PolicyStatement>): void
addPolicyStatements(...policies: Array<PolicyStatement>): 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`<sup>Required</sup> <a name="policies" id="@winglang/sdk.aws.IAwsFunction.addPolicyStatements.parameter.policies"></a>

- *Type:* MutArray&lt;<a href="#@winglang/sdk.aws.PolicyStatement">PolicyStatement</a>&gt;
- *Type:* <a href="#@winglang/sdk.aws.PolicyStatement">PolicyStatement</a>

---

Expand Down
4 changes: 2 additions & 2 deletions examples/tests/valid/dynamo.main.w
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ class DynamoTable {
pub bind(host: std.IInflightHost, ops: Array<str>) {
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,
}]);
});
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions examples/tests/valid/dynamo_awscdk.main.w
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,19 @@ class DynamoTable {
pub bind(host: std.IInflightHost, ops: Array<str>) {
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,
}]);
});
}
}
}
Expand Down
26 changes: 23 additions & 3 deletions libs/wingsdk/src/cloud/function.md
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down
5 changes: 1 addition & 4 deletions libs/wingsdk/src/shared-aws/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion libs/wingsdk/src/target-awscdk/bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion libs/wingsdk/src/target-awscdk/counter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
12 changes: 5 additions & 7 deletions libs/wingsdk/src/target-awscdk/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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));
}
Expand Down
2 changes: 1 addition & 1 deletion libs/wingsdk/src/target-awscdk/queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion libs/wingsdk/src/target-awscdk/secret.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion libs/wingsdk/src/target-awscdk/topic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 3 additions & 1 deletion libs/wingsdk/src/target-tf-aws/bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 3 additions & 1 deletion libs/wingsdk/src/target-tf-aws/counter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
12 changes: 5 additions & 7 deletions libs/wingsdk/src/target-tf-aws/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
24 changes: 11 additions & 13 deletions libs/wingsdk/src/target-tf-aws/queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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.
Expand Down
10 changes: 4 additions & 6 deletions libs/wingsdk/src/target-tf-aws/redis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down
4 changes: 3 additions & 1 deletion libs/wingsdk/src/target-tf-aws/secret.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
Loading

0 comments on commit 430ec75

Please sign in to comment.