@@ -1452,7 +1452,7 @@ describe('#compileIamRole', () => {
14521452 expectDenyAllPolicy ( policy ) ;
14531453 } ) ;
14541454
1455- it ( 'should give s3:GetObject permission for only objects referenced by state machine' , ( ) => {
1455+ it ( 'should give s3 permissions for only objects referenced by state machine' , ( ) => {
14561456 const hello = 'hello.txt' ;
14571457 const world = 'world.txt' ;
14581458 const testBucket = 'test-bucket' ;
@@ -1469,6 +1469,16 @@ describe('#compileIamRole', () => {
14691469 Bucket : bucket ,
14701470 Key : key ,
14711471 } ,
1472+ Next : 'B' ,
1473+ } ,
1474+ B : {
1475+ Type : 'Task' ,
1476+ Resource : 'arn:aws:states:::aws-sdk:s3:putObject' ,
1477+ Parameters : {
1478+ Bucket : bucket ,
1479+ Key : key ,
1480+ Body : { } ,
1481+ } ,
14721482 End : true ,
14731483 } ,
14741484 } ,
@@ -1491,6 +1501,14 @@ describe('#compileIamRole', () => {
14911501 . to . be . deep . equal ( [ `arn:aws:s3:::${ testBucket } /${ hello } ` ] ) ;
14921502 expect ( policy2 . PolicyDocument . Statement [ 0 ] . Resource )
14931503 . to . be . deep . equal ( [ `arn:aws:s3:::${ testBucket } /${ world } ` ] ) ;
1504+
1505+ [ policy1 , policy2 ] . forEach ( ( policy ) => {
1506+ expect ( policy . PolicyDocument . Statement [ 0 ] . Action )
1507+ . to . be . deep . equal ( [
1508+ 's3:GetObject' ,
1509+ 's3:PutObject' ,
1510+ ] ) ;
1511+ } ) ;
14941512 } ) ;
14951513
14961514 it ( 'should give s3:GetObject permission for only objects referenced by state machine with ItemReader' , ( ) => {
@@ -1612,9 +1630,135 @@ describe('#compileIamRole', () => {
16121630 . provider . compiledCloudFormationTemplate . Resources ;
16131631 const policy1 = resources . StateMachine1Role . Properties . Policies [ 0 ] ;
16141632
1615- // even though some tasks target specific topic ARNs , other states use Bucket.$
1633+ // even though some tasks target specific values , other states use Bucket.$
16161634 // and Key.$ so we need to give broad permissions to be able to get any
1617- // table and key the input specifies
1635+ // bucket and key the input specifies
1636+ expect ( policy1 . PolicyDocument . Statement [ 1 ] . Resource )
1637+ . to . be . deep . equal ( '*' ) ;
1638+ } ) ;
1639+
1640+ it ( 'should give s3:PutObject permission for only objects referenced by state machine with ResultWriter' , ( ) => {
1641+ const hello = 'hello' ;
1642+ const world = 'world' ;
1643+ const testBucket = 'test-bucket' ;
1644+
1645+ const genStateMachine = ( id , lambdaArn , bucket , prefix ) => ( {
1646+ id,
1647+ definition : {
1648+ StartAt : 'A' ,
1649+ States : {
1650+ A : {
1651+ Type : 'Map' ,
1652+ ItemProcessor : {
1653+ StartAt : 'B' ,
1654+ States : {
1655+ B : {
1656+ Type : 'Task' ,
1657+ Resource : lambdaArn ,
1658+ End : true ,
1659+ } ,
1660+ } ,
1661+ } ,
1662+ ResultWriter : {
1663+ Resource : 'arn:aws:states:::s3:putObject' ,
1664+ Parameters : {
1665+ Bucket : bucket ,
1666+ Prefix : prefix ,
1667+ } ,
1668+ } ,
1669+ End : true ,
1670+ } ,
1671+ } ,
1672+ } ,
1673+ } ) ;
1674+
1675+ serverless . service . stepFunctions = {
1676+ stateMachines : {
1677+ myStateMachine1 : genStateMachine ( 'StateMachine1' ,
1678+ 'arn:aws:lambda:us-west-2:1234567890:function:foo' , testBucket , hello ) ,
1679+ myStateMachine2 : genStateMachine ( 'StateMachine2' ,
1680+ 'arn:aws:lambda:us-west-2:1234567890:function:foo' , testBucket , world ) ,
1681+ } ,
1682+ } ;
1683+
1684+ serverlessStepFunctions . compileIamRole ( ) ;
1685+ const resources = serverlessStepFunctions . serverless . service
1686+ . provider . compiledCloudFormationTemplate . Resources ;
1687+ const policy1 = resources . StateMachine1Role . Properties . Policies [ 0 ] ;
1688+ const policy2 = resources . StateMachine2Role . Properties . Policies [ 0 ] ;
1689+ expect ( policy1 . PolicyDocument . Statement [ 1 ] . Resource )
1690+ . to . be . deep . equal ( [ `arn:aws:s3:::${ testBucket } /${ hello } /*` ] ) ;
1691+ expect ( policy2 . PolicyDocument . Statement [ 1 ] . Resource )
1692+ . to . be . deep . equal ( [ `arn:aws:s3:::${ testBucket } /${ world } /*` ] ) ;
1693+ } ) ;
1694+
1695+ it ( 'should give s3:PutObject permission to * when Bucket.$ and Prefix.$ are seen on ResultWriter' , ( ) => {
1696+ const genStateMachine = ( id , lambdaArn ) => ( {
1697+ id,
1698+ definition : {
1699+ StartAt : 'A' ,
1700+ States : {
1701+ A : {
1702+ Type : 'Map' ,
1703+ ItemProcessor : {
1704+ StartAt : 'B' ,
1705+ States : {
1706+ B : {
1707+ Type : 'Task' ,
1708+ Resource : lambdaArn ,
1709+ End : true ,
1710+ } ,
1711+ } ,
1712+ } ,
1713+ ResultWriter : {
1714+ Resource : 'arn:aws:states:::s3:putObject' ,
1715+ Parameters : {
1716+ Bucket : 'test-bucket' ,
1717+ Prefix : 'test-prefix' ,
1718+ } ,
1719+ } ,
1720+ Next : 'C' ,
1721+ } ,
1722+ C : {
1723+ Type : 'Map' ,
1724+ ItemProcessor : {
1725+ StartAt : 'D' ,
1726+ States : {
1727+ D : {
1728+ Type : 'Task' ,
1729+ Resource : lambdaArn ,
1730+ End : true ,
1731+ } ,
1732+ } ,
1733+ } ,
1734+ ResultWriter : {
1735+ Resource : 'arn:aws:states:::s3:putObject' ,
1736+ Parameters : {
1737+ 'Bucket.$' : '$.testBucket' ,
1738+ 'Prefix.$' : '$.prefix' ,
1739+ } ,
1740+ } ,
1741+ End : true ,
1742+ } ,
1743+ } ,
1744+ } ,
1745+ } ) ;
1746+
1747+ serverless . service . stepFunctions = {
1748+ stateMachines : {
1749+ myStateMachine1 : genStateMachine ( 'StateMachine1' ,
1750+ 'arn:aws:lambda:us-west-2:1234567890:function:foo' ) ,
1751+ } ,
1752+ } ;
1753+
1754+ serverlessStepFunctions . compileIamRole ( ) ;
1755+ const resources = serverlessStepFunctions . serverless . service
1756+ . provider . compiledCloudFormationTemplate . Resources ;
1757+ const policy1 = resources . StateMachine1Role . Properties . Policies [ 0 ] ;
1758+
1759+ // even though some tasks target specific values, other states use Bucket.$
1760+ // and Prefix.$ so we need to give broad permissions to be able to write to
1761+ // any bucket and prefix the input specifies
16181762 expect ( policy1 . PolicyDocument . Statement [ 1 ] . Resource )
16191763 . to . be . deep . equal ( '*' ) ;
16201764 } ) ;
0 commit comments