@@ -2148,6 +2148,289 @@ describe('#compileIamRole', () => {
2148
2148
. to . be . deep . equal ( '*' ) ;
2149
2149
} ) ;
2150
2150
2151
+ // Start
2152
+
2153
+ it ( 'should resolve literal bucket names in S3 permissions' , ( ) => {
2154
+ const literalBucket = 'my-test-bucket' ;
2155
+ const literalKey = 'test-key.txt' ;
2156
+
2157
+ serverless . service . stepFunctions = {
2158
+ stateMachines : {
2159
+ myStateMachine1 : {
2160
+ id : 'StateMachine1' ,
2161
+ definition : {
2162
+ StartAt : 'A' ,
2163
+ States : {
2164
+ A : {
2165
+ Type : 'Task' ,
2166
+ Resource : 'arn:aws:states:::aws-sdk:s3:getObject' ,
2167
+ Parameters : {
2168
+ Bucket : literalBucket ,
2169
+ Key : literalKey ,
2170
+ } ,
2171
+ End : true ,
2172
+ } ,
2173
+ } ,
2174
+ } ,
2175
+ } ,
2176
+ } ,
2177
+ } ;
2178
+
2179
+ serverlessStepFunctions . compileIamRole ( ) ;
2180
+ const statements = serverlessStepFunctions . serverless . service . provider
2181
+ . compiledCloudFormationTemplate . Resources . StateMachine1Role . Properties . Policies [ 0 ]
2182
+ . PolicyDocument . Statement ;
2183
+
2184
+ expect ( statements [ 0 ] . Resource [ 0 ] ) . to . equal ( `arn:aws:s3:::${ literalBucket } /${ literalKey } ` ) ;
2185
+ } ) ;
2186
+
2187
+ it ( 'should resolve CloudFormation reference buckets in S3 permissions' , ( ) => {
2188
+ const bucketRef = { Ref : 'MyS3Bucket' } ;
2189
+
2190
+ serverless . service . stepFunctions = {
2191
+ stateMachines : {
2192
+ myStateMachine1 : {
2193
+ id : 'StateMachine1' ,
2194
+ definition : {
2195
+ StartAt : 'A' ,
2196
+ States : {
2197
+ A : {
2198
+ Type : 'Task' ,
2199
+ Resource : 'arn:aws:states:::aws-sdk:s3:getObject' ,
2200
+ Parameters : {
2201
+ Bucket : bucketRef ,
2202
+ Key : 'test-key.txt' ,
2203
+ } ,
2204
+ End : true ,
2205
+ } ,
2206
+ } ,
2207
+ } ,
2208
+ } ,
2209
+ } ,
2210
+ } ;
2211
+
2212
+ serverlessStepFunctions . compileIamRole ( ) ;
2213
+ const statements = serverlessStepFunctions . serverless . service . provider
2214
+ . compiledCloudFormationTemplate . Resources . StateMachine1Role . Properties . Policies [ 0 ]
2215
+ . PolicyDocument . Statement ;
2216
+
2217
+ expect ( statements [ 0 ] . Resource [ 0 ] ) . to . deep . equal ( {
2218
+ 'Fn::Sub' : [
2219
+ 'arn:aws:s3:::${bucket}/test-key.txt' ,
2220
+ { bucket : bucketRef } ,
2221
+ ] ,
2222
+ } ) ;
2223
+ } ) ;
2224
+
2225
+ it ( 'should resolve Fn::GetAtt bucket references in S3 permissions' , ( ) => {
2226
+ const bucketRef = { 'Fn::GetAtt' : [ 'MyS3Bucket' , 'Arn' ] } ;
2227
+
2228
+ serverless . service . stepFunctions = {
2229
+ stateMachines : {
2230
+ myStateMachine1 : {
2231
+ id : 'StateMachine1' ,
2232
+ definition : {
2233
+ StartAt : 'A' ,
2234
+ States : {
2235
+ A : {
2236
+ Type : 'Task' ,
2237
+ Resource : 'arn:aws:states:::aws-sdk:s3:putObject' ,
2238
+ Parameters : {
2239
+ Bucket : bucketRef ,
2240
+ Key : 'output.json' ,
2241
+ Body : { result : 'success' } ,
2242
+ } ,
2243
+ End : true ,
2244
+ } ,
2245
+ } ,
2246
+ } ,
2247
+ } ,
2248
+ } ,
2249
+ } ;
2250
+
2251
+ serverlessStepFunctions . compileIamRole ( ) ;
2252
+ const statements = serverlessStepFunctions . serverless . service . provider
2253
+ . compiledCloudFormationTemplate . Resources . StateMachine1Role . Properties . Policies [ 0 ]
2254
+ . PolicyDocument . Statement ;
2255
+
2256
+ expect ( statements [ 0 ] . Resource [ 0 ] ) . to . deep . equal ( {
2257
+ 'Fn::Sub' : [
2258
+ 'arn:aws:s3:::${bucket}/output.json' ,
2259
+ { bucket : bucketRef } ,
2260
+ ] ,
2261
+ } ) ;
2262
+ } ) ;
2263
+
2264
+ it ( 'should resolve bucket references in S3 listObjectsV2 permissions' , ( ) => {
2265
+ const bucketRef = { Ref : 'MyS3Bucket' } ;
2266
+
2267
+ serverless . service . stepFunctions = {
2268
+ stateMachines : {
2269
+ myStateMachine1 : {
2270
+ id : 'StateMachine1' ,
2271
+ definition : {
2272
+ StartAt : 'A' ,
2273
+ States : {
2274
+ A : {
2275
+ Type : 'Map' ,
2276
+ ItemProcessor : {
2277
+ ProcessorConfig : {
2278
+ Mode : 'DISTRIBUTED' ,
2279
+ } ,
2280
+ } ,
2281
+ StartAt : 'B' ,
2282
+ States : {
2283
+ B : {
2284
+ Type : 'Task' ,
2285
+ Resource : 'arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:hello' ,
2286
+ End : true ,
2287
+ } ,
2288
+ } ,
2289
+ ItemReader : {
2290
+ Resource : 'arn:aws:states:::s3:listObjectsV2' ,
2291
+ Parameters : {
2292
+ Bucket : bucketRef ,
2293
+ Prefix : 'data' ,
2294
+ } ,
2295
+ } ,
2296
+ End : true ,
2297
+ } ,
2298
+ } ,
2299
+ } ,
2300
+ } ,
2301
+ } ,
2302
+ } ;
2303
+
2304
+ serverlessStepFunctions . compileIamRole ( ) ;
2305
+ const statements = serverlessStepFunctions . serverless . service . provider
2306
+ . compiledCloudFormationTemplate . Resources . StateMachine1Role . Properties . Policies [ 0 ]
2307
+ . PolicyDocument . Statement ;
2308
+
2309
+ expect ( statements [ 3 ] . Resource [ 0 ] ) . to . deep . equal ( {
2310
+ 'Fn::Sub' : [
2311
+ 'arn:aws:s3:::${bucket}' ,
2312
+ { bucket : bucketRef } ,
2313
+ ] ,
2314
+ } ) ;
2315
+ expect ( statements [ 3 ] . Resource [ 1 ] ) . to . deep . equal ( {
2316
+ 'Fn::Sub' : [
2317
+ 'arn:aws:s3:::${bucket}/*' ,
2318
+ { bucket : bucketRef } ,
2319
+ ] ,
2320
+ } ) ;
2321
+ } ) ;
2322
+
2323
+ it ( 'should handle mixed literal and reference buckets correctly' , ( ) => {
2324
+ const literalBucket = 'literal-bucket' ;
2325
+ const bucketRef = { Ref : 'ReferenceBucket' } ;
2326
+ const literalFile = 'file1.txt' ;
2327
+
2328
+ serverless . service . stepFunctions = {
2329
+ stateMachines : {
2330
+ myStateMachine1 : {
2331
+ id : 'StateMachine1' ,
2332
+ definition : {
2333
+ StartAt : 'A' ,
2334
+ States : {
2335
+ A : {
2336
+ Type : 'Task' ,
2337
+ Resource : 'arn:aws:states:::aws-sdk:s3:getObject' ,
2338
+ Parameters : {
2339
+ Bucket : literalBucket ,
2340
+ Key : literalFile ,
2341
+ } ,
2342
+ Next : 'B' ,
2343
+ } ,
2344
+ B : {
2345
+ Type : 'Task' ,
2346
+ Resource : 'arn:aws:states:::aws-sdk:s3:putObject' ,
2347
+ Parameters : {
2348
+ Bucket : bucketRef ,
2349
+ Key : 'file2.txt' ,
2350
+ Body : { } ,
2351
+ } ,
2352
+ End : true ,
2353
+ } ,
2354
+ } ,
2355
+ } ,
2356
+ } ,
2357
+ } ,
2358
+ } ;
2359
+
2360
+ serverlessStepFunctions . compileIamRole ( ) ;
2361
+ const statements = serverlessStepFunctions . serverless . service . provider
2362
+ . compiledCloudFormationTemplate . Resources . StateMachine1Role . Properties . Policies [ 0 ]
2363
+ . PolicyDocument . Statement ;
2364
+
2365
+ // Check that we have consolidated permissions
2366
+ expect ( statements ) . to . have . lengthOf ( 2 ) ;
2367
+
2368
+ // First statement for s3:GetObject with literal bucket
2369
+ expect ( statements [ 0 ] . Action ) . to . deep . equal ( [ 's3:GetObject' ] ) ;
2370
+ expect ( statements [ 0 ] . Resource [ 0 ] ) . to . equal ( `arn:aws:s3:::${ literalBucket } /${ literalFile } ` ) ;
2371
+
2372
+ // Second statement for s3:PutObject with reference bucket
2373
+ expect ( statements [ 1 ] . Action ) . to . deep . equal ( [ 's3:PutObject' ] ) ;
2374
+ expect ( statements [ 1 ] . Resource [ 0 ] ) . to . deep . equal ( {
2375
+ 'Fn::Sub' : [
2376
+ 'arn:aws:s3:::${bucket}/file2.txt' ,
2377
+ { bucket : bucketRef } ,
2378
+ ] ,
2379
+ } ) ;
2380
+ } ) ;
2381
+
2382
+ it ( 'should handle bucket references with prefixes correctly' , ( ) => {
2383
+ const bucketRef = { Ref : 'MyS3Bucket' } ;
2384
+
2385
+ serverless . service . stepFunctions = {
2386
+ stateMachines : {
2387
+ myStateMachine1 : {
2388
+ id : 'StateMachine1' ,
2389
+ definition : {
2390
+ StartAt : 'A' ,
2391
+ States : {
2392
+ A : {
2393
+ Type : 'Map' ,
2394
+ ItemProcessor : {
2395
+ StartAt : 'B' ,
2396
+ States : {
2397
+ B : {
2398
+ Type : 'Task' ,
2399
+ Resource : 'arn:aws:lambda:us-west-2:1234567890:function:foo' ,
2400
+ End : true ,
2401
+ } ,
2402
+ } ,
2403
+ } ,
2404
+ ResultWriter : {
2405
+ Resource : 'arn:aws:states:::s3:putObject' ,
2406
+ Parameters : {
2407
+ Bucket : bucketRef ,
2408
+ Prefix : 'results' ,
2409
+ } ,
2410
+ } ,
2411
+ End : true ,
2412
+ } ,
2413
+ } ,
2414
+ } ,
2415
+ } ,
2416
+ } ,
2417
+ } ;
2418
+
2419
+ serverlessStepFunctions . compileIamRole ( ) ;
2420
+ const statements = serverlessStepFunctions . serverless . service . provider
2421
+ . compiledCloudFormationTemplate . Resources . StateMachine1Role . Properties . Policies [ 0 ]
2422
+ . PolicyDocument . Statement ;
2423
+
2424
+ expect ( statements [ 1 ] . Resource [ 0 ] ) . to . deep . equal ( {
2425
+ 'Fn::Sub' : [
2426
+ 'arn:aws:s3:::${bucket}/results/*' ,
2427
+ { bucket : bucketRef } ,
2428
+ ] ,
2429
+ } ) ;
2430
+ } ) ;
2431
+
2432
+ // End
2433
+
2151
2434
it ( 'should not generate any permissions for Task states not yet supported' , ( ) => {
2152
2435
const genStateMachine = id => ( {
2153
2436
id,
0 commit comments