@@ -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,11 +1501,20 @@ 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' , ( ) => {
1515+ const hello = 'hello.txt' ;
1516+ const world = 'world.txt' ;
14971517 const testBucket = 'test-bucket' ;
1498- const testKey = 'test-key' ;
14991518
15001519 const genStateMachine = ( id , lambdaArn , bucket , key ) => ( {
15011520 id,
@@ -1517,8 +1536,8 @@ describe('#compileIamRole', () => {
15171536 ItemReader : {
15181537 Resource : 'arn:aws:states:::s3:getObject' ,
15191538 Parameters : {
1520- ' Bucket.$' : bucket ,
1521- ' Key.$' : key ,
1539+ Bucket : bucket ,
1540+ Key : key ,
15221541 } ,
15231542 } ,
15241543 End : true ,
@@ -1530,9 +1549,9 @@ describe('#compileIamRole', () => {
15301549 serverless . service . stepFunctions = {
15311550 stateMachines : {
15321551 myStateMachine1 : genStateMachine ( 'StateMachine1' ,
1533- 'arn:aws:lambda:us-west-2:1234567890:function:foo' , '$. testBucket' , '$.testKey' ) ,
1552+ 'arn:aws:lambda:us-west-2:1234567890:function:foo' , testBucket , hello ) ,
15341553 myStateMachine2 : genStateMachine ( 'StateMachine2' ,
1535- 'arn:aws:lambda:us-west-2:1234567890:function:foo' , testBucket , testKey ) ,
1554+ 'arn:aws:lambda:us-west-2:1234567890:function:foo' , testBucket , world ) ,
15361555 } ,
15371556 } ;
15381557
@@ -1541,10 +1560,207 @@ describe('#compileIamRole', () => {
15411560 . provider . compiledCloudFormationTemplate . Resources ;
15421561 const policy1 = resources . StateMachine1Role . Properties . Policies [ 0 ] ;
15431562 const policy2 = resources . StateMachine2Role . Properties . Policies [ 0 ] ;
1563+ expect ( policy1 . PolicyDocument . Statement [ 1 ] . Resource )
1564+ . to . be . deep . equal ( [ `arn:aws:s3:::${ testBucket } /${ hello } ` ] ) ;
1565+ expect ( policy2 . PolicyDocument . Statement [ 1 ] . Resource )
1566+ . to . be . deep . equal ( [ `arn:aws:s3:::${ testBucket } /${ world } ` ] ) ;
1567+ } ) ;
1568+
1569+ it ( 'should give s3:GetObject permission to * when Bucket.$ and Key.$ are seen on ItemReader' , ( ) => {
1570+ const genStateMachine = ( id , lambdaArn ) => ( {
1571+ id,
1572+ definition : {
1573+ StartAt : 'A' ,
1574+ States : {
1575+ A : {
1576+ Type : 'Map' ,
1577+ ItemProcessor : {
1578+ StartAt : 'B' ,
1579+ States : {
1580+ B : {
1581+ Type : 'Task' ,
1582+ Resource : lambdaArn ,
1583+ End : true ,
1584+ } ,
1585+ } ,
1586+ } ,
1587+ ItemReader : {
1588+ Resource : 'arn:aws:states:::s3:getObject' ,
1589+ Parameters : {
1590+ Bucket : 'test-bucket' ,
1591+ Key : 'test-key' ,
1592+ } ,
1593+ } ,
1594+ Next : 'C' ,
1595+ } ,
1596+ C : {
1597+ Type : 'Map' ,
1598+ ItemProcessor : {
1599+ StartAt : 'D' ,
1600+ States : {
1601+ D : {
1602+ Type : 'Task' ,
1603+ Resource : lambdaArn ,
1604+ End : true ,
1605+ } ,
1606+ } ,
1607+ } ,
1608+ ItemReader : {
1609+ Resource : 'arn:aws:states:::s3:getObject' ,
1610+ Parameters : {
1611+ 'Bucket.$' : '$.testBucket' ,
1612+ 'Key.$' : '$.key' ,
1613+ } ,
1614+ } ,
1615+ End : true ,
1616+ } ,
1617+ } ,
1618+ } ,
1619+ } ) ;
1620+
1621+ serverless . service . stepFunctions = {
1622+ stateMachines : {
1623+ myStateMachine1 : genStateMachine ( 'StateMachine1' ,
1624+ 'arn:aws:lambda:us-west-2:1234567890:function:foo' ) ,
1625+ } ,
1626+ } ;
1627+
1628+ serverlessStepFunctions . compileIamRole ( ) ;
1629+ const resources = serverlessStepFunctions . serverless . service
1630+ . provider . compiledCloudFormationTemplate . Resources ;
1631+ const policy1 = resources . StateMachine1Role . Properties . Policies [ 0 ] ;
1632+
1633+ // even though some tasks target specific values, other states use Bucket.$
1634+ // and Key.$ so we need to give broad permissions to be able to get any
1635+ // bucket and key the input specifies
15441636 expect ( policy1 . PolicyDocument . Statement [ 1 ] . Resource )
15451637 . 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 } /*` ] ) ;
15461691 expect ( policy2 . PolicyDocument . Statement [ 1 ] . Resource )
1547- . to . be . deep . equal ( [ `arn:aws:s3:::${ testBucket } /${ testKey } ` ] ) ;
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
1762+ expect ( policy1 . PolicyDocument . Statement [ 1 ] . Resource )
1763+ . to . be . deep . equal ( '*' ) ;
15481764 } ) ;
15491765
15501766 it ( 'should not generate any permissions for Task states not yet supported' , ( ) => {
0 commit comments