@@ -9,7 +9,8 @@ import { GuStack } from "../constructs/core";
99import { GuLambdaFunction } from "../constructs/lambda" ;
1010import { GuEc2AppExperimental } from "../experimental/patterns/ec2-app" ;
1111import { GuEc2App , GuNodeApp , GuPlayApp , GuScheduledLambda } from "../patterns" ;
12- import { RiffRaffYamlFile } from "./index" ;
12+ import { UnknownRiffRaffProjectName } from "./types" ;
13+ import { RiffRaffYamlFile , validateRiffRaffYamlDirectory } from "./index" ;
1314
1415describe ( "The RiffRaffYamlFile class" , ( ) => {
1516 it ( "Should support deploying different GuStacks to multiple AWS accounts (aka Riff-Raff stacks), and regions" , ( ) => {
@@ -1110,7 +1111,7 @@ describe("The RiffRaffYamlFile class", () => {
11101111
11111112 const riffraff = new RiffRaffYamlFile ( app ) ;
11121113
1113- riffraff . riffRaffYaml . deployments . set ( "upload-my-static-files" , {
1114+ riffraff . configuration . get ( UnknownRiffRaffProjectName ) ? .deployments . set ( "upload-my-static-files" , {
11141115 app : "my-static-site" ,
11151116 contentDirectory : "my-static-site" ,
11161117 parameters : {
@@ -2008,5 +2009,157 @@ describe("The RiffRaffYamlFile class", () => {
20082009 new RiffRaffYamlFile ( app ) ;
20092010 } ) . toThrow ( "Unable to produce a working riff-raff.yaml file; missing 2 definitions" ) ;
20102011 } ) ;
2012+
2013+ it ( "should generate multiple configurations" , ( ) => {
2014+ const app = new App ( { outdir : "/tmp/cdk.out" } ) ;
2015+
2016+ class MyCoreInfraStack extends GuStack { }
2017+ class MyApplicationStack extends GuStack { }
2018+
2019+ new MyCoreInfraStack ( app , "MyCoreInfra" , {
2020+ stack : "deploy" ,
2021+ stage : "INFRA" ,
2022+ env : { region : "eu-west-1" } ,
2023+ riffRaffProjectName : "deploy::core-infra" ,
2024+ } ) ;
2025+
2026+ new MyApplicationStack ( app , "MyApp-CODE" , {
2027+ stack : "deploy" ,
2028+ stage : "CODE" ,
2029+ env : { region : "eu-west-1" } ,
2030+ riffRaffProjectName : "deploy::my-app" ,
2031+ } ) ;
2032+
2033+ new MyApplicationStack ( app , "MyApp-PROD" , {
2034+ stack : "deploy" ,
2035+ stage : "PROD" ,
2036+ env : { region : "eu-west-1" } ,
2037+ riffRaffProjectName : "deploy::my-app" ,
2038+ } ) ;
2039+
2040+ const riffraff = new RiffRaffYamlFile ( app ) ;
2041+
2042+ expect ( Array . from ( riffraff . configuration . keys ( ) ) ) . toEqual ( [ "deploy::core-infra" , "deploy::my-app" ] ) ;
2043+
2044+ expect ( riffraff . toYAML ( "deploy::core-infra" ) ) . toMatchInlineSnapshot ( `
2045+ "allowedStages:
2046+ - INFRA
2047+ deployments:
2048+ cfn-eu-west-1-deploy-my-core-infra-stack:
2049+ type: cloud-formation
2050+ regions:
2051+ - eu-west-1
2052+ stacks:
2053+ - deploy
2054+ app: my-core-infra-stack
2055+ contentDirectory: /tmp/cdk.out
2056+ parameters:
2057+ templateStagePaths:
2058+ INFRA: MyCoreInfra.template.json
2059+ "
2060+ ` ) ;
2061+ expect ( riffraff . toYAML ( "deploy::my-app" ) ) . toMatchInlineSnapshot ( `
2062+ "allowedStages:
2063+ - CODE
2064+ - PROD
2065+ deployments:
2066+ cfn-eu-west-1-deploy-my-application-stack:
2067+ type: cloud-formation
2068+ regions:
2069+ - eu-west-1
2070+ stacks:
2071+ - deploy
2072+ app: my-application-stack
2073+ contentDirectory: /tmp/cdk.out
2074+ parameters:
2075+ templateStagePaths:
2076+ CODE: MyApp-CODE.template.json
2077+ PROD: MyApp-PROD.template.json
2078+ "
2079+ ` ) ;
2080+ } ) ;
2081+
2082+ it ( "should throw when generating multiple configurations and there are missing definitions" , ( ) => {
2083+ const app = new App ( { outdir : "/tmp/cdk.out" } ) ;
2084+
2085+ class MyCoreInfraStack extends GuStack { }
2086+ class MyApplicationStack extends GuStack { }
2087+ class MyDatabaseStack extends GuStack { }
2088+
2089+ new MyCoreInfraStack ( app , "MyCoreInfra" , {
2090+ stack : "deploy" ,
2091+ stage : "INFRA" ,
2092+ env : { region : "eu-west-1" } ,
2093+ riffRaffProjectName : "deploy::core-infra" ,
2094+ } ) ;
2095+
2096+ new MyApplicationStack ( app , "MyApp-CODE" , {
2097+ stack : "deploy" ,
2098+ stage : "CODE" ,
2099+ env : { region : "eu-west-1" } ,
2100+ riffRaffProjectName : "deploy::my-app" ,
2101+ } ) ;
2102+
2103+ new MyApplicationStack ( app , "MyApp-PROD" , {
2104+ stack : "deploy" ,
2105+ stage : "PROD" ,
2106+ env : { region : "eu-west-1" } ,
2107+ riffRaffProjectName : "deploy::my-app" ,
2108+ } ) ;
2109+
2110+ new MyDatabaseStack ( app , "MyDatabase-PROD" , {
2111+ stack : "deploy" ,
2112+ stage : "PROD" ,
2113+ env : { region : "eu-west-1" } ,
2114+ riffRaffProjectName : "deploy::my-app" ,
2115+ } ) ;
2116+
2117+ expect ( ( ) => {
2118+ new RiffRaffYamlFile ( app ) ;
2119+ } ) . toThrow ( "Unable to produce a working riff-raff.yaml file; missing 1 definitions" ) ;
2120+ } ) ;
2121+ } ) ;
2122+ } ) ;
2123+
2124+ describe ( "The validateRiffRaffYamlDirectory function" , ( ) => {
2125+ it ( "accepts a child directory" , ( ) => {
2126+ const actual = validateRiffRaffYamlDirectory ( "/tmp/cdk.out" , "playground::my-project" ) ;
2127+ expect ( actual ) . toBe ( "/tmp/cdk.out/playground::my-project" ) ;
2128+ } ) ;
2129+
2130+ it ( "accepts a grand-child directory" , ( ) => {
2131+ const actual = validateRiffRaffYamlDirectory ( "/tmp/cdk.out" , "playground/my-project" ) ;
2132+ expect ( actual ) . toBe ( "/tmp/cdk.out/playground/my-project" ) ;
2133+ } ) ;
2134+
2135+ it ( "accepts the empty string" , ( ) => {
2136+ const actual = validateRiffRaffYamlDirectory ( "/tmp/cdk.out" , "" ) ;
2137+ expect ( actual ) . toBe ( "/tmp/cdk.out" ) ;
2138+ } ) ;
2139+
2140+ it ( "accepts a .. directory name" , ( ) => {
2141+ const actual = validateRiffRaffYamlDirectory ( "/tmp/cdk.out" , "..final" ) ;
2142+ expect ( actual ) . toBe ( "/tmp/cdk.out/..final" ) ;
2143+ } ) ;
2144+
2145+ it ( "rejects a parent directory" , ( ) => {
2146+ expect ( ( ) => {
2147+ validateRiffRaffYamlDirectory ( "/tmp/cdk.out" , "../playground::my-project" ) ;
2148+ } ) . toThrow (
2149+ "Directory traversal detected: '../playground::my-project' would create a directory outside of /tmp/cdk.out (riffRaffProjectName=../playground::my-project, resolvedPath='/tmp/playground::my-project', resolvedBase='/tmp/cdk.out')" ,
2150+ ) ;
2151+ } ) ;
2152+
2153+ it ( "accepts an ancestor directory" , ( ) => {
2154+ const actual = validateRiffRaffYamlDirectory ( "/tmp/cdk.out" , "child/../final" ) ;
2155+ expect ( actual ) . toBe ( "/tmp/cdk.out/final" ) ;
2156+ } ) ;
2157+
2158+ it ( "rejects a multi-ancestor directory" , ( ) => {
2159+ expect ( ( ) => {
2160+ validateRiffRaffYamlDirectory ( "/tmp/cdk.out" , "child/../somewhere/../../final" ) ;
2161+ } ) . toThrow (
2162+ "Directory traversal detected: 'child/../somewhere/../../final' would create a directory outside of /tmp/cdk.out (riffRaffProjectName=child/../somewhere/../../final, resolvedPath='/tmp/final', resolvedBase='/tmp/cdk.out')" ,
2163+ ) ;
20112164 } ) ;
20122165} ) ;
0 commit comments