Skip to content

Commit ceaf54a

Browse files
authored
fix(codepipeline-actions): correctly serialize the userParameters passed to the Lambda invoke Action. (#2537)
BREAKING CHANGE: removed the `addPutJobResultPolicy` property when creating LambdaInvokeAction.
1 parent 0f553ee commit ceaf54a

File tree

3 files changed

+143
-35
lines changed

3 files changed

+143
-35
lines changed

packages/@aws-cdk/aws-codepipeline-actions/lib/lambda/invoke-action.ts

+14-33
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ export interface LambdaInvokeActionProps extends codepipeline.CommonActionProps
2020
*/
2121
readonly inputs?: codepipeline.Artifact[];
2222

23-
// tslint:enable:max-line-length
24-
2523
/**
2624
* The optional names of the output Artifacts of the Action.
2725
* A Lambda Action can have up to 5 outputs.
@@ -34,30 +32,14 @@ export interface LambdaInvokeActionProps extends codepipeline.CommonActionProps
3432
readonly outputs?: codepipeline.Artifact[];
3533

3634
/**
37-
* String to be used in the event data parameter passed to the Lambda
38-
* function
39-
*
40-
* See an example JSON event in the CodePipeline documentation.
35+
* A set of key-value pairs that will be accessible to the invoked Lambda
36+
* inside the event that the Pipeline will call it with.
4137
*
42-
* https://docs.aws.amazon.com/codepipeline/latest/userguide/actions-invoke-lambda-function.html#actions-invoke-lambda-function-json-event-example
38+
* @see https://docs.aws.amazon.com/codepipeline/latest/userguide/actions-invoke-lambda-function.html#actions-invoke-lambda-function-json-event-example
4339
*/
44-
readonly userParameters?: any;
40+
readonly userParameters?: { [key: string]: any };
4541

46-
/**
47-
* Adds the "codepipeline:PutJobSuccessResult" and
48-
* "codepipeline:PutJobFailureResult" for '*' resource to the Lambda
49-
* execution role policy.
50-
*
51-
* NOTE: the reason we can't add the specific pipeline ARN as a resource is
52-
* to avoid a cyclic dependency between the pipeline and the Lambda function
53-
* (the pipeline references) the Lambda and the Lambda needs permissions on
54-
* the pipeline.
55-
*
56-
* @see https://docs.aws.amazon.com/codepipeline/latest/userguide/actions-invoke-lambda-function.html#actions-invoke-lambda-function-create-function
57-
*
58-
* @default true
59-
*/
60-
readonly addPutJobResultPolicy?: boolean;
42+
// tslint:enable:max-line-length
6143

6244
/**
6345
* The lambda function to invoke.
@@ -86,8 +68,8 @@ export class LambdaInvokeAction extends codepipeline.Action {
8668
},
8769
configuration: {
8870
FunctionName: props.lambda.functionName,
89-
UserParameters: props.userParameters
90-
}
71+
UserParameters: props.lambda.node.stringifyJson(props.userParameters),
72+
},
9173
});
9274

9375
this.props = props;
@@ -104,13 +86,12 @@ export class LambdaInvokeAction extends codepipeline.Action {
10486
.addAction('lambda:InvokeFunction')
10587
.addResource(this.props.lambda.functionArn));
10688

107-
// allow lambda to put job results for this pipeline.
108-
const addToPolicy = this.props.addPutJobResultPolicy !== undefined ? this.props.addPutJobResultPolicy : true;
109-
if (addToPolicy) {
110-
this.props.lambda.addToRolePolicy(new iam.PolicyStatement()
111-
.addAllResources() // to avoid cycles (see docs)
112-
.addAction('codepipeline:PutJobSuccessResult')
113-
.addAction('codepipeline:PutJobFailureResult'));
114-
}
89+
// allow lambda to put job results for this pipeline
90+
// CodePipeline requires this to be granted to '*'
91+
// (the Pipeline ARN will not be enough)
92+
this.props.lambda.addToRolePolicy(new iam.PolicyStatement()
93+
.addAllResources()
94+
.addAction('codepipeline:PutJobSuccessResult')
95+
.addAction('codepipeline:PutJobFailureResult'));
11596
}
11697
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import { expect, haveResourceLike } from "@aws-cdk/assert";
2+
import codepipeline = require('@aws-cdk/aws-codepipeline');
3+
import lambda = require('@aws-cdk/aws-lambda');
4+
import { Aws, SecretValue, Stack, Token } from "@aws-cdk/cdk";
5+
import { Test } from 'nodeunit';
6+
import cpactions = require('../../lib');
7+
8+
// tslint:disable:object-literal-key-quotes
9+
10+
export = {
11+
'Lambda invoke Action': {
12+
'properly serializes the object passed in userParameters'(test: Test) {
13+
const stack = stackIncludingLambdaInvokeCodePipeline({
14+
key: 1234,
15+
});
16+
17+
expect(stack).to(haveResourceLike('AWS::CodePipeline::Pipeline', {
18+
'Stages': [
19+
{},
20+
{
21+
'Actions': [
22+
{
23+
'Configuration': {
24+
'UserParameters': '{"key":1234}',
25+
},
26+
},
27+
],
28+
},
29+
],
30+
}));
31+
32+
test.done();
33+
},
34+
35+
'properly resolves any Tokens passed in userParameters'(test: Test) {
36+
const stack = stackIncludingLambdaInvokeCodePipeline({
37+
key: new Token(() => Aws.region),
38+
});
39+
40+
expect(stack).to(haveResourceLike('AWS::CodePipeline::Pipeline', {
41+
'Stages': [
42+
{},
43+
{
44+
'Actions': [
45+
{
46+
'Configuration': {
47+
'UserParameters': {
48+
'Fn::Join': [
49+
'',
50+
[
51+
'{"key":"',
52+
{
53+
'Ref': 'AWS::Region',
54+
},
55+
'"}',
56+
],
57+
],
58+
},
59+
},
60+
},
61+
],
62+
},
63+
],
64+
}));
65+
66+
test.done();
67+
},
68+
69+
'properly resolves any stringified Tokens passed in userParameters'(test: Test) {
70+
const stack = stackIncludingLambdaInvokeCodePipeline({
71+
key: new Token(() => null).toString(),
72+
});
73+
74+
expect(stack).to(haveResourceLike('AWS::CodePipeline::Pipeline', {
75+
'Stages': [
76+
{},
77+
{
78+
'Actions': [
79+
{
80+
'Configuration': {
81+
'UserParameters': '{"key":null}',
82+
},
83+
},
84+
],
85+
},
86+
],
87+
}));
88+
89+
test.done();
90+
},
91+
},
92+
};
93+
94+
function stackIncludingLambdaInvokeCodePipeline(userParams: { [key: string]: any }) {
95+
const stack = new Stack();
96+
97+
new codepipeline.Pipeline(stack, 'Pipeline', {
98+
stages: [
99+
{
100+
name: 'Source',
101+
actions: [
102+
new cpactions.GitHubSourceAction({
103+
actionName: 'GitHub',
104+
output: new codepipeline.Artifact(),
105+
oauthToken: SecretValue.plainText('secret'),
106+
owner: 'awslabs',
107+
repo: 'aws-cdk',
108+
}),
109+
],
110+
},
111+
{
112+
name: 'Invoke',
113+
actions: [
114+
new cpactions.LambdaInvokeAction({
115+
actionName: 'Lambda',
116+
lambda: new lambda.Function(stack, 'Lambda', {
117+
code: lambda.Code.cfnParameters(),
118+
handler: 'index.handler',
119+
runtime: lambda.Runtime.NodeJS810,
120+
}),
121+
userParameters: userParams,
122+
}),
123+
],
124+
},
125+
],
126+
});
127+
128+
return stack;
129+
}

packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts

-2
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,6 @@ export = {
464464
const lambdaAction = new cpactions.LambdaInvokeAction({
465465
actionName: 'InvokeAction',
466466
lambda: lambdaFun,
467-
userParameters: 'foo-bar/42',
468467
inputs: [
469468
source2Output,
470469
source1Output,
@@ -510,7 +509,6 @@ export = {
510509
"FunctionName": {
511510
"Ref": "Function76856677"
512511
},
513-
"UserParameters": "foo-bar/42"
514512
},
515513
"InputArtifacts": [
516514
{ "Name": "sourceArtifact2" },

0 commit comments

Comments
 (0)