├── cft ├── cft_test.go ├── pkg │ ├── test.txt │ ├── tmpl │ │ ├── lambda-src │ │ │ └── handler.py │ │ ├── .gitignore │ │ ├── embed.txt │ │ ├── awscli-modules │ │ │ ├── badref-expect.yaml │ │ │ ├── insertfile-file.yaml │ │ │ ├── sub │ │ │ │ ├── subsub.yaml │ │ │ │ └── modinmod-submodule.yaml │ │ │ ├── zip-module.yaml │ │ │ ├── zip-expect.yaml │ │ │ ├── conditional-module2.yaml │ │ │ ├── badref-template.yaml │ │ │ ├── depends-template.yaml │ │ │ ├── transform-module.yaml │ │ │ ├── package.zip │ │ │ ├── depends-module.yaml │ │ │ ├── transform-expect.yaml │ │ │ ├── depends-expect.yaml │ │ │ ├── transform-template.yaml │ │ │ ├── insertfile-expect.yaml │ │ │ ├── proparray-expect.yaml │ │ │ ├── zip-template.yaml │ │ │ ├── proparray-template.yaml │ │ │ ├── insertfile-template.yaml │ │ │ ├── select-template.yaml │ │ │ ├── badref-module.yaml │ │ │ ├── default-module.yaml │ │ │ ├── constant-template.yaml │ │ │ ├── select-expect.yaml │ │ │ ├── example-expect.yaml │ │ │ ├── mergetags-template.yaml │ │ │ ├── cond-intrinsics-expect.yaml │ │ │ ├── proparray-module.yaml │ │ │ ├── cond-unres-template.yaml │ │ │ ├── output-module2.yaml │ │ │ ├── default-expect.yaml │ │ │ ├── default-template.yaml │ │ │ ├── same-mod-submod.yaml │ │ │ ├── map-list-module.yaml │ │ │ ├── cond-conflict-template.yaml │ │ │ ├── map-output-module.yaml │ │ │ ├── mergetags-expect.yaml │ │ │ ├── example-template.yaml │ │ │ ├── foreach-module.yaml │ │ │ ├── cond-intrinsics-template.yaml │ │ │ ├── example-module.yaml │ │ │ ├── modinmod-template.yaml │ │ │ ├── vpc-template.yaml │ │ │ ├── sub-template.yaml │ │ │ ├── invoke-module-b.yaml │ │ │ ├── cond-unres-submodule.yaml │ │ │ ├── map-module.yaml │ │ │ ├── getatt-module.yaml │ │ │ ├── select-module.yaml │ │ │ ├── merge-expect.yaml │ │ │ ├── modinmod-submodule.yaml │ │ │ ├── map-index-module.yaml │ │ │ ├── outjoin-template.yaml │ │ │ ├── outsublist-template.yaml │ │ │ ├── type-template.yaml │ │ │ ├── same-mod-template.yaml │ │ │ ├── merge-template.yaml │ │ │ ├── same-mod-module.yaml │ │ │ ├── conditional-template.yaml │ │ │ ├── constant-expect.yaml │ │ │ ├── mergetags-module.yaml │ │ │ ├── getatt-template.yaml │ │ │ ├── basic-template.yaml │ │ │ ├── type-module.yaml │ │ │ ├── getatt-expect.yaml │ │ │ ├── policy-template.yaml │ │ │ ├── constant-module.yaml │ │ │ ├── outsublist-module.yaml │ │ │ ├── outjoin-expect.yaml │ │ │ ├── modinmod-module.yaml │ │ │ ├── outsublist-expect.yaml │ │ │ ├── type-expect.yaml │ │ │ ├── basic-module.yaml │ │ │ ├── merge-module.yaml │ │ │ ├── outjoin-module.yaml │ │ │ ├── policy-expect.yaml │ │ │ ├── basic-expect.yaml │ │ │ ├── policy-module.yaml │ │ │ ├── s3-template.yaml │ │ │ ├── sub-expect.yaml │ │ │ ├── foreach-template.yaml │ │ │ ├── sub-module.yaml │ │ │ ├── same-mod-expect.yaml │ │ │ ├── invoke-expect.yaml │ │ │ ├── foreach-expect.yaml │ │ │ ├── modinmod-expect.yaml │ │ │ ├── mapout-template.yaml │ │ │ ├── output-module.yaml │ │ │ ├── cond-unres-module.yaml │ │ │ ├── url-template.yaml │ │ │ ├── cond-unres-expect.yaml │ │ │ ├── cond-intrinsics-module.yaml │ │ │ ├── map-template.yaml │ │ │ ├── invoke-template.yaml │ │ │ └── output-template.yaml │ │ ├── s3.txt │ │ ├── s3http.txt │ │ ├── alias-module.yaml │ │ ├── alias-expect.yaml │ │ ├── pkg-alias-expect.yaml │ │ ├── pkg-alias-module.yaml │ │ ├── include-file.yaml │ │ ├── include-template.yaml │ │ ├── constant-template.yaml │ │ ├── s3-template.yaml │ │ ├── ref-expect.yaml │ │ ├── s3http-template.yaml │ │ ├── constant-expect.yaml │ │ ├── meta-expect.yaml │ │ ├── env-template.yaml │ │ ├── meta-template.yaml │ │ ├── ref-template.yaml │ │ ├── alias-template.yaml │ │ ├── embed-expect.yaml │ │ ├── default-module.yaml │ │ ├── foreach-template.yaml │ │ ├── embed-template.yaml │ │ ├── s3-extension-template.yaml │ │ ├── pkg-alias-template.yaml │ │ ├── api-template.yaml │ │ ├── many-module.yaml │ │ ├── default-expect.yaml │ │ ├── same-mod-submod.yaml │ │ ├── constant-module.yaml │ │ ├── ref-module.yaml │ │ ├── s3-in-module-template.yaml │ │ ├── default-template.yaml │ │ ├── meta-module.yaml │ │ ├── simple-expect.yaml │ │ ├── override-expect.yaml │ │ ├── simple-template.yaml │ │ ├── simple-module.yaml │ │ ├── modinmod-template.yaml │ │ ├── modinmod-module.yaml │ │ ├── ref-false-template.yaml │ │ ├── sub-template.yaml │ │ ├── override-template.yaml │ │ ├── s3-props-template.yaml │ │ ├── modinmod-sub-module.yaml │ │ ├── unquoted-directive-oneline.yaml │ │ ├── quoted-directive.yaml │ │ ├── unquoted-directive.yaml │ │ ├── same-mod-module.yaml │ │ ├── modinmod-expect.yaml │ │ ├── same-mod-template.yaml │ │ ├── ifparam-template.yaml │ │ ├── override-module.yaml │ │ ├── ifparam-expect.yaml │ │ ├── foreach-expect.yaml │ │ ├── ref-false-expect.yaml │ │ ├── ifparam-module.yaml │ │ ├── composite.yaml │ │ ├── many-expect.yaml │ │ ├── many-template.yaml │ │ ├── foreach-module.yaml │ │ ├── ref-false-module.yaml │ │ ├── sub-expect.yaml │ │ ├── anchors.yaml │ │ ├── api-expect.yaml │ │ ├── api-module.yaml │ │ ├── s3-in-module-module.yaml │ │ ├── anchors-expect.yaml │ │ ├── sub-module.yaml │ │ ├── same-mod-expect.yaml │ │ ├── constant2-expect.yaml │ │ ├── bucket-template.yaml │ │ └── constant2-template.yaml │ ├── recurse.yaml │ ├── s3-object-uri.yaml │ └── anchor_test.go └── graph │ └── graph.yaml ├── test ├── webapp │ ├── site │ │ ├── img │ │ │ └── .gitkeep │ │ ├── js │ │ │ ├── .gitignore │ │ │ ├── containers.js │ │ │ ├── plugins.js │ │ │ └── config-sample.js │ │ ├── .gitignore │ │ ├── icon.png │ │ ├── vite.config.js │ │ ├── favicon.ico │ │ ├── robots.txt │ │ ├── site.webmanifest │ │ ├── icon.svg │ │ ├── eslint.config.mjs │ │ └── package.json │ ├── api │ │ ├── .gitignore │ │ └── dist │ │ │ ├── .gitkeep │ │ │ └── .gitignore │ ├── .gitignore │ ├── PklProject │ ├── buildapi.sh │ ├── PklProject.deps.json │ └── buildsite.sh ├── templates │ ├── testcommand.sh │ ├── lambda-src │ │ └── handler.py │ ├── build.yaml │ ├── analytics.yaml │ ├── include.yaml │ ├── merge1.yaml │ ├── invalid.template │ ├── analytics2.yaml │ ├── forecast-already.yml │ ├── analytics3.yaml │ ├── fmtunicode.yaml │ ├── merge-out-1.yaml │ ├── forecast │ │ ├── param.yaml │ │ ├── forecast-ref.yaml │ │ ├── forecast-notempty.yaml │ │ └── forecast-ec2.yaml │ ├── failure.template │ ├── merge-nodes-expect.yaml │ ├── merge2.yaml │ ├── success.template │ ├── emptychangeset.template │ ├── roundtrip.yaml │ ├── getazs-null.yaml │ ├── merge-out-2.yaml │ ├── quoted-directive.yaml │ ├── notcontains.yaml │ ├── ext-ref-module.yaml │ ├── pkg-alias.yaml │ ├── fmtziplinesok.yaml │ ├── merge-nodes-template.yaml │ ├── content-bucket.yaml │ ├── fmtmultiwithgt.yaml │ ├── schedule-off.yaml │ ├── graph.yaml │ ├── reuse-param.yaml │ ├── bucket.yaml │ ├── nested.template │ ├── ccdeploy2.yaml │ ├── anchors.yaml │ ├── fmtziplines.yaml │ ├── ccdeploy.yaml │ ├── fmtziplinesfolded.yaml │ ├── fmtfindinmap.yaml │ ├── format-test.yaml │ ├── intrinsic.yaml │ ├── intrinsic2.yaml │ ├── fix-320.yaml │ ├── prop-change.yaml │ ├── allowed-values.yaml │ ├── constants.yaml │ ├── null.yaml │ ├── comments.yaml │ ├── prop-change2.yaml │ ├── condition-stringlike.yaml │ └── fmtmulti.yaml ├── pkl │ ├── pkl-out.yaml │ ├── directive.yaml │ ├── PklProject │ ├── modules │ │ ├── PklProject │ │ └── PklProject.deps.json │ ├── modules.pkl │ ├── override.pkl │ ├── pkl-out.pkl │ ├── directive.json │ ├── directive-basic.pkl │ ├── PklProject.deps.json │ ├── directive.pkl │ └── bucket.pkl └── samples │ └── test-template.yaml ├── docs ├── _config.yml ├── chart.png ├── module.png ├── rain_version.md ├── rain_diff.md ├── rain_check.md ├── rain_info.md ├── rain_tree.md ├── rain_watch.md ├── rain_stackset_rm.md ├── rain_ls.md └── rain_stackset.md ├── internal ├── cmd │ ├── rm │ │ └── rm_test.go │ ├── deploy │ │ ├── util_test.go │ │ └── deploy_test.go │ ├── build │ │ ├── tmpl │ │ │ ├── modules │ │ │ │ └── sub │ │ │ │ │ └── test.yaml │ │ │ ├── metadata.txt │ │ │ └── bucket │ │ │ │ └── bucket.yaml │ │ └── nobell.go │ ├── forecast │ │ ├── ec2_launchtemplate.go │ │ ├── launch_config.go │ │ ├── codes.go │ │ └── autoscaling.go │ ├── info │ │ └── info_test.go │ ├── watch │ │ └── watch_test.go │ ├── ls │ │ ├── util.go │ │ └── ls_test.go │ ├── diff │ │ └── diff_test.go │ ├── bootstrap │ │ ├── bootstrap.go │ │ └── bootstrap_test.go │ ├── cat │ │ └── cat_test.go │ └── cc │ │ └── update_test.go ├── config │ ├── version.go │ └── config.go ├── aws │ ├── cfn │ │ ├── common.go │ │ ├── common_test.go │ │ ├── schemas │ │ │ └── aws │ │ │ │ ├── sdb │ │ │ │ └── domain.json │ │ │ │ ├── cloudformation │ │ │ │ ├── waitconditionhandle.json │ │ │ │ ├── customresource.json │ │ │ │ ├── waitcondition.json │ │ │ │ └── macro.json │ │ │ │ ├── ses │ │ │ │ └── receiptruleset.json │ │ │ │ ├── appstream │ │ │ │ ├── stackfleetassociation.json │ │ │ │ ├── stackuserassociation.json │ │ │ │ └── user.json │ │ │ │ ├── pinpoint │ │ │ │ ├── voicechannel.json │ │ │ │ ├── app.json │ │ │ │ ├── eventstream.json │ │ │ │ ├── smschannel.json │ │ │ │ ├── admchannel.json │ │ │ │ ├── baiduchannel.json │ │ │ │ ├── gcmchannel.json │ │ │ │ └── smstemplate.json │ │ │ │ ├── opsworks │ │ │ │ ├── elasticloadbalancerattachment.json │ │ │ │ ├── userprofile.json │ │ │ │ └── volume.json │ │ │ │ ├── dax │ │ │ │ ├── parametergroup.json │ │ │ │ └── subnetgroup.json │ │ │ │ ├── iam │ │ │ │ ├── usertogroupaddition.json │ │ │ │ └── accesskey.json │ │ │ │ ├── iot1click │ │ │ │ ├── device.json │ │ │ │ └── placement.json │ │ │ │ ├── appsync │ │ │ │ ├── graphqlschema.json │ │ │ │ └── apikey.json │ │ │ │ ├── iot │ │ │ │ ├── thingprincipalattachment.json │ │ │ │ └── policyprincipalattachment.json │ │ │ │ ├── wafregional │ │ │ │ ├── webaclassociation.json │ │ │ │ └── regexpatternset.json │ │ │ │ ├── glue │ │ │ │ ├── customentitytype.json │ │ │ │ └── workflow.json │ │ │ │ ├── servicecatalog │ │ │ │ ├── acceptedportfolioshare.json │ │ │ │ ├── tagoption.json │ │ │ │ ├── tagoptionassociation.json │ │ │ │ ├── portfolioshare.json │ │ │ │ ├── launchtemplateconstraint.json │ │ │ │ ├── portfolioproductassociation.json │ │ │ │ └── launchroleconstraint.json │ │ │ │ ├── elasticache │ │ │ │ └── securitygroupingress.json │ │ │ │ ├── servicediscovery │ │ │ │ └── instance.json │ │ │ │ ├── dms │ │ │ │ └── certificate.json │ │ │ │ ├── ec2 │ │ │ │ ├── clientvpntargetnetworkassociation.json │ │ │ │ ├── networkinterfacepermission.json │ │ │ │ └── clientvpnroute.json │ │ │ │ ├── codebuild │ │ │ │ └── sourcecredential.json │ │ │ │ ├── rds │ │ │ │ └── dbsecuritygroupingress.json │ │ │ │ ├── lakeformation │ │ │ │ └── resource.json │ │ │ │ ├── mediaconvert │ │ │ │ ├── preset.json │ │ │ │ └── queue.json │ │ │ │ ├── neptune │ │ │ │ └── eventsubscription.json │ │ │ │ └── redshift │ │ │ │ └── clustersecuritygroupingress.json │ │ └── stack_test.go │ ├── servicequotas │ │ └── servicequotas.go │ ├── iam │ │ └── iam_test.go │ ├── kms │ │ └── kms.go │ └── apigateway │ │ └── apigateway.go ├── ui │ └── ui.go └── console │ └── console_windows.go ├── NOTICE ├── scripts ├── build.sh ├── update.sh ├── test.sh ├── cache-schemas.sh ├── release.sh ├── gen-one-pkl.sh ├── one-schema.sh └── RELEASE.md ├── staticcheck.conf ├── .github ├── dependabot.yml ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── modules.sh │ └── test.yml ├── CODE_OF_CONDUCT.md ├── .pre-commit-hooks.yaml ├── modules ├── encrypted-bucket.yaml ├── bucket-policy.yaml └── rest-api.yaml ├── plugins └── deployconfig │ └── deployconfig.go ├── .gitignore ├── cmd ├── rain │ └── main.go ├── cfn-format │ └── main.go ├── cfn-skeleton │ └── main.go └── sample_plugin │ └── main.go └── pkl └── pkl.go /cft/cft_test.go: -------------------------------------------------------------------------------- 1 | package cft 2 | -------------------------------------------------------------------------------- /test/webapp/site/img/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cft/pkg/test.txt: -------------------------------------------------------------------------------- 1 | This: is a test 2 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/lambda-src/handler.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/.gitignore: -------------------------------------------------------------------------------- 1 | modules.zip 2 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/embed.txt: -------------------------------------------------------------------------------- 1 | This is a test 2 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate -------------------------------------------------------------------------------- /test/webapp/api/.gitignore: -------------------------------------------------------------------------------- 1 | bootstrap 2 | -------------------------------------------------------------------------------- /test/webapp/api/dist/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/badref-expect.yaml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /internal/cmd/rm/rm_test.go: -------------------------------------------------------------------------------- 1 | package rm_test 2 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/s3.txt: -------------------------------------------------------------------------------- 1 | This file will be uploaded to S3. 2 | -------------------------------------------------------------------------------- /internal/cmd/deploy/util_test.go: -------------------------------------------------------------------------------- 1 | package deploy_test 2 | -------------------------------------------------------------------------------- /test/webapp/api/dist/.gitignore: -------------------------------------------------------------------------------- 1 | lambda-handler.zip 2 | -------------------------------------------------------------------------------- /test/webapp/site/js/.gitignore: -------------------------------------------------------------------------------- 1 | config.js 2 | 3 | 4 | -------------------------------------------------------------------------------- /cft/pkg/recurse.yaml: -------------------------------------------------------------------------------- 1 | Description: !Rain::Include test.txt 2 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/insertfile-file.yaml: -------------------------------------------------------------------------------- 1 | Test: abc 2 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/s3http.txt: -------------------------------------------------------------------------------- 1 | This file will be uploaded to S3. 2 | -------------------------------------------------------------------------------- /test/webapp/site/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | 4 | 5 | -------------------------------------------------------------------------------- /test/templates/testcommand.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "Arg 1: $1" 3 | 4 | -------------------------------------------------------------------------------- /test/webapp/.gitignore: -------------------------------------------------------------------------------- 1 | site/node_modules 2 | DS_Store 3 | local/ 4 | 5 | -------------------------------------------------------------------------------- /docs/chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-cloudformation/rain/HEAD/docs/chart.png -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Rain 2 | Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/alias-module.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | bar: 3 | Type: AWS::S3::Bucket 4 | 5 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/sub/subsub.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Z: 3 | Type: A::B::C 4 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/zip-module.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Test: 3 | Type: A::B::C 4 | -------------------------------------------------------------------------------- /docs/module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-cloudformation/rain/HEAD/docs/module.png -------------------------------------------------------------------------------- /test/templates/lambda-src/handler.py: -------------------------------------------------------------------------------- 1 | def handler(evt, ctx): 2 | print("hello") 3 | 4 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/alias-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | foobar: 3 | Type: AWS::S3::Bucket 4 | 5 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/zip-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | TestTest: 3 | Type: A::B::C 4 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/pkg-alias-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | foobar: 3 | Type: AWS::S3::Bucket 4 | 5 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/pkg-alias-module.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | bar: 3 | Type: AWS::S3::Bucket 4 | 5 | -------------------------------------------------------------------------------- /internal/cmd/build/tmpl/modules/sub/test.yaml: -------------------------------------------------------------------------------- 1 | Description: Test a module in a sub-directory 2 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/conditional-module2.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Foo: 3 | Type: A::B::C 4 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/include-file.yaml: -------------------------------------------------------------------------------- 1 | Type: AWS::S3::Bucket 2 | Properties: 3 | BucketName: test 4 | 5 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/include-template.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Test: 3 | !Rain::Include include-file.yaml 4 | 5 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/badref-template.yaml: -------------------------------------------------------------------------------- 1 | Modules: 2 | Badref: 3 | Source: badref-module.yaml 4 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/depends-template.yaml: -------------------------------------------------------------------------------- 1 | Modules: 2 | A: 3 | Source: depends-module.yaml 4 | 5 | -------------------------------------------------------------------------------- /test/webapp/site/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-cloudformation/rain/HEAD/test/webapp/site/icon.png -------------------------------------------------------------------------------- /test/webapp/site/vite.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | build: { 3 | sourcemap: true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/templates/build.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | 3 | Description: Generated by rain 4 | 5 | 6 | -------------------------------------------------------------------------------- /test/webapp/site/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-cloudformation/rain/HEAD/test/webapp/site/favicon.ico -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/transform-module.yaml: -------------------------------------------------------------------------------- 1 | Transform: 2 | - MyMacro 3 | - AWS::CodeDeployBlueGreen 4 | 5 | 6 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/constant-template.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Bucket: 3 | Type: !Rain::Module ./constant-module.yaml 4 | 5 | -------------------------------------------------------------------------------- /test/templates/analytics.yaml: -------------------------------------------------------------------------------- 1 | Metadata: 2 | Comment: abc 3 | Resources: 4 | Bucket: 5 | Type: AWS::S3::Bucket 6 | -------------------------------------------------------------------------------- /test/webapp/site/robots.txt: -------------------------------------------------------------------------------- 1 | # www.robotstxt.org/ 2 | 3 | # Allow crawling of all content 4 | User-agent: * 5 | Disallow: 6 | -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eoux pipefail 4 | 5 | go build ./cmd/rain 6 | staticcheck ./... 7 | go vet ./... 8 | 9 | -------------------------------------------------------------------------------- /test/templates/include.yaml: -------------------------------------------------------------------------------- 1 | # This file is used to test Rain::Include 2 | 3 | Type: AWS::CloudFormation::WaitConditionHandle 4 | -------------------------------------------------------------------------------- /cft/pkg/s3-object-uri.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Test: !Rain::S3 3 | Path: tmpl/test.txt 4 | Format: URI 5 | Zip: true 6 | 7 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/package.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-cloudformation/rain/HEAD/cft/pkg/tmpl/awscli-modules/package.zip -------------------------------------------------------------------------------- /cft/pkg/tmpl/s3-template.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Test: 3 | Type: A::B::C 4 | Properties: 5 | TheS3URI: !Rain::S3 s3.txt 6 | -------------------------------------------------------------------------------- /staticcheck.conf: -------------------------------------------------------------------------------- 1 | checks = ["all", "-SA1006", "-ST1003", "-ST1020", "-ST1000", "-ST1002", "-ST1021", "-ST1022", "-S1009", "-ST1016"] 2 | 3 | -------------------------------------------------------------------------------- /test/templates/merge1.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Bar: 3 | Type: String 4 | 5 | Resources: 6 | Bucket: 7 | Type: AWS::S3::Bucket 8 | 9 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/ref-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | BucketBucket: 3 | Type: AWS::S3::Bucket 4 | Properties: 5 | BucketName: foo 6 | 7 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/s3http-template.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Test: 3 | Type: A::B::C 4 | Properties: 5 | TheS3URL: !Rain::S3Http s3http.txt 6 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/depends-module.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Foo: 3 | Type: A::B::C 4 | DependsOn: Bar 5 | Bar: 6 | Type: A::B::C 7 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/transform-expect.yaml: -------------------------------------------------------------------------------- 1 | Transform: 2 | - AWS::LanguageExtensions 3 | - MyMacro 4 | - AWS::CodeDeployBlueGreen 5 | 6 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/constant-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | BucketBucket: 3 | Type: AWS::S3::Bucket 4 | Properties: 5 | BucketName: bar 6 | 7 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/meta-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | BucketBucket: 3 | Type: AWS::S3::Bucket 4 | Metadata: 5 | Rain: 6 | Content: foo 7 | -------------------------------------------------------------------------------- /scripts/update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Update everything except pkl-go (v0.8.1 has a bad hash..?) 3 | go get -u ./... github.com/apple/pkl-go@v0.8.0 4 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "gomod" 4 | directory: "/" 5 | schedule: 6 | interval: "monthly" 7 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/depends-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | ABar: 3 | Type: A::B::C 4 | AFoo: 5 | Type: A::B::C 6 | DependsOn: ABar 7 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/transform-template.yaml: -------------------------------------------------------------------------------- 1 | Transform: AWS::LanguageExtensions 2 | 3 | Modules: 4 | T: 5 | Source: transform-module.yaml 6 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/env-template.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Test: 3 | Type: AWS::S3::Bucket 4 | Properties: 5 | BucketName: !Rain::Env BUCKET_NAME 6 | 7 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/meta-template.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Bucket: 3 | Type: !Rain::Module "./meta-module.yaml" 4 | Properties: 5 | Content: foo 6 | 7 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/ref-template.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Bucket: 3 | Type: !Rain::Module "./ref-module.yaml" 4 | Properties: 5 | AppName: foo 6 | 7 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/alias-template.yaml: -------------------------------------------------------------------------------- 1 | Rain: 2 | Packages: 3 | abc: 4 | Location: . 5 | Resources: 6 | foo: 7 | Type: $abc/alias-module.yaml 8 | 9 | -------------------------------------------------------------------------------- /test/templates/invalid.template: -------------------------------------------------------------------------------- 1 | Description: This template is invalid 2 | 3 | Resources: 4 | Bucket1: 5 | Type: AWS::S3::Pail 6 | Properties: yes! 7 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/insertfile-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Foo: 3 | Type: A::B::C 4 | Properties: 5 | Content: 'Test: abc 6 | 7 | ' 8 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/proparray-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | FooBaz: 3 | Type: A::B::C 4 | Properties: 5 | AnArray: 6 | - a 7 | - b 8 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/zip-template.yaml: -------------------------------------------------------------------------------- 1 | Packages: 2 | abc: 3 | Source: package.zip 4 | 5 | Modules: 6 | Test: 7 | Source: $abc/zip-module.yaml 8 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/embed-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Test: 3 | Type: AWS::CloudFormation::WaitConditionHandle 4 | Metadata: 5 | Comment: This is a test 6 | 7 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/default-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Z: 3 | Type: String 4 | Resources: 5 | Foo: 6 | Type: A::B::C 7 | Properties: 8 | ShouldBeARef: !Ref Z 9 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/foreach-template.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | 3 | ForeachTest: 4 | Type: !Rain::Module "./foreach-module.yaml" 5 | Properties: 6 | Handles: D,E,F 7 | 8 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/proparray-template.yaml: -------------------------------------------------------------------------------- 1 | Modules: 2 | Foo: 3 | Source: proparray-module.yaml 4 | Properties: 5 | Bar: 6 | - a 7 | - b 8 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/embed-template.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Test: 3 | Type: AWS::CloudFormation::WaitConditionHandle 4 | Metadata: 5 | Comment: !Rain::Embed embed.txt 6 | 7 | -------------------------------------------------------------------------------- /test/templates/analytics2.yaml: -------------------------------------------------------------------------------- 1 | Metadata: 2 | Comment: abc 3 | AWSToolsMetrics: 4 | AlreadyHere: ForSomeReason 5 | Resources: 6 | Bucket: 7 | Type: AWS::S3::Bucket 8 | -------------------------------------------------------------------------------- /test/templates/forecast-already.yml: -------------------------------------------------------------------------------- 1 | Resources: 2 | 3 | AlreadyExists: 4 | Type: AWS::S3::Bucket 5 | Properties: 6 | BucketName: ezbeard-cep-alpha-packages 7 | 8 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/insertfile-template.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Foo: 3 | Type: A::B::C 4 | Properties: 5 | Content: 6 | Fn::InsertFile: insertfile-file.yaml 7 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/select-template.yaml: -------------------------------------------------------------------------------- 1 | Modules: 2 | TestSelect: 3 | Source: select-module.yaml 4 | Properties: 5 | Things: 6 | - foo 7 | - bar 8 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/badref-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | NotSet: 3 | Type: String 4 | Resources: 5 | Foo: 6 | Type: A::B::C 7 | Properties: 8 | Name: !Ref NotSet 9 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/default-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Z: 3 | Type: String 4 | Resources: 5 | Foo: 6 | Type: A::B::C 7 | Properties: 8 | ShouldBeARef: !Ref Z 9 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/s3-extension-template.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Test: 3 | Type: A::B::C 4 | Properties: 5 | TheS3URI: !Rain::S3 6 | Path: s3.txt 7 | Extension: txt 8 | -------------------------------------------------------------------------------- /test/pkl/pkl-out.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Bucket: 3 | Type: AWS::S3::Bucket 4 | Outputs: 5 | BucketName: 6 | Value: !Ref Bucket 7 | Export: 8 | Name: foo 9 | 10 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/constant-template.yaml: -------------------------------------------------------------------------------- 1 | Constants: 2 | yyy: zzz 3 | Metadata: 4 | test: !Sub ${Const::yyy} 5 | Modules: 6 | Content: 7 | Source: ./constant-module.yaml 8 | 9 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/select-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | TestSelectFoo: 3 | Type: A::B::C 4 | Properties: 5 | Names: 6 | - foo 7 | - bar 8 | OneName: foo 9 | -------------------------------------------------------------------------------- /test/templates/analytics3.yaml: -------------------------------------------------------------------------------- 1 | Metadata: 2 | Comment: abc 3 | AWSToolsMetrics: 4 | AlreadyHere: ForSomeReason 5 | Rain: foo 6 | Resources: 7 | Bucket: 8 | Type: AWS::S3::Bucket 9 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/example-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | ContentBucket: 3 | Type: AWS::S3::Bucket 4 | Metadata: 5 | OverrideMe: def 6 | Properties: 7 | BucketName: foo 8 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/mergetags-template.yaml: -------------------------------------------------------------------------------- 1 | Modules: 2 | Network: 3 | Source: mergetags-module.yaml 4 | Properties: 5 | Tags: 6 | - Key: Name 7 | Value: abc 8 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/pkg-alias-template.yaml: -------------------------------------------------------------------------------- 1 | Rain: 2 | Packages: 3 | abc: 4 | Location: http://localhost:3000/modules.zip 5 | Resources: 6 | foo: 7 | Type: $abc/pkg-alias-module.yaml 8 | 9 | -------------------------------------------------------------------------------- /test/samples/test-template.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | queueName: 3 | Type: String 4 | Resources: 5 | TestQueue: 6 | Type: AWS::SQS::Queue 7 | Properties: 8 | QueueName: !Ref queueName 9 | -------------------------------------------------------------------------------- /test/templates/fmtunicode.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | pBotToken: 3 | Type: "AWS::SSM::Parameter::Value" 4 | Description: Bot Token 5 | Default: '/token/bot' 6 | NoEcho: 'true' 7 | 8 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/api-template.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | 3 | Meth: 4 | Type: !Rain::Module "./api-module.yaml" 5 | Overrides: 6 | Get: 7 | Properties: 8 | AuthorizationType: NONE 9 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/cond-intrinsics-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | ABucket0: 3 | Type: AWS::S3::Bucket 4 | ABucket1: 5 | Type: AWS::S3::Bucket 6 | ABucket2: 7 | Type: AWS::S3::Bucket 8 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/proparray-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Bar: 3 | Type: Array 4 | 5 | Resources: 6 | Baz: 7 | Type: A::B::C 8 | Properties: 9 | AnArray: !Ref Bar 10 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/many-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Name: 3 | Type: String 4 | Resources: 5 | Bucket1: 6 | Type: AWS::S3::Bucket 7 | Properties: 8 | BucketName: !Ref Name 9 | 10 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/default-expect.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | X: 3 | Type: String 4 | Default: abc 5 | Resources: 6 | YFoo: 7 | Type: A::B::C 8 | Properties: 9 | ShouldBeARef: !Ref X 10 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/same-mod-submod.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | X: 3 | Type: String 4 | Resources: 5 | HIJ: 6 | Type: H::I::J 7 | Properties: 8 | Name: !Ref X 9 | SubName: !Sub ${X}-hij 10 | -------------------------------------------------------------------------------- /test/templates/merge-out-1.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Bucket: 3 | Type: AWS::S3::Bucket 4 | Outputs: 5 | BucketName: 6 | Value: !Ref Bucket 7 | Export: 8 | Name: BucketNameExport 9 | 10 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/cond-unres-template.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | P: 3 | Type: String 4 | 5 | Modules: 6 | Foo: 7 | Source: cond-unres-module.yaml 8 | Properties: 9 | P: !Ref P 10 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/output-module2.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Name: 3 | Type: String 4 | Resources: 5 | Foo: 6 | Type: A::B::C 7 | Properties: 8 | AName: !Sub another-${Name} 9 | 10 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/constant-module.yaml: -------------------------------------------------------------------------------- 1 | Rain: 2 | Constants: 3 | foo: bar 4 | 5 | Resources: 6 | Bucket: 7 | Type: AWS::S3::Bucket 8 | Properties: 9 | BucketName: !Sub ${Rain::foo} 10 | 11 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/ref-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | AppName: 3 | Type: String 4 | Resources: 5 | Bucket: 6 | Type: AWS::S3::Bucket 7 | Properties: 8 | BucketName: !Ref AppName 9 | 10 | 11 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/s3-in-module-template.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | MyLambda: 3 | Type: !Rain::Module "./s3-in-module-module.yaml" 4 | Properties: 5 | SourceDir: lambda-src 6 | Handler: hello.handler 7 | 8 | -------------------------------------------------------------------------------- /test/templates/forecast/param.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Name: 3 | Type: String 4 | 5 | Resources: 6 | MyBucket: 7 | Type: AWS::S3::Bucket 8 | Properties: 9 | BucketName: !Ref Name 10 | 11 | -------------------------------------------------------------------------------- /internal/config/version.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | const ( 4 | // NAME is the name of the application 5 | NAME = "Rain" 6 | 7 | // VERSION is the application's version string 8 | VERSION = "v1.24.1" 9 | ) 10 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/default-expect.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | X: 3 | Type: String 4 | Default: abc 5 | Resources: 6 | YFoo: 7 | Type: A::B::C 8 | Properties: 9 | ShouldBeARef: !Ref X 10 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/default-template.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | X: 3 | Type: String 4 | Default: abc 5 | Modules: 6 | Y: 7 | Source: default-module.yaml 8 | Properties: 9 | Z: !Ref X 10 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/same-mod-submod.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | X: 3 | Type: String 4 | Resources: 5 | HIJ: 6 | Type: H::I::J 7 | Properties: 8 | Name: !Ref X 9 | SubName: !Sub ${X}-hij 10 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/default-template.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | X: 3 | Type: String 4 | Default: abc 5 | Resources: 6 | Y: 7 | Type: !Rain::Module default-module.yaml 8 | Properties: 9 | Z: !Ref X 10 | -------------------------------------------------------------------------------- /test/templates/failure.template: -------------------------------------------------------------------------------- 1 | Description: This template fails 2 | Resources: 3 | Bucket1: 4 | Type: AWS::S3::Bucket 5 | Bucket2: 6 | Type: AWS::S3::Bucket 7 | Properties: 8 | BucketName: !Ref Bucket1 9 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/meta-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Content: 3 | Type: String 4 | Resources: 5 | Bucket: 6 | Type: AWS::S3::Bucket 7 | Metadata: 8 | Rain: 9 | Content: !Ref Content 10 | 11 | 12 | -------------------------------------------------------------------------------- /test/templates/forecast/forecast-ref.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | BucketName: 3 | Type: String 4 | 5 | Resources: 6 | RefdBucket: 7 | Type: AWS::S3::Bucket 8 | Properties: 9 | BucketName: !Ref BucketName 10 | 11 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/map-list-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | ListRef: 3 | Type: List 4 | Resources: 5 | Bar: 6 | Type: A::B::C 7 | Properties: 8 | Refs: !Ref ListRef 9 | ListOverride: aaa 10 | 11 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/simple-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | MyBucket1: 3 | Type: AWS::S3::Bucket 4 | Properties: 5 | BucketName: foo 6 | MyBucket2: 7 | Type: AWS::S3::Bucket 8 | Properties: 9 | BucketName: bar 10 | -------------------------------------------------------------------------------- /test/pkl/directive.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Func: 3 | Type: AWS::Lambda::Function 4 | Properties: 5 | Code: !Rain::S3 6 | Path: "." 7 | KeyProperty: "S3Key" 8 | BucketProperty: "S3Bucket" 9 | 10 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/cond-conflict-template.yaml: -------------------------------------------------------------------------------- 1 | Conditions: 2 | FooIsRegionUsEast1: 3 | Fn::Equals: 4 | - NotTheSameThing 5 | - us-east-1 6 | 7 | Modules: 8 | Foo: 9 | Source: cond-unres-module.yaml 10 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/map-output-module.yaml: -------------------------------------------------------------------------------- 1 | Modules: 2 | B: 3 | Source: ./map-module.yaml 4 | ForEach: x,y 5 | Properties: 6 | Name: b-$Identifier 7 | Outputs: 8 | BArns: 9 | Value: !GetAtt B[].Arn 10 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/mergetags-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | NetworkVPC: 3 | Type: AWS::EC2::VPC 4 | Properties: 5 | Tags: 6 | - Key: Name 7 | Value: abc 8 | - Key: Foo 9 | Value: Bar 10 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/override-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | MyBucket1: 3 | Type: AWS::S3::Bucket 4 | Properties: 5 | BucketName: foo 6 | MyBucket2: 7 | Type: AWS::S3::Bucket 8 | Properties: 9 | BucketName: bar 10 | -------------------------------------------------------------------------------- /scripts/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eoux pipefail 4 | 5 | # This should be run regularly, but in its own PR 6 | # go generate ./... 7 | 8 | go build ./cmd/rain 9 | staticcheck ./... 10 | go vet ./... 11 | go test ./... 12 | 13 | -------------------------------------------------------------------------------- /test/pkl/PklProject: -------------------------------------------------------------------------------- 1 | amends "pkl:Project" 2 | 3 | dependencies { 4 | ["cfn"] { 5 | uri = "package://github.com/aws-cloudformation/cloudformation-pkl/releases/download/cloudformation@0.1.4/cloudformation@0.1.4" 6 | } 7 | } 8 | 9 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | *Issue #, if available:* 2 | 3 | *Description of changes:* 4 | 5 | 6 | By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. 7 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/simple-template.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | My: 3 | Type: !Rain::Module "./simple-module.yaml" 4 | Properties: 5 | Name: foo 6 | Overrides: 7 | Bucket2: 8 | Properties: 9 | BucketName: bar 10 | -------------------------------------------------------------------------------- /test/templates/merge-nodes-expect.yaml: -------------------------------------------------------------------------------- 1 | Merged: 2 | A: AAA 3 | B: bbb 4 | C: 5 | Obj: 6 | D: DDD 7 | E: 8 | - 1 9 | - 2 10 | - 3 11 | - 4 12 | F: 13 | - Key: a 14 | Val: c 15 | - Key: x 16 | Val: y 17 | -------------------------------------------------------------------------------- /test/templates/merge2.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Foo: 3 | Type: String 4 | 5 | Resources: 6 | MyEventBridgeSchedule: 7 | Type: AWS::Scheduler::Schedule 8 | Properties: 9 | FlexibleTimeWindow: 10 | Mode: "OFF" 11 | 12 | -------------------------------------------------------------------------------- /test/webapp/PklProject: -------------------------------------------------------------------------------- 1 | amends "pkl:Project" 2 | 3 | dependencies { 4 | ["cfn"] { 5 | uri = "package://github.com/aws-cloudformation/cloudformation-pkl/releases/download/cloudformation@0.1.4/cloudformation@0.1.4" 6 | } 7 | } 8 | 9 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/example-template.yaml: -------------------------------------------------------------------------------- 1 | Modules: 2 | Content: 3 | Source: ./example-module.yaml 4 | Properties: 5 | Name: foo 6 | Overrides: 7 | Bucket: 8 | Metadata: 9 | OverrideMe: def 10 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/foreach-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Name: 3 | Type: String 4 | Resources: 5 | Foo: 6 | Type: A::B::C 7 | Properties: 8 | Name: !Ref Name 9 | Outputs: 10 | Out1: 11 | Value: !GetAtt Foo.Arn 12 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/simple-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Name: 3 | Type: String 4 | Resources: 5 | Bucket1: 6 | Type: AWS::S3::Bucket 7 | Properties: 8 | BucketName: !Ref Name 9 | Bucket2: 10 | Type: AWS::S3::Bucket 11 | 12 | -------------------------------------------------------------------------------- /test/pkl/modules/PklProject: -------------------------------------------------------------------------------- 1 | amends "pkl:Project" 2 | 3 | dependencies { 4 | ["cfn"] { 5 | uri = "package://github.com/aws-cloudformation/cloudformation-pkl/releases/download/cloudformation@0.1.4/cloudformation@0.1.4" 6 | } 7 | } 8 | 9 | -------------------------------------------------------------------------------- /test/templates/forecast/forecast-notempty.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | 3 | NotEmpty: 4 | Type: AWS::S3::Bucket 5 | Properties: 6 | BucketName: ezbeard-rain-notempty 7 | VersioningConfiguration: 8 | Status: Enabled 9 | 10 | -------------------------------------------------------------------------------- /test/templates/success.template: -------------------------------------------------------------------------------- 1 | Description: This template succeeds 2 | Parameters: 3 | BucketName: 4 | Type: String 5 | Resources: 6 | Bucket1: 7 | Type: AWS::S3::Bucket 8 | Properties: 9 | BucketName: !Ref BucketName 10 | -------------------------------------------------------------------------------- /test/templates/emptychangeset.template: -------------------------------------------------------------------------------- 1 | Description: This template succeeds 2 | Parameters: 3 | BucketName: 4 | Type: String 5 | Resources: 6 | Bucket1: 7 | Type: AWS::S3::Bucket 8 | Properties: 9 | BucketName: !Ref BucketName 10 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/cond-intrinsics-template.yaml: -------------------------------------------------------------------------------- 1 | Modules: 2 | A: 3 | Source: ./cond-intrinsics-module.yaml 4 | Properties: 5 | Foo: bar 6 | B: 7 | Source: ./cond-intrinsics-module.yaml 8 | Properties: 9 | Foo: baz 10 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/example-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Name: 3 | Type: String 4 | Resources: 5 | Bucket: 6 | Type: AWS::S3::Bucket 7 | Metadata: 8 | OverrideMe: abc 9 | Properties: 10 | BucketName: !Ref Name 11 | 12 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/modinmod-template.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | ParentVal: 3 | Type: String 4 | pAppName: 5 | Type: String 6 | Modules: 7 | My: 8 | Source: ./modinmod-module.yaml 9 | Properties: 10 | AppName: !Ref pAppName 11 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/modinmod-template.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | ParentVal: 3 | Type: String 4 | pAppName: 5 | Type: String 6 | Resources: 7 | My: 8 | Type: !Rain::Module "./modinmod-module.yaml" 9 | Properties: 10 | AppName: !Ref pAppName 11 | -------------------------------------------------------------------------------- /internal/cmd/build/tmpl/metadata.txt: -------------------------------------------------------------------------------- 1 | Apache-2.0 License. Adapt this template to your needs and thoruoughly test it before introducing it in a production environment. **WARNING** This template will create resources in your account that may incur billing charges. 2 | -------------------------------------------------------------------------------- /test/templates/roundtrip.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | RootId: 3 | Type: String 4 | 5 | Resources: 6 | 7 | Sandbox: 8 | Type: AWS::Organizations::OrganizationalUnit 9 | Properties: 10 | ParentId: !Ref RootId 11 | Name: Sandbox 12 | 13 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/vpc-template.yaml: -------------------------------------------------------------------------------- 1 | Modules: 2 | Network: 3 | Source: ./vpc-module.yaml 4 | Properties: 5 | CidrBlock: 10.0.0.0/16 6 | PrivateCidrBlocks: 10.0.0.0/18,10.0.64.0/18 7 | PublicCidrBlocks: 10.0.128.0/18,10.0.192.0/18 8 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/modinmod-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | AppName: 3 | Type: String 4 | Resources: 5 | Sub: 6 | Type: !Rain::Module "./modinmod-sub-module.yaml" 7 | Properties: 8 | X: !Sub ${ParentVal}-abc 9 | Y: !Sub ${AppName}-xyz 10 | 11 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/sub-template.yaml: -------------------------------------------------------------------------------- 1 | Modules: 2 | My: 3 | Source: ./sub-module.yaml 4 | Properties: 5 | Name: foo 6 | SubName: !Sub ${Foo} 7 | Overrides: 8 | Bucket2: 9 | Properties: 10 | BucketName: bar 11 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/ref-false-template.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | My: 3 | Type: !Rain::Module "./ref-false-module.yaml" 4 | Properties: 5 | Name: foo 6 | B: false 7 | Overrides: 8 | Bucket2: 9 | Properties: 10 | BucketName: bar 11 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/sub-template.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | My: 3 | Type: !Rain::Module "./sub-module.yaml" 4 | Properties: 5 | Name: foo 6 | SubName: !Sub ${Foo} 7 | Overrides: 8 | Bucket2: 9 | Properties: 10 | BucketName: bar 11 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/invoke-module-b.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | X: 3 | Type: String 4 | Y: 5 | Type: String 6 | Z: 7 | Type: String 8 | 9 | Outputs: 10 | Props: 11 | Value: 12 | X: !Ref X 13 | Y: !Ref Y 14 | Z: !Ref Z 15 | 16 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/override-template.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | My: 3 | Type: !Rain::Module "./override-module.yaml" 4 | Properties: 5 | Name: foo 6 | BucketName: bar 7 | Overrides: 8 | Bucket2: 9 | Properties: 10 | BucketName: baz 11 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/s3-props-template.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | MyFunction: 3 | Type: AWS::Lambda::Function 4 | Properties: 5 | Code: !Rain::S3 6 | Path: lambda-src 7 | Zip: true 8 | BucketProperty: S3Bucket 9 | KeyProperty: S3Key 10 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/cond-unres-submodule.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | P: 3 | Type: String 4 | 5 | Conditions: 6 | IsParam: 7 | Fn::Equals: 8 | - !Ref P 9 | - true 10 | 11 | Resources: 12 | B: 13 | Condition: IsParam 14 | Type: A::B::C 15 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/map-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Name: 3 | Type: String 4 | 5 | Resources: 6 | Bucket: 7 | Type: AWS::S3::Bucket 8 | Properties: 9 | BucketName: !Ref Name 10 | 11 | Outputs: 12 | Arn: 13 | Value: !GetAtt Bucket.Arn 14 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/getatt-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Name: 3 | Type: String 4 | Resources: 5 | Bucket: 6 | Type: AWS::S3::Bucket 7 | Properties: 8 | BucketName: !Ref Name 9 | Outputs: 10 | BucketName: 11 | Value: !GetAtt "Bucket.BucketName" 12 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/modinmod-sub-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | X: 3 | Type: String 4 | Y: 5 | Type: String 6 | Resources: 7 | Bucket: 8 | Type: AWS::S3::Bucket 9 | Properties: 10 | BucketName: mod-in-mod-bucket 11 | XName: !Ref X 12 | YName: !Ref Y 13 | -------------------------------------------------------------------------------- /.github/workflows/modules.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eoux pipefail 4 | 5 | # Zip up the modules directory and create a sha256 hash 6 | mkdir -p dist 7 | cd modules 8 | zip -r ../dist/modules.zip * 9 | sha256sum -b ../dist/modules.zip | cut -d " " -f 1 > ../dist/modules.sha256 10 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/select-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Things: 3 | Type: List 4 | Resources: 5 | Foo: 6 | Type: A::B::C 7 | Properties: 8 | Names: !Ref Things 9 | OneName: 10 | Fn::Select: 11 | - !Ref Things 12 | - 0 13 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/merge-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | FooBar: 3 | Type: A::B::C 4 | Properties: 5 | Merged: 6 | A: BBB 7 | B: CCC 8 | C: D 9 | Lists: 10 | - a 11 | - b 12 | - b 13 | - c 14 | - b 15 | - c 16 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/modinmod-submodule.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | X: 3 | Type: String 4 | Y: 5 | Type: String 6 | Resources: 7 | Bucket: 8 | Type: AWS::S3::Bucket 9 | Properties: 10 | BucketName: mod-in-mod-bucket 11 | XName: !Ref X 12 | YName: !Ref Y 13 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/unquoted-directive-oneline.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | MyLambda: 3 | Type: AWS::Lambda::Function 4 | Properties: 5 | Code: !Rain::S3 6 | Path: lambda-src 7 | Zip: true 8 | BucketProperty: S3Bucket 9 | KeyProperty: S3Key 10 | 11 | -------------------------------------------------------------------------------- /test/templates/getazs-null.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | VpcId: 3 | Type: String 4 | 5 | Resources: 6 | 7 | PrivateSubnet1Subnet: 8 | Type: AWS::EC2::Subnet 9 | Properties: 10 | AvailabilityZone: !Select 11 | - 0 12 | - !GetAZs "" 13 | VpcId: !Ref VpcId 14 | -------------------------------------------------------------------------------- /test/templates/merge-out-2.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | AccessLogsBucket: 3 | Type: AWS::S3::Bucket 4 | Properties: 5 | BucketName: 6 | Fn::Sub: 7 | - ${ParentBucket}-access-logs 8 | - ParentBucket: 9 | Fn::ImportValue: BucketNameExport 10 | 11 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/map-index-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | ContentRef: 3 | Type: String 4 | NestedRef: 5 | Type: String 6 | Resources: 7 | Foo: 8 | Type: A::B::C 9 | Properties: 10 | Name: !Sub content-ref-${ContentRef} 11 | NestedName: !Ref NestedRef 12 | 13 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/outjoin-template.yaml: -------------------------------------------------------------------------------- 1 | Modules: 2 | Content: 3 | Source: ./outjoin-module.yaml 4 | Properties: 5 | Name: foo 6 | Resources: 7 | A: 8 | Type: D::E::F 9 | Properties: 10 | X: !GetAtt Content.JoinTest 11 | Y: !GetAtt Content.ScalarTest 12 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/quoted-directive.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | MyLambda: 3 | Type: AWS::Lambda::Function 4 | Properties: 5 | Code: 6 | 'Rain::S3': 7 | Path: lambda-src 8 | Zip: true 9 | BucketProperty: S3Bucket 10 | KeyProperty: S3Key 11 | 12 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/unquoted-directive.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | MyLambda: 3 | Type: AWS::Lambda::Function 4 | Properties: 5 | Code: 6 | !Rain::S3 7 | Path: lambda-src 8 | Zip: true 9 | BucketProperty: S3Bucket 10 | KeyProperty: S3Key 11 | 12 | -------------------------------------------------------------------------------- /test/templates/quoted-directive.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | MyLambda: 3 | Type: AWS::Lambda::Function 4 | Properties: 5 | Code: 6 | '!Rain::S3': 7 | Path: lamdba-src 8 | Zip: true 9 | BucketProperty: S3Bucket 10 | KeyProperty: S3Key 11 | 12 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/outsublist-template.yaml: -------------------------------------------------------------------------------- 1 | Modules: 2 | Content: 3 | Source: ./output-module.yaml 4 | Properties: 5 | Name: foo 6 | 7 | Resources: 8 | A: 9 | Type: D::E::F 10 | Properties: 11 | Object: 12 | GetAttToGetAttList: !GetAtt Content.ArnList 13 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/type-template.yaml: -------------------------------------------------------------------------------- 1 | Modules: 2 | Content: 3 | Source: ./type-module.yaml 4 | Properties: 5 | Name: foo 6 | Overrides: 7 | Bucket: 8 | Properties: 9 | OverrideMe: def 10 | Resources: 11 | OtherResource: 12 | Type: AWS::S3::Bucket 13 | -------------------------------------------------------------------------------- /test/pkl/modules.pkl: -------------------------------------------------------------------------------- 1 | import "@cfn/cloudformation.pkl" as cfn 2 | import "./modules/bucket.pkl" as bucket 3 | 4 | b = new bucket { 5 | AppName = "test" 6 | Content = "." 7 | EmptyOnDelete = true 8 | LogicalId = "Content" 9 | } 10 | 11 | Resources { 12 | ...b.Resources 13 | } 14 | 15 | 16 | -------------------------------------------------------------------------------- /test/templates/notcontains.yaml: -------------------------------------------------------------------------------- 1 | Rules: 2 | CheckBootstrapVersion: 3 | Assertions: 4 | - Assert: !Not 5 | - !Contains 6 | - - '1' 7 | - '2' 8 | - '3' 9 | - '4' 10 | - '5' 11 | - !Ref BootstrapVersion 12 | 13 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/same-mod-template.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | X: 3 | Type: String 4 | Default: default-x 5 | Modules: 6 | A: 7 | Source: same-mod-module.yaml 8 | Properties: 9 | X: !Ref X 10 | B: 11 | Source: same-mod-module.yaml 12 | Properties: 13 | X: x 14 | 15 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/same-mod-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | X: 3 | Type: String 4 | Resources: 5 | ABC: 6 | Type: A::B::C 7 | Properties: 8 | Name: !Ref X 9 | SubName: !Sub ${X}-name 10 | DEF: 11 | Type: !Rain::Module same-mod-submod.yaml 12 | Properties: 13 | X: !Sub ${X}-def 14 | -------------------------------------------------------------------------------- /test/webapp/site/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "", 3 | "name": "", 4 | "icons": [{ 5 | "src": "icon.png", 6 | "type": "image/png", 7 | "sizes": "192x192" 8 | }], 9 | "start_url": "/?utm_source=homescreen", 10 | "background_color": "#fafafa", 11 | "theme_color": "#fafafa" 12 | } 13 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/merge-template.yaml: -------------------------------------------------------------------------------- 1 | Modules: 2 | Foo: 3 | Source: merge-module.yaml 4 | Properties: 5 | X: 6 | A: "BBB" 7 | B: "c" 8 | Y: 9 | B: "CCC" 10 | C: "D" 11 | XX: 12 | - a 13 | - b 14 | YY: 15 | - b 16 | - c 17 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/modinmod-expect.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | ParentVal: 3 | Type: String 4 | pAppName: 5 | Type: String 6 | Resources: 7 | MySubBucket: 8 | Type: AWS::S3::Bucket 9 | Properties: 10 | BucketName: mod-in-mod-bucket 11 | XName: !Sub ${ParentVal}-abc 12 | YName: !Sub ${pAppName}-xyz 13 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/same-mod-template.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | X: 3 | Type: String 4 | Default: default-x 5 | Resources: 6 | A: 7 | Type: !Rain::Module same-mod-module.yaml 8 | Properties: 9 | X: !Ref X 10 | B: 11 | Type: !Rain::Module same-mod-module.yaml 12 | Properties: 13 | X: x 14 | 15 | -------------------------------------------------------------------------------- /test/templates/ext-ref-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | ThePolicy: 3 | Type: String 4 | 5 | Resources: 6 | 7 | ModuleExample: 8 | Type: !Rain::Module "file://../../modules/ext-ref.yaml" 9 | Properties: 10 | BucketName: ezbeard-cep-test-module-bucket 11 | RetentionPolicy: !Ref ThePolicy 12 | 13 | 14 | -------------------------------------------------------------------------------- /test/templates/pkg-alias.yaml: -------------------------------------------------------------------------------- 1 | Rain: 2 | Packages: 3 | abc: 4 | Location: https://github.com/ericzbeard/rain/releases/download/m0.1.0-c/modules.zip 5 | Hash: https://github.com/ericzbeard/rain/releases/download/m0.1.0-c/modules.sha256 6 | Resources: 7 | foo: 8 | Type: $abc/encrypted-bucket.yaml 9 | 10 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/same-mod-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | X: 3 | Type: String 4 | Modules: 5 | DEF: 6 | Source: same-mod-submod.yaml 7 | Properties: 8 | X: !Sub ${X}-def 9 | Resources: 10 | ABC: 11 | Type: A::B::C 12 | Properties: 13 | Name: !Ref X 14 | SubName: !Sub ${X}-name 15 | -------------------------------------------------------------------------------- /scripts/cache-schemas.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # $1 is the dir to use for storing schemas 4 | 5 | set -eou pipefail 6 | 7 | export RAIN_CACHE_DIR=$1 8 | 9 | ./rain build -l --no-cache > internal/aws/cfn/all-types.txt 10 | 11 | cat internal/aws/cfn/all-types.txt | grep "^AWS::" | xargs -n1 scripts/one-schema.sh 12 | 13 | 14 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/conditional-template.yaml: -------------------------------------------------------------------------------- 1 | Modules: 2 | A: 3 | Source: ./conditional-module.yaml 4 | Properties: 5 | TableName: table-a 6 | LambdaRoleName: my-role 7 | HasLambda: true 8 | B: 9 | Source: ./conditional-module.yaml 10 | Properties: 11 | TableName: table-b 12 | 13 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/constant-expect.yaml: -------------------------------------------------------------------------------- 1 | Metadata: 2 | test: zzz 3 | Resources: 4 | ContentBucket: 5 | Type: AWS::S3::Bucket 6 | Metadata: 7 | Test: 8 | Fn::Sub: bar-abc-${AWS::AccountId}-xyz 9 | TestObj: 10 | TestObject: 11 | A: b 12 | Properties: 13 | BucketName: bar 14 | -------------------------------------------------------------------------------- /test/pkl/override.pkl: -------------------------------------------------------------------------------- 1 | open class a { 2 | Metadata: Mapping 3 | } 4 | 5 | aa = new a { 6 | Metadata { 7 | ["Foo"] { 8 | ["Key1"] = "bar" 9 | } 10 | } 11 | } 12 | 13 | bb = (aa) { 14 | Metadata { 15 | ["Foo"] { 16 | ["Key1"] = "baz" 17 | ["Key2"] = "baz2" 18 | } 19 | } 20 | } 21 | 22 | 23 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/mergetags-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Tags: 3 | Type: Object 4 | Constants: 5 | FooTag: 6 | - Key: Foo 7 | Value: Bar 8 | Resources: 9 | VPC: 10 | Type: AWS::EC2::VPC 11 | Properties: 12 | Tags: 13 | Fn::Merge: 14 | - !Ref Tags 15 | - !Ref Const::FooTag 16 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/ifparam-template.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Show1Hide2: 3 | Type: !Rain::Module ./ifparam-module.yaml 4 | Properties: 5 | Foo: foo 6 | Show1Hide2Sub: 7 | Type: !Rain::Module ./ifparam-module.yaml 8 | Properties: 9 | Foo: !Sub ${Foo} 10 | Hide1Show2: 11 | Type: !Rain::Module ./ifparam-module.yaml 12 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/override-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Name: 3 | Type: String 4 | BucketName: 5 | Type: String 6 | Resources: 7 | Bucket1: 8 | Type: AWS::S3::Bucket 9 | Properties: 10 | BucketName: !Ref Name 11 | Bucket2: 12 | Type: AWS::S3::Bucket 13 | Properties: 14 | BucketName: !Ref BucketName 15 | 16 | -------------------------------------------------------------------------------- /test/templates/fmtziplinesok.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | 3 | Description: Example AWS CloudFormation template snippet. 4 | 5 | Resources: 6 | Test: 7 | Type: AWS::Lambda::Function 8 | Properties: 9 | Code: 10 | ZipFile: | 11 | """Example.""" 12 | import boto3 13 | TEST = 1 14 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/getatt-template.yaml: -------------------------------------------------------------------------------- 1 | Modules: 2 | Content: 3 | Source: ./getatt-module.yaml 4 | Properties: 5 | Name: foo 6 | 7 | Resources: 8 | Foo: 9 | Type: A::B::C 10 | Properties: 11 | BucketName: !GetAtt Content.BucketName 12 | 13 | Outputs: 14 | BucketName: 15 | Value: !GetAtt Content.BucketName 16 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/sub/modinmod-submodule.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | X: 3 | Type: String 4 | Y: 5 | Type: String 6 | Modules: 7 | SubSub: 8 | Source: subsub.yaml 9 | Resources: 10 | Bucket: 11 | Type: AWS::S3::Bucket 12 | Properties: 13 | BucketName: mod-in-mod-bucket 14 | XName: !Ref X 15 | YName: !Ref Y 16 | -------------------------------------------------------------------------------- /test/pkl/pkl-out.pkl: -------------------------------------------------------------------------------- 1 | amends "@cfn/template.pkl" 2 | import "@cfn/cloudformation.pkl" as cfn 3 | import "@cfn/aws/s3/bucket.pkl" 4 | 5 | Resources { 6 | ["Bucket"] = new bucket.Bucket { 7 | Type = "AWS::S3::Bucket" 8 | } 9 | 10 | } 11 | 12 | Outputs { 13 | ["BucketName"] = new cfn.Output { 14 | Value = cfn.Ref("Bucket") 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/basic-template.yaml: -------------------------------------------------------------------------------- 1 | Modules: 2 | Content: 3 | Source: ./basic-module.yaml 4 | Properties: 5 | Name: foo 6 | Overrides: 7 | Bucket: 8 | Properties: 9 | OverrideMe: def 10 | Resources: 11 | OtherResource: 12 | Type: AWS::S3::Bucket 13 | Metadata: 14 | TestOutputSub: !Sub ${Content.Name} 15 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/ifparam-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Show1Hide2Bucket1: 3 | Type: AWS::S3::Bucket 4 | Properties: 5 | BucketName: Bucket1 6 | Show1Hide2SubBucket1: 7 | Type: AWS::S3::Bucket 8 | Properties: 9 | BucketName: Bucket1 10 | Hide1Show2Bucket2: 11 | Type: AWS::S3::Bucket 12 | Properties: 13 | BucketName: Bucket2 14 | 15 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/type-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Name: 3 | Type: String 4 | Resources: 5 | Bucket: 6 | Type: AWS::S3::Bucket 7 | Properties: 8 | BucketName: !Ref Name 9 | OverrideMe: abc 10 | SubName: !Sub ${Name} 11 | Bucket2: 12 | Type: AWS::S3::Bucket 13 | Properties: 14 | BucketName: !GetAtt Bucket.Something 15 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/getatt-expect.yaml: -------------------------------------------------------------------------------- 1 | Outputs: 2 | BucketName: 3 | Value: 4 | Fn::GetAtt: 5 | - ContentBucket 6 | - BucketName 7 | Resources: 8 | ContentBucket: 9 | Type: AWS::S3::Bucket 10 | Properties: 11 | BucketName: foo 12 | Foo: 13 | Type: A::B::C 14 | Properties: 15 | BucketName: !GetAtt ContentBucket.BucketName 16 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/policy-template.yaml: -------------------------------------------------------------------------------- 1 | Modules: 2 | Access: 3 | Source: ./policy-module.yaml 4 | Properties: 5 | Role: foo 6 | Overrides: 7 | Policy: 8 | Properties: 9 | PolicyDocument: 10 | Statement: 11 | - Effect: DENY 12 | Action: s3:Put* 13 | Resource: arn:aws:s3:::bar 14 | -------------------------------------------------------------------------------- /test/templates/merge-nodes-template.yaml: -------------------------------------------------------------------------------- 1 | Original: 2 | A: aaa 3 | B: bbb 4 | C: 5 | Obj: 6 | D: ddd 7 | E: 8 | - 1 9 | - 2 10 | F: 11 | - Key: a 12 | Val: b 13 | - Key: x 14 | Val: y 15 | 16 | Override: 17 | A: AAA 18 | B: bbb 19 | C: 20 | Obj: 21 | D: DDD 22 | E: 23 | - 3 24 | - 4 25 | F: 26 | - Key: a 27 | Val: c 28 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/constant-module.yaml: -------------------------------------------------------------------------------- 1 | Constants: 2 | foo: bar 3 | sub: "${Const::foo}-abc-${AWS::AccountId}" 4 | obj: 5 | TestObject: 6 | A: b 7 | 8 | Resources: 9 | Bucket: 10 | Type: AWS::S3::Bucket 11 | Metadata: 12 | Test: !Sub ${Const::sub}-xyz 13 | TestObj: !Ref Const::obj 14 | Properties: 15 | BucketName: !Sub ${Const::foo} 16 | 17 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/outsublist-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Name: 3 | Type: String 4 | Resources: 5 | Bucket: 6 | Type: AWS::S3::Bucket 7 | Properties: 8 | BucketName: !Ref Name 9 | Bucket2: 10 | Type: AWS::S3::Bucket 11 | Outputs: 12 | ArnList: 13 | Value: 14 | - !Sub ${Bucket.Arn} 15 | - !Sub ${Bucket2.Arn} 16 | - !Sub abc-${Name} 17 | 18 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/foreach-expect.yaml: -------------------------------------------------------------------------------- 1 | Transform: AWS::LanguageExtensions 2 | 3 | Resources: 4 | 5 | Fn::ForEach::ForeachTestMakeHandles: 6 | - HandleName 7 | - - D 8 | - E 9 | - F 10 | - "ForeachTest${HandleName}": 11 | Type: AWS::CloudFormation::WaitConditionHandle 12 | Metadata: 13 | Comment: !Sub "This is wait handle ${HandleName}" 14 | 15 | 16 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/outjoin-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | A: 3 | Type: D::E::F 4 | Properties: 5 | X: 6 | Fn::Join: 7 | - '-' 8 | - - Ref: ContentBucket 9 | - Fn::GetAtt: 10 | - ContentBucket 11 | - Arn 12 | Y: foo-xyz 13 | ContentBucket: 14 | Type: AWS::S3::Bucket 15 | Properties: 16 | BucketName: foo 17 | -------------------------------------------------------------------------------- /internal/aws/cfn/common.go: -------------------------------------------------------------------------------- 1 | package cfn 2 | 3 | // uniqueStrings returns a unique subset of the string slice provided. 4 | func UniqueStrings(input []string) []string { 5 | u := make([]string, 0, len(input)) 6 | m := make(map[string]bool) 7 | 8 | for _, val := range input { 9 | if _, ok := m[val]; !ok { 10 | m[val] = true 11 | u = append(u, val) 12 | } 13 | } 14 | 15 | return u 16 | } 17 | -------------------------------------------------------------------------------- /test/templates/content-bucket.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Bucket: 3 | Type: AWS::S3::Bucket 4 | Metadata: 5 | Rain: 6 | Content: ./lambda-src 7 | Version: 2 8 | EmptyOnDelete: true 9 | RunAfter: 10 | Command: testcommand.sh 11 | Args: 12 | - Rain::OutputValue BucketName 13 | Outputs: 14 | BucketName: 15 | Value: !Ref Bucket 16 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/modinmod-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | AppName: 3 | Type: String 4 | Modules: 5 | Sub: 6 | Source: "./modinmod-submodule.yaml" 7 | Properties: 8 | X: !Sub ${ParentVal}-abc 9 | Y: !Sub ${AppName}-xyz 10 | SubInDir: 11 | Source: "./sub/modinmod-submodule.yaml" 12 | Properties: 13 | X: !Sub ${ParentVal}-abc 14 | Y: !Sub ${AppName}-xyz 15 | 16 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/ref-false-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | MyBucket1: 3 | Type: AWS::S3::Bucket 4 | Properties: 5 | BucketName: foo 6 | Parent: 7 | - Child: 8 | ShouldBeFalse: false 9 | - OtherChild: false 10 | - Subs: 11 | - "b0false" 12 | - "b1false" 13 | MyBucket2: 14 | Type: AWS::S3::Bucket 15 | Properties: 16 | BucketName: bar 17 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/ifparam-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Foo: 3 | Type: String 4 | 5 | Resources: 6 | Bucket1: 7 | Type: AWS::S3::Bucket 8 | Metadata: 9 | Rain: 10 | IfParam: Foo 11 | Properties: 12 | BucketName: Bucket1 13 | Bucket2: 14 | Type: AWS::S3::Bucket 15 | Metadata: 16 | Rain: 17 | IfNotParam: Foo 18 | Properties: 19 | BucketName: Bucket2 20 | 21 | -------------------------------------------------------------------------------- /internal/aws/cfn/common_test.go: -------------------------------------------------------------------------------- 1 | package cfn_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/aws-cloudformation/rain/internal/aws/cfn" 7 | ) 8 | 9 | func TestUniqueStrings(t *testing.T) { 10 | in := []string{"a", "a", "b", "c"} 11 | expect := []string{"a", "b", "c"} 12 | uq := cfn.UniqueStrings(in) 13 | if uq[0] != expect[0] || uq[1] != expect[1] || uq[2] != expect[2] { 14 | t.Error() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/outsublist-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | A: 3 | Type: D::E::F 4 | Properties: 5 | Object: 6 | GetAttToGetAttList: 7 | - Fn::Sub: ${ContentBucket.Arn} 8 | - Fn::Sub: ${ContentBucket2.Arn} 9 | - abc-foo 10 | ContentBucket: 11 | Type: AWS::S3::Bucket 12 | Properties: 13 | BucketName: foo 14 | ContentBucket2: 15 | Type: AWS::S3::Bucket 16 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/type-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | OtherResource: 3 | Type: AWS::S3::Bucket 4 | ContentBucket: 5 | Type: AWS::S3::Bucket 6 | Properties: 7 | BucketName: foo 8 | OverrideMe: def 9 | SubName: foo 10 | ContentBucket2: 11 | Type: AWS::S3::Bucket 12 | Properties: 13 | BucketName: 14 | Fn::GetAtt: 15 | - ContentBucket 16 | - Something 17 | -------------------------------------------------------------------------------- /test/templates/fmtmultiwithgt.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | 3 | Description: Example AWS CloudFormation template snippet. 4 | 5 | Resources: 6 | Test: 7 | Type: AWS::Lambda::Function 8 | Properties: 9 | Code: 10 | ZipFile: | 11 | """Example.""" 12 | 13 | import boto3 14 | 15 | breaks = """ 16 | > 17 | """ 18 | 19 | TEST = 1 -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/basic-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Name: 3 | Type: String 4 | Resources: 5 | Bucket: 6 | Type: AWS::S3::Bucket 7 | Properties: 8 | BucketName: !Ref Name 9 | OverrideMe: abc 10 | SubName: !Sub ${Name} 11 | Bucket2: 12 | Type: AWS::S3::Bucket 13 | Properties: 14 | BucketName: !GetAtt Bucket.Something 15 | Outputs: 16 | Name: 17 | Value: !Ref Bucket 18 | -------------------------------------------------------------------------------- /test/webapp/site/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/composite.yaml: -------------------------------------------------------------------------------- 1 | Description: This module demonstrates a composition of resources, without an extension. 2 | 3 | Parameters: 4 | AName: 5 | Type: String 6 | BName: 7 | Type: String 8 | 9 | Resources: 10 | 11 | BucketA: 12 | Type: AWS::S3::Bucket 13 | Properties: 14 | BucketName: !Ref AName 15 | 16 | BucketB: 17 | Type: AWS::S3::Bucket 18 | Properties: 19 | BucketName: !Ref BName 20 | 21 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/many-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | My1Bucket1: 3 | Type: AWS::S3::Bucket 4 | Properties: 5 | BucketName: foo1 6 | 7 | My2Bucket1: 8 | Type: AWS::S3::Bucket 9 | Properties: 10 | BucketName: foo2 11 | 12 | My3Bucket1: 13 | Type: AWS::S3::Bucket 14 | Properties: 15 | BucketName: foo3 16 | 17 | My4Bucket1: 18 | Type: AWS::S3::Bucket 19 | Properties: 20 | BucketName: foo4 21 | -------------------------------------------------------------------------------- /scripts/release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eou pipefail 4 | 5 | echo "Updating dependencies..." 6 | ./scripts/update.sh 7 | go mod vendor 8 | 9 | echo "Generating cached schemas..." 10 | ./scripts/cache-schemas.sh internal/aws/cfn/schemas 11 | 12 | echo "Generating docs..." 13 | go generate ./... 14 | 15 | echo "Running tests..." 16 | ./scripts/integ.sh 17 | 18 | echo "Finished. Don't forget to update internal/config/version.go" 19 | 20 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/merge-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | X: 3 | Type: Object 4 | Y: 5 | Type: Object 6 | XX: 7 | Type: List 8 | YY: 9 | Type: List 10 | Resources: 11 | Bar: 12 | Type: A::B::C 13 | Properties: 14 | Merged: 15 | Fn::Merge: 16 | - !Ref X 17 | - !Ref Y 18 | Lists: 19 | Fn::Merge: 20 | - !Ref XX 21 | - !Ref YY 22 | - !Ref YY 23 | 24 | -------------------------------------------------------------------------------- /internal/cmd/build/nobell.go: -------------------------------------------------------------------------------- 1 | package build 2 | 3 | import "github.com/chzyer/readline" 4 | 5 | type noBellStdout struct{} 6 | 7 | func (n *noBellStdout) Write(p []byte) (int, error) { 8 | if len(p) == 1 && p[0] == readline.CharBell { 9 | return 0, nil 10 | } 11 | return readline.Stdout.Write(p) 12 | } 13 | 14 | func (n *noBellStdout) Close() error { 15 | return readline.Stdout.Close() 16 | } 17 | 18 | var NoBellStdout = &noBellStdout{} 19 | -------------------------------------------------------------------------------- /test/templates/schedule-off.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | Schedule: 3 | Type: AWS::Scheduler::Schedule 4 | Properties: 5 | GroupName: !Ref ScheduleGroupName 6 | ScheduleExpression: rate(5 minutes) 7 | ScheduleExpressionTimezone: Europe/Berlin 8 | FlexibleTimeWindow: 9 | Mode: "OFF" 10 | State: ENABLED 11 | Target: 12 | Arn: !GetAtt LambdaFunction.Arn 13 | RoleArn: !GetAtt ScheduleRole.Arn 14 | -------------------------------------------------------------------------------- /.pre-commit-hooks.yaml: -------------------------------------------------------------------------------- 1 | - id: rain-format 2 | name: rain format 3 | description: Format AWS CloudFormation templates 4 | entry: rain 5 | language: golang 6 | files: \.(yml|yaml|json)$ 7 | args: ["fmt", "-w"] 8 | 9 | - id: rain-verify 10 | name: rain verify 11 | description: Verify AWS CloudFormation templates formatting without modifying files 12 | entry: rain 13 | language: golang 14 | files: \.(yml|yaml|json)$ 15 | args: ["fmt", "-v"] 16 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/many-template.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | My1: 3 | Type: !Rain::Module "./many-module.yaml" 4 | Properties: 5 | Name: foo1 6 | My2: 7 | Type: !Rain::Module "./many-module.yaml" 8 | Properties: 9 | Name: foo2 10 | My3: 11 | Type: !Rain::Module "./many-module.yaml" 12 | Properties: 13 | Name: foo3 14 | My4: 15 | Type: !Rain::Module "./many-module.yaml" 16 | Properties: 17 | Name: foo4 18 | 19 | -------------------------------------------------------------------------------- /cft/graph/graph.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | 3 | N: 4 | Type: String 5 | Default: "A" 6 | 7 | Resources: 8 | 9 | A: 10 | Type: AWS::S3::Bucket 11 | DependsOn: B 12 | Properties: 13 | BucketName: !Ref N 14 | 15 | B: 16 | Type: AWS::S3::Bucket 17 | 18 | C: 19 | Type: AWS::S3::Bucket 20 | DependsOn: [B, D] 21 | 22 | D: 23 | Type: AWS::S3::Bucket 24 | DependsOn: E 25 | 26 | E: 27 | Type: AWS::S3::Bucket 28 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/foreach-module.yaml: -------------------------------------------------------------------------------- 1 | Transform: AWS::LanguageExtensions 2 | 3 | Parameters: 4 | Handles: 5 | Type: CommaDelimitedList 6 | Default: A,B,C 7 | 8 | Resources: 9 | 10 | Fn::ForEach::MakeHandles: 11 | - HandleName 12 | - !Ref Handles 13 | - "ModuleExtension${HandleName}": 14 | Metadata: 15 | Comment: !Sub "This is wait handle ${HandleName}" 16 | Extends: AWS::CloudFormation::WaitConditionHandle 17 | 18 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/ref-false-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Name: 3 | Type: String 4 | B: 5 | Type: Boolean 6 | Resources: 7 | Bucket1: 8 | Type: AWS::S3::Bucket 9 | Properties: 10 | BucketName: !Ref Name 11 | Parent: 12 | - Child: 13 | ShouldBeFalse: !Ref B 14 | - OtherChild: !Ref B 15 | - Subs: 16 | - !Sub "b0${B}" 17 | - !Sub "b1${B}" 18 | Bucket2: 19 | Type: AWS::S3::Bucket 20 | 21 | -------------------------------------------------------------------------------- /test/pkl/directive.json: -------------------------------------------------------------------------------- 1 | { 2 | "Resources": { 3 | "Func": { 4 | "Type": "AWS::Lambda::Function", 5 | "Properties": { 6 | "Code": { 7 | "Rain::S3": { 8 | "Path": ".", 9 | "KeyProperty": "S3Key", 10 | "BucketProperty": "S3Bucket" 11 | } 12 | } 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/templates/graph.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | 3 | N: 4 | Type: String 5 | Default: "A" 6 | 7 | Resources: 8 | 9 | A: 10 | Type: AWS::S3::Bucket 11 | DependsOn: B 12 | Properties: 13 | BucketName: !Ref N 14 | 15 | B: 16 | Type: AWS::S3::Bucket 17 | 18 | C: 19 | Type: AWS::S3::Bucket 20 | DependsOn: [B, D] 21 | 22 | D: 23 | Type: AWS::S3::Bucket 24 | DependsOn: E 25 | 26 | E: 27 | Type: AWS::S3::Bucket 28 | -------------------------------------------------------------------------------- /test/templates/reuse-param.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | LogName: 3 | Type: String 4 | Query: 5 | Type: String 6 | Default: "fields @message" 7 | Resources: 8 | Log: 9 | Type: AWS::Logs::LogGroup 10 | Properties: 11 | LogGroupName: !Ref LogName 12 | Query1: 13 | Type: AWS::Logs::QueryDefinition 14 | Properties: 15 | Name: Query1 16 | QueryString: !Ref Query 17 | LogGroupNames: 18 | - !Ref LogName 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/templates/bucket.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | AppName: 3 | Description: This name be used as a prefix for resource names 4 | Type: String 5 | 6 | Resources: 7 | ObjectStorageBucket: 8 | Type: AWS::S3::Bucket 9 | Properties: 10 | BucketEncryption: 11 | ServerSideEncryptionConfiguration: 12 | - ServerSideEncryptionByDefault: 13 | SSEAlgorithm: AES256 14 | BucketName: !Sub ${AppName}-${AWS::Region}-${AWS::AccountId} 15 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/outjoin-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Name: 3 | Type: String 4 | Resources: 5 | Bucket: 6 | Type: AWS::S3::Bucket 7 | Properties: 8 | BucketName: !Ref Name 9 | Outputs: 10 | JoinTest: 11 | Value: 12 | Fn::Join: 13 | - "-" 14 | - - !Ref Bucket 15 | - !GetAtt Bucket.Arn 16 | ScalarTest: 17 | Value: 18 | Fn::Join: 19 | - "-" 20 | - - !Ref Name 21 | - xyz 22 | 23 | -------------------------------------------------------------------------------- /internal/aws/cfn/schemas/aws/sdb/domain.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeName": "AWS::SDB::Domain", 3 | "description": "Resource Type definition for AWS::SDB::Domain", 4 | "additionalProperties": false, 5 | "properties": { 6 | "Id": { 7 | "type": "string" 8 | }, 9 | "Description": { 10 | "type": "string" 11 | } 12 | }, 13 | "primaryIdentifier": [ 14 | "/properties/Id" 15 | ], 16 | "readOnlyProperties": [ 17 | "/properties/Id" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /test/templates/nested.template: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | 3 | Description: Nested stack! 4 | 5 | Resources: 6 | SuccessStack: 7 | Type: AWS::CloudFormation::Stack 8 | Properties: 9 | Parameters: 10 | BucketName: !Ref AWS::StackName 11 | TemplateURL: success.template 12 | 13 | Outputs: 14 | StackName: 15 | Description: The name of the stack 16 | Value: !Ref SuccessStack 17 | Export: 18 | Name: SuccessStackName 19 | -------------------------------------------------------------------------------- /test/webapp/site/js/containers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Show and hide top level containers. 3 | * 4 | * @param name - The container to show. Hide the others. 5 | */ 6 | export function showHide(name) { 7 | const containers = ["grid", "canvas", "expand", "parts"] 8 | for (const c of containers) { 9 | document.getElementById(c + "-container").style.display = (name === c) ? "block" : "none" 10 | } 11 | document.getElementById("props").style.display = "none" 12 | } 13 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/sub-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | MyBucket1: 3 | Type: AWS::S3::Bucket 4 | Properties: 5 | BucketName: foo 6 | X: !Sub ${Foo} 7 | Y: 8 | - !Sub noparent0-${Foo} 9 | - !Sub noparent1-${Foo} 10 | Z: 11 | - !Sub ${Foo} 12 | - !Ref MyBucket2 13 | - ZZ: 14 | ZZZ: 15 | ZZZZ: !Sub ${Foo} 16 | MyBucket2: 17 | Type: AWS::S3::Bucket 18 | Properties: 19 | BucketName: bar 20 | -------------------------------------------------------------------------------- /internal/aws/cfn/schemas/aws/cloudformation/waitconditionhandle.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeName": "AWS::CloudFormation::WaitConditionHandle", 3 | "description": "Resource Type definition for AWS::CloudFormation::WaitConditionHandle", 4 | "additionalProperties": false, 5 | "properties": { 6 | "Id": { 7 | "type": "string" 8 | } 9 | }, 10 | "primaryIdentifier": [ 11 | "/properties/Id" 12 | ], 13 | "readOnlyProperties": [ 14 | "/properties/Id" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/policy-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | AccessPolicy: 3 | Type: AWS::IAM::RolePolicy 4 | Properties: 5 | PolicyDocument: 6 | Statement: 7 | - Effect: ALLOW 8 | Action: s3:List* 9 | Resource: 10 | - arn:aws:s3:::foo 11 | - arn:aws:s3:::foo/* 12 | - Effect: DENY 13 | Action: s3:Put* 14 | Resource: arn:aws:s3:::bar 15 | PolicyName: my-policy 16 | RoleName: foo 17 | -------------------------------------------------------------------------------- /test/templates/ccdeploy2.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | A: 3 | Type: AWS::SQS::Queue 4 | Metadata: 5 | Comment: A1 6 | Properties: 7 | DelaySeconds: 2 8 | QueueName: ccdeploy-a 9 | 10 | B: 11 | Type: AWS::SQS::Queue 12 | DependsOn: A 13 | Metadata: 14 | Comment: B1 15 | Properties: 16 | QueueName: ccdeploy-b 17 | 18 | D: 19 | Type: AWS::SQS::Queue 20 | Properties: 21 | QueueName: ccdeploy-d 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /test/pkl/directive-basic.pkl: -------------------------------------------------------------------------------- 1 | amends "@cfn/template.pkl" 2 | import "@cfn/cloudformation.pkl" as cfn 3 | 4 | Resources { 5 | ["Func"] { 6 | ["Type"] = "AWS::Lambda::Function" 7 | ["Properties"] { 8 | ["Code"] { 9 | ["Rain::S3"] { 10 | ["Path"] = "." 11 | ["KeyProperty"] = "S3Key" 12 | ["BucketProperty"] = "S3Bucket" 13 | } 14 | } 15 | } 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/anchors.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | MyLambda: 3 | Type: AWS::Lambda::Function 4 | Properties: 5 | Code: &code 6 | ZipFile: "print(\"Hello World!\")\n" 7 | FunctionName: my-lambda 8 | Handler: index.lambda_handler 9 | Role: !ImportValue 'MyLambdaRoleArn' 10 | Runtime: python3.8 11 | Tags: 12 | - Key: foo 13 | Value: &fooval myval 14 | - Key: bar 15 | Value: *fooval 16 | Metadata: 17 | Comment: *code 18 | 19 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/basic-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | OtherResource: 3 | Type: AWS::S3::Bucket 4 | Metadata: 5 | TestOutputSub: 6 | Fn::Sub: ${ContentBucket} 7 | ContentBucket: 8 | Type: AWS::S3::Bucket 9 | Properties: 10 | BucketName: foo 11 | OverrideMe: def 12 | SubName: foo 13 | ContentBucket2: 14 | Type: AWS::S3::Bucket 15 | Properties: 16 | BucketName: 17 | Fn::GetAtt: 18 | - ContentBucket 19 | - Something 20 | -------------------------------------------------------------------------------- /scripts/gen-one-pkl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eou pipefail 4 | 5 | # Create a directory for the pkl class based on the resource name 6 | dn=$(echo "$1" | awk -F '::' '/^AWS/ {print "pkl/" tolower($1) "/" tolower($2) }') 7 | mkdir -p "$dn" 8 | 9 | # The pkl class filename 10 | fn=$(echo "$1" | awk -F '::' '/^AWS/ {print "pkl/" tolower($1) "/" tolower($2) "/" tolower($3) ".pkl"}') 11 | 12 | echo "${1}" 13 | 14 | ./rain build --pkl-class $1 > ${fn} || exit 255 15 | 16 | pkl eval ${fn} || exit 255 17 | 18 | -------------------------------------------------------------------------------- /test/webapp/buildapi.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eou pipefail 4 | 5 | SCRIPT_DIR=$(dirname "$0") 6 | echo "SCRIPT_DIR: ${SCRIPT_DIR}" 7 | cd $SCRIPT_DIR 8 | 9 | function build() { 10 | echo "Building $1..." 11 | cd ../$1 12 | staticcheck . 13 | go vet . 14 | GOOS=linux GOARCH=amd64 go build -o bootstrap main.go 15 | mkdir -p ../../dist/$1 16 | zip ../../dist/$1/lambda-handler.zip bootstrap 17 | } 18 | 19 | cd api/resources/test 20 | 21 | build test 22 | build jwt 23 | 24 | 25 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/api-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | 3 | MethGet: 4 | Type: AWS::ApiGateway::Method 5 | Properties: 6 | HttpMethod: GET 7 | ResourceId: !Ref Resource 8 | RestApiId: !Ref RestApi 9 | AuthorizationType: NONE 10 | AuthorizerId: !Ref AuthorizerId 11 | Integration: 12 | IntegrationHttpMethod: POST 13 | Type: AWS_PROXY 14 | Uri: !Sub "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Handler.Arn}/invocations" 15 | -------------------------------------------------------------------------------- /test/templates/anchors.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | MyLambda: 3 | Type: AWS::Lambda::Function 4 | Properties: 5 | Code: &code 6 | ZipFile: "print(\"Hello World!\")\n" 7 | FunctionName: my-lambda 8 | Handler: index.lambda_handler 9 | Role: !ImportValue 'MyLambdaRoleArn' 10 | Runtime: python3.8 11 | Tags: 12 | - Key: foo 13 | Value: &fooval myval 14 | - Key: bar 15 | Value: *fooval 16 | - Key: baz 17 | Value: *code 18 | 19 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/api-module.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | 3 | Get: 4 | Type: AWS::ApiGateway::Method 5 | Properties: 6 | HttpMethod: GET 7 | ResourceId: !Ref Resource 8 | RestApiId: !Ref RestApi 9 | AuthorizationType: COGNITO_USER_POOLS 10 | AuthorizerId: !Ref AuthorizerId 11 | Integration: 12 | IntegrationHttpMethod: POST 13 | Type: AWS_PROXY 14 | Uri: !Sub "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Handler.Arn}/invocations" 15 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/s3-in-module-module.yaml: -------------------------------------------------------------------------------- 1 | Description: A module for lambda 2 | 3 | Parameters: 4 | SourceDir: 5 | Type: String 6 | 7 | Resources: 8 | ModuleExtension: 9 | Metadata: 10 | Extends: AWS::Lambda::Function 11 | Properties: 12 | Runtime: python3.9 13 | Handler: index.handler 14 | ReservedConcurrentExecutions: 100 15 | Code: !Rain::S3 16 | Path: !Ref SourceDir 17 | Zip: true 18 | BucketProperty: S3Bucket 19 | KeyProperty: S3Key 20 | 21 | -------------------------------------------------------------------------------- /test/templates/fmtziplines.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | 3 | Description: Example AWS CloudFormation template snippet. 4 | 5 | Resources: 6 | Test: 7 | Type: AWS::Lambda::Function 8 | Properties: 9 | Role: arn:aws:iam::755952356119:role/lambda-basic 10 | Runtime: python3.7 11 | Handler: index.handler 12 | Code: 13 | ZipFile: | 14 | import boto3 15 | 16 | def handler: 17 | 18 | """Example.""" 19 | 20 | print('hello') 21 | -------------------------------------------------------------------------------- /test/templates/ccdeploy.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | A: 3 | Type: AWS::SQS::Queue 4 | Metadata: 5 | Comment: A1 6 | Properties: 7 | DelaySeconds: 1 8 | MessageRetentionPeriod: 200000 9 | QueueName: ccdeploy-a 10 | 11 | B: 12 | Type: AWS::SQS::Queue 13 | DependsOn: A 14 | Metadata: 15 | Comment: B1 16 | Properties: 17 | QueueName: ccdeploy-b 18 | 19 | 20 | C: 21 | Type: AWS::SQS::Queue 22 | Properties: 23 | QueueName: ccdeploy-c 24 | 25 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/policy-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Role: 3 | Type: String 4 | BucketName: 5 | Default: foo 6 | Resources: 7 | Policy: 8 | Type: AWS::IAM::RolePolicy 9 | Properties: 10 | PolicyDocument: 11 | Statement: 12 | - Effect: ALLOW 13 | Action: s3:List* 14 | Resource: 15 | - !Sub arn:aws:s3:::${BucketName} 16 | - !Sub arn:aws:s3:::${BucketName}/* 17 | PolicyName: my-policy 18 | RoleName: !Ref Role 19 | 20 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/s3-template.yaml: -------------------------------------------------------------------------------- 1 | Packages: 2 | abc: 3 | Source: s3://ezbeard-awscli/modules/package.zip 4 | Constants: 5 | ModuleSource: s3://ezbeard-awscli/modules 6 | Modules: 7 | Content: 8 | Source: !Sub ${Const::ModuleSource}/basic-module.yaml 9 | Properties: 10 | Name: foo 11 | Overrides: 12 | Bucket: 13 | Properties: 14 | OverrideMe: def 15 | TestPackage: 16 | Source: $abc/zip-module.yaml 17 | Resources: 18 | OtherResource: 19 | Type: AWS::S3::Bucket 20 | -------------------------------------------------------------------------------- /internal/cmd/forecast/ec2_launchtemplate.go: -------------------------------------------------------------------------------- 1 | package forecast 2 | 3 | import fc "github.com/aws-cloudformation/rain/plugins/forecast" 4 | 5 | // AWS::EC2::LaunchTemplate 6 | 7 | func CheckEC2LaunchTemplate(input fc.PredictionInput) fc.Forecast { 8 | 9 | forecast := fc.MakeForecast(&input) 10 | 11 | // Check to see if the key name exists 12 | checkKeyName(&input, &forecast) 13 | 14 | // Make sure the AMI and the instance type are compatible 15 | checkInstanceType(&input, &forecast) 16 | 17 | return forecast 18 | 19 | } 20 | -------------------------------------------------------------------------------- /test/pkl/PklProject.deps.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "resolvedDependencies": { 4 | "package://github.com/aws-cloudformation/cloudformation-pkl/releases/download/cloudformation@0.1.4/cloudformation@0": { 5 | "type": "remote", 6 | "uri": "projectpackage://github.com/aws-cloudformation/cloudformation-pkl/releases/download/cloudformation@0.1.4/cloudformation@0.1.4", 7 | "checksums": { 8 | "sha256": "d235477833d6b941ad255f5a94e061c7b987742ab1e703abaaf6d1980694f3b5" 9 | } 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /cft/pkg/tmpl/anchors-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | MyLambda: 3 | Type: AWS::Lambda::Function 4 | Properties: 5 | Code: 6 | ZipFile: "print(\"Hello World!\")\n" 7 | FunctionName: my-lambda 8 | Handler: index.lambda_handler 9 | Role: !ImportValue 'MyLambdaRoleArn' 10 | Runtime: python3.8 11 | Tags: 12 | - Key: foo 13 | Value: myval 14 | - Key: bar 15 | Value: myval 16 | Metadata: 17 | Comment: 18 | ZipFile: "print(\"Hello World!\")\n" 19 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/sub-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | MyBucket1: 3 | Type: AWS::S3::Bucket 4 | Properties: 5 | BucketName: foo 6 | X: 7 | Fn::Sub: ${Foo} 8 | Y: 9 | - Fn::Sub: noparent0-${Foo} 10 | - Fn::Sub: noparent1-${Foo} 11 | Z: 12 | - Fn::Sub: ${Foo} 13 | - Ref: MyBucket2 14 | - ZZ: 15 | ZZZ: 16 | ZZZZ: 17 | Fn::Sub: ${Foo} 18 | MyBucket2: 19 | Type: AWS::S3::Bucket 20 | Properties: 21 | BucketName: bar 22 | -------------------------------------------------------------------------------- /test/templates/fmtziplinesfolded.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | 3 | Description: Example AWS CloudFormation template snippet. 4 | 5 | Resources: 6 | Test: 7 | Type: AWS::Lambda::Function 8 | Properties: 9 | Role: arn:aws:iam::755952356119:role/lambda-basic 10 | Runtime: python3.7 11 | Handler: index.handler 12 | Code: 13 | ZipFile: > 14 | import boto3 15 | 16 | def handler: 17 | 18 | """Example.""" 19 | 20 | print('hello') 21 | 22 | -------------------------------------------------------------------------------- /test/webapp/PklProject.deps.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "resolvedDependencies": { 4 | "package://github.com/aws-cloudformation/cloudformation-pkl/releases/download/cloudformation@0.1.4/cloudformation@0": { 5 | "type": "remote", 6 | "uri": "projectpackage://github.com/aws-cloudformation/cloudformation-pkl/releases/download/cloudformation@0.1.4/cloudformation@0.1.4", 7 | "checksums": { 8 | "sha256": "d235477833d6b941ad255f5a94e061c7b987742ab1e703abaaf6d1980694f3b5" 9 | } 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/foreach-template.yaml: -------------------------------------------------------------------------------- 1 | Modules: 2 | Fn::ForEach::A: 3 | - TheKey 4 | - A,B,C 5 | - A: 6 | Source: foreach-module.yaml 7 | Properties: 8 | Name: a-${TheKey} 9 | Fn::ForEach::B: 10 | - TheKey 11 | - A,B,C 12 | - B&{TheKey}: 13 | Source: foreach-module.yaml 14 | Properties: 15 | Name: b-${TheKey} 16 | Outputs: 17 | TestGetAttA: 18 | Value: !GetAtt A[0].Out1 19 | TestGetAttB: 20 | Value: !GetAtt B[B].Out1 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /internal/cmd/info/info_test.go: -------------------------------------------------------------------------------- 1 | package info_test 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/aws-cloudformation/rain/internal/cmd/info" 7 | ) 8 | 9 | func Example_info_help() { 10 | os.Args = []string{ 11 | os.Args[0], 12 | "--help", 13 | } 14 | 15 | info.Cmd.Execute() 16 | // Output: 17 | // Display the AWS account and region that you're configured to use. 18 | // 19 | // Usage: 20 | // info 21 | // 22 | // Flags: 23 | // -c, --creds include current AWS credentials 24 | // -h, --help help for info 25 | } 26 | -------------------------------------------------------------------------------- /test/pkl/modules/PklProject.deps.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "resolvedDependencies": { 4 | "package://github.com/aws-cloudformation/cloudformation-pkl/releases/download/cloudformation@0.1.4/cloudformation@0": { 5 | "type": "remote", 6 | "uri": "projectpackage://github.com/aws-cloudformation/cloudformation-pkl/releases/download/cloudformation@0.1.4/cloudformation@0.1.4", 7 | "checksums": { 8 | "sha256": "d235477833d6b941ad255f5a94e061c7b987742ab1e703abaaf6d1980694f3b5" 9 | } 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /cft/pkg/tmpl/sub-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Name: 3 | Type: String 4 | SubName: 5 | Type: String 6 | Resources: 7 | Bucket1: 8 | Type: AWS::S3::Bucket 9 | Properties: 10 | BucketName: !Sub ${Name} 11 | X: !Sub "${SubName}" 12 | Y: 13 | - !Sub noparent0-${SubName} 14 | - !Sub noparent1-${SubName} 15 | Z: 16 | - !Ref SubName 17 | - !Ref Bucket2 18 | - ZZ: 19 | ZZZ: 20 | ZZZZ: !Sub "${SubName}" 21 | Bucket2: 22 | Type: AWS::S3::Bucket 23 | 24 | -------------------------------------------------------------------------------- /modules/encrypted-bucket.yaml: -------------------------------------------------------------------------------- 1 | Description: A simple S3 bucket with encryption enabled and public access blocked 2 | 3 | Resources: 4 | 5 | Bucket: 6 | Type: AWS::S3::Bucket 7 | Properties: 8 | BucketEncryption: 9 | ServerSideEncryptionConfiguration: 10 | - ServerSideEncryptionByDefault: 11 | SSEAlgorithm: AES256 12 | PublicAccessBlockConfiguration: 13 | BlockPublicAcls: true 14 | BlockPublicPolicy: true 15 | IgnorePublicAcls: true 16 | RestrictPublicBuckets: true 17 | 18 | -------------------------------------------------------------------------------- /internal/aws/cfn/stack_test.go: -------------------------------------------------------------------------------- 1 | package cfn_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/aws-cloudformation/rain/internal/aws/cfn" 7 | ) 8 | 9 | func TestStatusIsSettled(t *testing.T) { 10 | for input, expected := range map[string]bool{ 11 | "STACK_COMPLETE": true, 12 | "STACK_FAILED": true, 13 | "SOMETHING_COMPLETE": true, 14 | "SOMETHING_FAILED": true, 15 | "COMPLETE_STACK": false, 16 | "FAILED_STACK": false, 17 | } { 18 | if cfn.StatusIsSettled(input) != expected { 19 | t.Fail() 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/sub-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Name: 3 | Type: String 4 | SubName: 5 | Type: String 6 | Resources: 7 | Bucket1: 8 | Type: AWS::S3::Bucket 9 | Properties: 10 | BucketName: !Sub ${Name} 11 | X: !Sub "${SubName}" 12 | Y: 13 | - !Sub noparent0-${SubName} 14 | - !Sub noparent1-${SubName} 15 | Z: 16 | - !Ref SubName 17 | - !Ref Bucket2 18 | - ZZ: 19 | ZZZ: 20 | ZZZZ: !Sub "${SubName}" 21 | Bucket2: 22 | Type: AWS::S3::Bucket 23 | 24 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/same-mod-expect.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | X: 3 | Type: String 4 | Default: default-x 5 | Resources: 6 | AABC: 7 | Type: A::B::C 8 | Properties: 9 | Name: !Ref X 10 | SubName: !Sub ${X}-name 11 | ADEFHIJ: 12 | Type: H::I::J 13 | Properties: 14 | Name: !Sub ${X}-def 15 | SubName: !Sub ${X}-def-hij 16 | BABC: 17 | Type: A::B::C 18 | Properties: 19 | Name: x 20 | SubName: x-name 21 | BDEFHIJ: 22 | Type: H::I::J 23 | Properties: 24 | Name: x-def 25 | SubName: x-def-hij 26 | 27 | -------------------------------------------------------------------------------- /internal/aws/cfn/schemas/aws/ses/receiptruleset.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeName": "AWS::SES::ReceiptRuleSet", 3 | "description": "Resource Type definition for AWS::SES::ReceiptRuleSet", 4 | "additionalProperties": false, 5 | "properties": { 6 | "Id": { 7 | "type": "string" 8 | }, 9 | "RuleSetName": { 10 | "type": "string" 11 | } 12 | }, 13 | "createOnlyProperties": [ 14 | "/properties/RuleSetName" 15 | ], 16 | "primaryIdentifier": [ 17 | "/properties/Id" 18 | ], 19 | "readOnlyProperties": [ 20 | "/properties/Id" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/constant2-expect.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Prefix: 3 | Type: String 4 | 5 | Resources: 6 | Bucket: 7 | Type: AWS::S3::Bucket 8 | Properties: 9 | BucketName: ezbeard-rain-test-constants 10 | Bucket2: 11 | Type: AWS::S3::Bucket 12 | Properties: 13 | BucketName: !Sub ${Prefix}-ezbeard-rain-test-constants-SubTest 14 | Bucket3: 15 | Type: AWS::S3::Bucket 16 | Properties: 17 | BucketName: !Sub pre-${Prefix}-ezbeard-rain-test-constants-suffix 18 | Foo: ezbeard-rain-test-constants 19 | Bar: ${!leavemealone} 20 | 21 | -------------------------------------------------------------------------------- /internal/cmd/forecast/launch_config.go: -------------------------------------------------------------------------------- 1 | package forecast 2 | 3 | import ( 4 | "github.com/aws-cloudformation/rain/internal/config" 5 | fc "github.com/aws-cloudformation/rain/plugins/forecast" 6 | ) 7 | 8 | // AWS::AutoScaling::LaunchConfiguration 9 | 10 | func CheckAutoScalingLaunchConfiguration(input fc.PredictionInput) fc.Forecast { 11 | 12 | forecast := fc.MakeForecast(&input) 13 | 14 | config.Debugf("About to check key name for launch config") 15 | 16 | // Check to see if the key name exists 17 | checkKeyName(&input, &forecast) 18 | 19 | return forecast 20 | 21 | } 22 | -------------------------------------------------------------------------------- /test/pkl/directive.pkl: -------------------------------------------------------------------------------- 1 | amends "@cfn/template.pkl" 2 | import "@cfn/cloudformation.pkl" as cfn 3 | import "./function.pkl" as func 4 | 5 | Parameters { 6 | ["RoleArn"] { 7 | Type = "String" 8 | } 9 | } 10 | 11 | Resources { 12 | ["Func"] = new func.Function { 13 | Role = cfn.Ref("RoleArn") 14 | Runtime = "nodejs20x" 15 | Code { 16 | Rain__S3 { 17 | Path = "." 18 | KeyProperty = "S3Key" 19 | BucketProperty = "S3Bucket" 20 | } 21 | } 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /test/webapp/site/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import globals from "globals"; 2 | import pluginJs from "@eslint/js"; 3 | import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'; 4 | 5 | 6 | export default [ 7 | { 8 | languageOptions: { 9 | globals: globals.browser 10 | } 11 | }, 12 | pluginJs.configs.recommended, 13 | { 14 | ignores: ["dist", "config-sample.js", "js/vendor"] 15 | }, 16 | { 17 | plugins: { 18 | "prettier": eslintPluginPrettierRecommended 19 | } 20 | } 21 | ]; 22 | -------------------------------------------------------------------------------- /internal/cmd/forecast/codes.go: -------------------------------------------------------------------------------- 1 | package forecast 2 | 3 | const ( 4 | FG001 = "FG001" 5 | FG002 = "FG002" 6 | F0001 = "F0001" 7 | F0002 = "F0002" 8 | F0003 = "F0003" 9 | F0004 = "F0004" 10 | F0005 = "F0005" 11 | F0006 = "F0006" 12 | F0007 = "F0007" 13 | F0008 = "F0008" 14 | F0009 = "F0009" 15 | F0010 = "F0010" 16 | F0011 = "F0011" 17 | F0012 = "F0012" 18 | F0013 = "F0013" 19 | F0014 = "F0014" 20 | F0015 = "F0015" 21 | F0016 = "F0016" 22 | F0017 = "F0017" 23 | F0018 = "F0018" 24 | F0019 = "F0019" 25 | F0020 = "F0020" 26 | F0021 = "F0021" 27 | F0022 = "F0022" 28 | ) 29 | -------------------------------------------------------------------------------- /test/templates/fmtfindinmap.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | 3 | Description: Reproduce "semantic difference after formatting" error 4 | 5 | Parameters: 6 | EnvironmentParam: 7 | Default: dev 8 | Type: String 9 | AllowedValues: 10 | - dev 11 | - prod 12 | 13 | Mappings: 14 | EnvironmentMap: 15 | MappedParam: 16 | dev: my-dev-topic 17 | prod: my-prod-topic 18 | 19 | Resources: 20 | Topic: 21 | Type: AWS::SNS::Topic 22 | Properties: 23 | TopicName: !FindInMap [ EnvironmentMap, MappedParam, !Ref EnvironmentParam ] 24 | 25 | -------------------------------------------------------------------------------- /test/templates/format-test.yaml: -------------------------------------------------------------------------------- 1 | Outputs: 2 | Bucket1: 3 | Value: !GetAtt Bucket1.Arn # Short GetAtt 4 | Bucket2: # Bucket comment 5 | Value: 6 | Fn::GetAtt: # GetAtt comment 7 | - Bucket2 8 | - Arn # Arn comment 9 | 10 | # Multiline comment 11 | # starting at indent 0 12 | Resources: 13 | Bucket2: 14 | Properties: 15 | BucketName: !Ref Name # Ref: comment 16 | Type: "AWS::S3::Bucket" 17 | Bucket1: 18 | Type: AWS::S3::Bucket 19 | Properties: 20 | BucketName: !Sub ${Bucket2}-newer 21 | Parameters: 22 | Name: 23 | Type: String 24 | 25 | -------------------------------------------------------------------------------- /internal/cmd/forecast/autoscaling.go: -------------------------------------------------------------------------------- 1 | package forecast 2 | 3 | /* TODO 4 | Resource handler returned message: 5 | The availability zones of the specified subnets and the 6 | Auto Scaling group do not match (Service: AutoScaling 7 | */ 8 | 9 | /* TODO 10 | Resource handler returned message: "Provided Target Group 11 | 'arn:aws:elasticloadbalancing:us-east-1:755952356119:targetgroup/MyTargetGroup/bd36b34c22052e00' 12 | has invalid target type. Please ensure all provided Target Groups have target 13 | type of instance. (Service: AutoScaling 14 | 15 | This should probably be a cfn-lint check instead. 16 | 17 | */ 18 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/same-mod-expect.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | X: 3 | Type: String 4 | Default: default-x 5 | 6 | Resources: 7 | AABC: 8 | Type: A::B::C 9 | Properties: 10 | Name: !Ref X 11 | SubName: !Sub ${X}-name 12 | 13 | ADEFHIJ: 14 | Type: H::I::J 15 | Properties: 16 | Name: !Sub ${X}-def 17 | SubName: !Sub ${X}-def-hij 18 | 19 | BABC: 20 | Type: A::B::C 21 | Properties: 22 | Name: x 23 | SubName: x-name 24 | 25 | BDEFHIJ: 26 | Type: H::I::J 27 | Properties: 28 | Name: x-def 29 | SubName: x-def-hij 30 | 31 | -------------------------------------------------------------------------------- /test/templates/intrinsic.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | LogName: 3 | Type: String 4 | Resources: 5 | Log: 6 | Type: AWS::Logs::LogGroup 7 | Properties: 8 | LogGroupName: !Ref LogName 9 | Query1: 10 | Type: AWS::Logs::QueryDefinition 11 | Properties: 12 | Name: Query1 13 | QueryString: "fields @message" 14 | LogGroupNames: 15 | - !Sub "${Log.LogGroupName}" 16 | Query2: 17 | Type: AWS::Logs::QueryDefinition 18 | Properties: 19 | Name: Query2 20 | QueryString: "fields @timestamp" 21 | LogGroupNames: 22 | - !Sub "${Log.LogGroupName}" 23 | 24 | 25 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/invoke-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | A: 3 | Type: D::E::F 4 | Properties: 5 | Name: test-myapp-prod 6 | Name2: test2-myapp-prod 7 | WithRegion: 8 | Fn::Join: 9 | - '-' 10 | - - test3 11 | - myapp 12 | - prod 13 | - Ref: AWS::Region 14 | B: 15 | Type: H::I::J 16 | Properties: 17 | X: x 18 | Y: yy 19 | Z: z 20 | C: 21 | Type: H::I::J 22 | Properties: 23 | X: x 24 | Y: y 25 | Z: zz 26 | LabelWhy: 27 | Type: X::Y::Z 28 | Properties: 29 | Id: ?-myapp-prod 30 | -------------------------------------------------------------------------------- /test/templates/forecast/forecast-ec2.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | 3 | Instance1: 4 | Type: AWS::EC2::Instance 5 | Properties: 6 | InstanceType: t3.micro 7 | SecurityGroups: [!Ref 'Instance1SecurityGroup'] 8 | KeyName: abc 9 | ImageId: "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2" 10 | 11 | Instance1SecurityGroup: 12 | Type: AWS::EC2::SecurityGroup 13 | Properties: 14 | GroupDescription: Enable SSH access via port 22 15 | SecurityGroupIngress: 16 | - IpProtocol: tcp 17 | FromPort: 22 18 | ToPort: 22 19 | CidrIp: 54.240.196.187/1 20 | 21 | -------------------------------------------------------------------------------- /test/templates/intrinsic2.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | LogName: 3 | Type: String 4 | Resources: 5 | Log: 6 | Type: AWS::Logs::LogGroup 7 | Properties: 8 | LogGroupName: !Ref LogName 9 | Query1: 10 | Type: AWS::Logs::QueryDefinition 11 | Properties: 12 | Name: Query1 13 | QueryString: "fields @timestamp, @message" 14 | LogGroupNames: 15 | - !Sub "${Log.LogGroupName}" 16 | Query3: 17 | Type: AWS::Logs::QueryDefinition 18 | Properties: 19 | Name: Query2 20 | QueryString: "fields @timestamp" 21 | LogGroupNames: 22 | - !Sub "${Log.LogGroupName}" 23 | 24 | 25 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/foreach-expect.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | A0Foo: 3 | Type: A::B::C 4 | Properties: 5 | Name: a-A 6 | A1Foo: 7 | Type: A::B::C 8 | Properties: 9 | Name: a-B 10 | A2Foo: 11 | Type: A::B::C 12 | Properties: 13 | Name: a-C 14 | BAFoo: 15 | Type: A::B::C 16 | Properties: 17 | Name: b-A 18 | BBFoo: 19 | Type: A::B::C 20 | Properties: 21 | Name: b-B 22 | BCFoo: 23 | Type: A::B::C 24 | Properties: 25 | Name: b-C 26 | Outputs: 27 | TestGetAttA: 28 | Value: !GetAtt A0Foo.Arn 29 | TestGetAttB: 30 | Value: !GetAtt BBFoo.Arn 31 | -------------------------------------------------------------------------------- /test/pkl/bucket.pkl: -------------------------------------------------------------------------------- 1 | amends "@cfn/template.pkl" 2 | import "@cfn/cloudformation.pkl" as cfn 3 | import "@cfn/aws/s3/bucket.pkl" 4 | 5 | Parameters { 6 | ["AppName"] = new cfn.Parameter { 7 | Type = "String" 8 | } 9 | } 10 | 11 | local a = "a" 12 | 13 | Resources { 14 | [a + "Bucket"] = new bucket.Bucket { 15 | BucketName = cfn.Sub("${AppName}-content") 16 | } 17 | ["Bucket2"] = new cfn.Resource { 18 | Type = "AWS::S3::Bucket" 19 | Properties { 20 | ["BucketName"] { 21 | ["Sub"] = "${AppName}-content2" 22 | } 23 | } 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /test/templates/fix-320.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | BackupPlanId: 3 | Type: String 4 | 5 | Resources: 6 | BackupSelection: 7 | Type: AWS::Backup::BackupSelection 8 | Properties: 9 | BackupPlanId: !Ref BackupPlanId 10 | BackupSelection: 11 | IamRoleArn: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AWSBackupDefaultServiceRole 12 | Resources: 13 | - !Sub arn:${AWS::Partition}:elasticfilesystem:${AWS::Region}:${AWS::AccountId}:file-system/${EfsFileSystem} 14 | SelectionName: !Sub ${AWS::StackName} 15 | 16 | EfsFileSystem: 17 | Type: AWS::EFS::FileSystem 18 | 19 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/modinmod-expect.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | ParentVal: 3 | Type: String 4 | pAppName: 5 | Type: String 6 | Resources: 7 | MySubBucket: 8 | Type: AWS::S3::Bucket 9 | Properties: 10 | BucketName: mod-in-mod-bucket 11 | XName: 12 | Fn::Sub: ${ParentVal}-abc 13 | YName: 14 | Fn::Sub: ${pAppName}-xyz 15 | MySubInDirBucket: 16 | Type: AWS::S3::Bucket 17 | Properties: 18 | BucketName: mod-in-mod-bucket 19 | XName: 20 | Fn::Sub: ${ParentVal}-abc 21 | YName: 22 | Fn::Sub: ${pAppName}-xyz 23 | MySubInDirSubSubZ: 24 | Type: A::B::C 25 | -------------------------------------------------------------------------------- /test/templates/prop-change.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | LogName: 3 | Type: String 4 | Resources: 5 | Log: 6 | Type: AWS::Logs::LogGroup 7 | Properties: 8 | LogGroupName: !Ref LogName 9 | Query1: 10 | Type: AWS::Logs::QueryDefinition 11 | Properties: 12 | Name: Query1 13 | QueryString: "fields @timestamp, @message | sort @timestamp desc | limit 20" 14 | LogGroupNames: 15 | - !Ref LogName 16 | Query2: 17 | Type: AWS::Logs::QueryDefinition 18 | Properties: 19 | Name: Query2 20 | QueryString: "fields @timestamp" 21 | LogGroupNames: 22 | - !Ref LogName 23 | 24 | 25 | -------------------------------------------------------------------------------- /test/templates/allowed-values.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | 3 | Description: A simple demo to reproduce the rain CLI tool issue with string parameters using WaitConditionHandle. 4 | 5 | Parameters: 6 | CreateThing: 7 | Description: Should this Thing be created? 8 | Type: String 9 | # ❌ - Broken Allowed Values 10 | AllowedValues: 11 | - Yes 12 | - No 13 | Default: No 14 | 15 | Conditions: 16 | ShouldCreateThing: !Equals 17 | - !Ref CreateThing 18 | - Yes 19 | 20 | Resources: 21 | Thing: 22 | Type: AWS::CloudFormation::WaitConditionHandle 23 | Condition: ShouldCreateThing 24 | 25 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/bucket-template.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | RainBucket: 3 | Type: !Rain::Module "./bucket-module.yaml" 4 | Properties: 5 | CreateLogBucket: true 6 | Overrides: 7 | Bucket: 8 | UpdateReplacePolicy: Delete 9 | Properties: 10 | VersioningConfiguration: 11 | Status: Enabled 12 | Tags: 13 | - Key: test-tag2 14 | Value: test-value2 15 | LogBucket: 16 | Properties: 17 | BucketName: test-module-log-bucket 18 | PublicAccessBlockConfiguration: 19 | BlockPublicAcls: false 20 | SomeNewThing: foo 21 | 22 | 23 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/constant2-template.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Prefix: 3 | Type: String 4 | 5 | Rain: 6 | Constants: 7 | Test1: ezbeard-rain-test-constants 8 | Test2: !Sub ${Prefix}-${Rain::Test1}-SubTest 9 | 10 | Resources: 11 | Bucket: 12 | Type: AWS::S3::Bucket 13 | Properties: 14 | BucketName: !Rain::Constant Test1 15 | Bucket2: 16 | Type: AWS::S3::Bucket 17 | Properties: 18 | BucketName: !Rain::Constant Test2 19 | Bucket3: 20 | Type: AWS::S3::Bucket 21 | Properties: 22 | BucketName: !Sub "pre-${Prefix}-${Rain::Test1}-suffix" 23 | Foo: !Sub ${Rain::Test1} 24 | Bar: !Sub ${!leavemealone} 25 | 26 | -------------------------------------------------------------------------------- /docs/rain_version.md: -------------------------------------------------------------------------------- 1 | ## rain version 2 | 3 | Display the installed version of rain 4 | 5 | ### Synopsis 6 | 7 | Display the installed version of rain 8 | 9 | ``` 10 | rain version 11 | ``` 12 | 13 | ### Options 14 | 15 | ``` 16 | -h, --help help for version 17 | ``` 18 | 19 | ### Options inherited from parent commands 20 | 21 | ``` 22 | --debug Output debugging information 23 | -p, --profile string AWS profile name; read from the AWS CLI configuration file 24 | -r, --region string AWS region to use 25 | ``` 26 | 27 | ### SEE ALSO 28 | 29 | * [rain](index.md) - 30 | 31 | ###### Auto generated by spf13/cobra on 7-Nov-2019 32 | -------------------------------------------------------------------------------- /internal/cmd/watch/watch_test.go: -------------------------------------------------------------------------------- 1 | package watch_test 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/aws-cloudformation/rain/internal/cmd/watch" 7 | ) 8 | 9 | func Example_watch_help() { 10 | os.Args = []string{ 11 | os.Args[0], 12 | "--help", 13 | } 14 | 15 | watch.Cmd.Execute() 16 | // Output: 17 | // Repeatedly displays the status of a CloudFormation stack. Useful for watching the progress of a deployment started from outside of Rain. 18 | // 19 | // Usage: 20 | // watch 21 | // 22 | // Flags: 23 | // -h, --help help for watch 24 | // -w, --wait wait for changes to begin rather than refusing to watch an unchanging stack 25 | } 26 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/mapout-template.yaml: -------------------------------------------------------------------------------- 1 | Modules: 2 | OutputTest: 3 | Source: ./map-output-module.yaml 4 | OutputTest2: 5 | Source: ./map-output-module.yaml 6 | ListTest: 7 | Source: ./map-list-module.yaml 8 | Properties: 9 | ListRef: 10 | - Arn1 11 | - Arn2 12 | Overrides: 13 | Bar: 14 | Properties: 15 | OutputOverride: !GetAtt OutputTest.BArns 16 | ListTest2: 17 | Source: ./map-list-module.yaml 18 | Properties: 19 | ListRef: 20 | - Arn3 21 | - Arn4 22 | Overrides: 23 | Bar: 24 | Properties: 25 | OutputOverride: !GetAtt OutputTest.BArns 26 | -------------------------------------------------------------------------------- /internal/aws/cfn/schemas/aws/appstream/stackfleetassociation.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeName": "AWS::AppStream::StackFleetAssociation", 3 | "description": "Resource Type definition for AWS::AppStream::StackFleetAssociation", 4 | "additionalProperties": false, 5 | "properties": { 6 | "Id": { 7 | "type": "string" 8 | }, 9 | "FleetName": { 10 | "type": "string" 11 | }, 12 | "StackName": { 13 | "type": "string" 14 | } 15 | }, 16 | "required": [ 17 | "FleetName", 18 | "StackName" 19 | ], 20 | "primaryIdentifier": [ 21 | "/properties/Id" 22 | ], 23 | "readOnlyProperties": [ 24 | "/properties/Id" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /test/templates/constants.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Prefix: 3 | Type: String 4 | 5 | Rain: 6 | Constants: 7 | Test1: ezbeard-rain-test-constants 8 | Test2: !Sub ${Prefix}-${Rain::Test1}-SubTest 9 | 10 | Resources: 11 | Bucket: 12 | Type: AWS::S3::Bucket 13 | Properties: 14 | BucketName: !Rain::Constant Test1 15 | 16 | Bucket2: 17 | Type: AWS::S3::Bucket 18 | Properties: 19 | BucketName: !Rain::Constant Test2 20 | 21 | Bucket3: 22 | Type: AWS::S3::Bucket 23 | Properties: 24 | BucketName: !Sub "pre-${Prefix}-${Rain::Test1}-suffix" 25 | Foo: !Sub ${Rain::Test1} 26 | Bar: !Sub ${!leavemealone} 27 | 28 | -------------------------------------------------------------------------------- /test/templates/null.yaml: -------------------------------------------------------------------------------- 1 | Conditions: 2 | NeverValid: !Equals [True, False] 3 | 4 | # Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod 5 | # tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 6 | # quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo 7 | # consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse 8 | # cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non 9 | # proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 10 | Resources: 11 | NullResource: 12 | Type: 'Custom::NullResource' 13 | Condition: NeverValid 14 | 15 | -------------------------------------------------------------------------------- /modules/bucket-policy.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | PolicyBucketName: 3 | Type: String 4 | Resources: 5 | Policy: 6 | Type: AWS::S3::BucketPolicy 7 | Properties: 8 | Bucket: !Ref PolicyBucketName 9 | PolicyDocument: 10 | Statement: 11 | - Action: s3:* 12 | Condition: 13 | Bool: 14 | aws:SecureTransport: false 15 | Effect: Deny 16 | Principal: 17 | AWS: '*' 18 | Resource: 19 | - !Sub "arn:${AWS::Partition}:s3:::${PolicyBucketName}" 20 | - !Sub "arn:${AWS::Partition}:s3:::${PolicyBucketName}/*" 21 | Version: "2012-10-17" 22 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/output-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | Name: 3 | Type: String 4 | Resources: 5 | Bucket: 6 | Type: AWS::S3::Bucket 7 | Properties: 8 | BucketName: !Ref Name 9 | Bucket2: 10 | Type: AWS::S3::Bucket 11 | Outputs: 12 | BucketArn: 13 | Value: !GetAtt Bucket.Arn 14 | BucketArnSub: 15 | Value: !Sub ${Bucket.Arn} 16 | BucketRef: 17 | Value: !Ref Bucket 18 | ArnList: 19 | Value: 20 | - !Sub ${Bucket.Arn} 21 | - !Sub ${Bucket2.Arn} 22 | - !Sub abc-${Name} 23 | JoinTest: 24 | Value: 25 | Fn::Join: 26 | - "-" 27 | - - !GetAtt Bucket.BucketName 28 | - !GetAtt Bucket.Arn 29 | 30 | -------------------------------------------------------------------------------- /test/webapp/site/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "lint": "eslint --fix", 9 | "build": "vite build" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "axios": "^1.7.7", 15 | "js-cookie": "^3.0.5", 16 | "vite": "^6.2.6" 17 | }, 18 | "devDependencies": { 19 | "@eslint/js": "^9.10.0", 20 | "eslint": "^9.10.0", 21 | "eslint-config-prettier": "^9.1.0", 22 | "eslint-plugin-prettier": "^5.2.1", 23 | "globals": "^15.9.0", 24 | "prettier": "^3.3.3" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /internal/aws/cfn/schemas/aws/pinpoint/voicechannel.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeName": "AWS::Pinpoint::VoiceChannel", 3 | "description": "Resource Type definition for AWS::Pinpoint::VoiceChannel", 4 | "additionalProperties": false, 5 | "properties": { 6 | "Id": { 7 | "type": "string" 8 | }, 9 | "Enabled": { 10 | "type": "boolean" 11 | }, 12 | "ApplicationId": { 13 | "type": "string" 14 | } 15 | }, 16 | "required": [ 17 | "ApplicationId" 18 | ], 19 | "createOnlyProperties": [ 20 | "/properties/ApplicationId" 21 | ], 22 | "primaryIdentifier": [ 23 | "/properties/Id" 24 | ], 25 | "readOnlyProperties": [ 26 | "/properties/Id" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /docs/rain_diff.md: -------------------------------------------------------------------------------- 1 | ## rain diff 2 | 3 | Compare CloudFormation templates 4 | 5 | ### Synopsis 6 | 7 | Outputs a summary of the changes necessary to transform the CloudFormation template named into the template named . 8 | 9 | ``` 10 | rain diff 11 | ``` 12 | 13 | ### Options 14 | 15 | ``` 16 | -h, --help help for diff 17 | -l, --long Include unchanged elements in diff output 18 | ``` 19 | 20 | ### Options inherited from parent commands 21 | 22 | ``` 23 | --debug Output debugging information 24 | --no-colour Disable colour output 25 | ``` 26 | 27 | ### SEE ALSO 28 | 29 | * [rain](index.md) - 30 | 31 | ###### Auto generated by spf13/cobra on 4-Jul-2025 32 | -------------------------------------------------------------------------------- /internal/aws/cfn/schemas/aws/opsworks/elasticloadbalancerattachment.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeName": "AWS::OpsWorks::ElasticLoadBalancerAttachment", 3 | "description": "Resource Type definition for AWS::OpsWorks::ElasticLoadBalancerAttachment", 4 | "additionalProperties": false, 5 | "properties": { 6 | "Id": { 7 | "type": "string" 8 | }, 9 | "ElasticLoadBalancerName": { 10 | "type": "string" 11 | }, 12 | "LayerId": { 13 | "type": "string" 14 | } 15 | }, 16 | "required": [ 17 | "LayerId", 18 | "ElasticLoadBalancerName" 19 | ], 20 | "primaryIdentifier": [ 21 | "/properties/Id" 22 | ], 23 | "readOnlyProperties": [ 24 | "/properties/Id" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | pull_request: 6 | branches: 7 | - main 8 | 9 | name: Unit tests 10 | 11 | env: 12 | GOFLAGS: "-buildvcs=false" 13 | 14 | jobs: 15 | test: 16 | name: Test 17 | runs-on: ubuntu-latest 18 | container: golang:latest 19 | steps: 20 | - name: Checkout code 21 | uses: actions/checkout@v2 22 | 23 | - name: Install dependencies 24 | run: | 25 | go install honnef.co/go/tools/cmd/staticcheck@latest 26 | 27 | - name: Lint 28 | run: | 29 | staticcheck ./... 30 | go vet ./... 31 | 32 | - name: Run unit tests 33 | run: go test ./... 34 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/cond-unres-module.yaml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | P: 3 | Type: String 4 | 5 | Conditions: 6 | IsRegionUsEast1: 7 | Fn::Equals: 8 | - Ref: AWS::Region 9 | - us-east-1 10 | IsPTrue: 11 | Fn::Equals: 12 | - !Ref P 13 | - true 14 | 15 | Modules: 16 | Sub: 17 | Source: cond-unres-submodule.yaml 18 | Properties: 19 | P: !Ref P 20 | 21 | Resources: 22 | S3Bucket: 23 | Type: AWS::S3::Bucket 24 | Condition: IsRegionUsEast1 25 | A: 26 | Type: A::B::C 27 | Properties: 28 | Name: 29 | Fn::If: 30 | - IsRegionUsEast1 31 | - a-east 32 | - a-not-east 33 | C: 34 | Type: D::E::F 35 | Condition: IsPTrue 36 | -------------------------------------------------------------------------------- /internal/aws/cfn/schemas/aws/dax/parametergroup.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeName": "AWS::DAX::ParameterGroup", 3 | "description": "Resource Type definition for AWS::DAX::ParameterGroup", 4 | "additionalProperties": false, 5 | "properties": { 6 | "ParameterNameValues": { 7 | "type": "object" 8 | }, 9 | "Description": { 10 | "type": "string" 11 | }, 12 | "Id": { 13 | "type": "string" 14 | }, 15 | "ParameterGroupName": { 16 | "type": "string" 17 | } 18 | }, 19 | "createOnlyProperties": [ 20 | "/properties/ParameterGroupName" 21 | ], 22 | "primaryIdentifier": [ 23 | "/properties/Id" 24 | ], 25 | "readOnlyProperties": [ 26 | "/properties/Id" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /plugins/deployconfig/deployconfig.go: -------------------------------------------------------------------------------- 1 | package deployconfig 2 | 3 | import "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" 4 | 5 | // DeployConfig represents the user-supplied configuration for a deployment 6 | // This is also used by the forecast command 7 | type DeployConfig struct { 8 | Params []types.Parameter 9 | Tags map[string]string 10 | } 11 | 12 | // GetParam gets the value of a supplied parameter 13 | func (dc DeployConfig) GetParam(name string) (string, bool) { 14 | for _, p := range dc.Params { 15 | if *p.ParameterKey == name { 16 | if p.ResolvedValue != nil { 17 | return *p.ResolvedValue, true 18 | } 19 | return *p.ParameterValue, true 20 | } 21 | } 22 | return "", false 23 | } 24 | -------------------------------------------------------------------------------- /internal/aws/cfn/schemas/aws/cloudformation/customresource.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeName": "AWS::CloudFormation::CustomResource", 3 | "description": "Resource Type definition for AWS::CloudFormation::CustomResource", 4 | "additionalProperties": false, 5 | "properties": { 6 | "ServiceToken": { 7 | "type": "string" 8 | }, 9 | "ServiceTimeout": { 10 | "type": "integer" 11 | }, 12 | "Id": { 13 | "type": "string" 14 | } 15 | }, 16 | "required": [ 17 | "ServiceToken" 18 | ], 19 | "createOnlyProperties": [ 20 | "/properties/ServiceToken" 21 | ], 22 | "primaryIdentifier": [ 23 | "/properties/Id" 24 | ], 25 | "readOnlyProperties": [ 26 | "/properties/Id" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /internal/aws/cfn/schemas/aws/cloudformation/waitcondition.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeName": "AWS::CloudFormation::WaitCondition", 3 | "description": "Resource Type definition for AWS::CloudFormation::WaitCondition", 4 | "additionalProperties": false, 5 | "properties": { 6 | "Id": { 7 | "type": "string" 8 | }, 9 | "Data": { 10 | "type": "object" 11 | }, 12 | "Count": { 13 | "type": "integer" 14 | }, 15 | "Handle": { 16 | "type": "string" 17 | }, 18 | "Timeout": { 19 | "type": "string" 20 | } 21 | }, 22 | "readOnlyProperties": [ 23 | "/properties/Data", 24 | "/properties/Id" 25 | ], 26 | "primaryIdentifier": [ 27 | "/properties/Id" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /internal/aws/cfn/schemas/aws/pinpoint/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeName": "AWS::Pinpoint::App", 3 | "description": "Resource Type definition for AWS::Pinpoint::App", 4 | "additionalProperties": false, 5 | "properties": { 6 | "Id": { 7 | "type": "string" 8 | }, 9 | "Arn": { 10 | "type": "string" 11 | }, 12 | "Tags": { 13 | "type": "object" 14 | }, 15 | "Name": { 16 | "type": "string" 17 | } 18 | }, 19 | "required": [ 20 | "Name" 21 | ], 22 | "readOnlyProperties": [ 23 | "/properties/Arn", 24 | "/properties/Id" 25 | ], 26 | "createOnlyProperties": [ 27 | "/properties/Name" 28 | ], 29 | "primaryIdentifier": [ 30 | "/properties/Id" 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /cft/pkg/tmpl/awscli-modules/url-template.yaml: -------------------------------------------------------------------------------- 1 | Packages: 2 | abc: 3 | Source: https://github.com/aws/aws-cli/raw/3c491be90e9c146717e1aeb79dd21be98bfb022e/tests/unit/customizations/cloudformation/modules/package.zip 4 | Constants: 5 | ModuleSource: https://raw.githubusercontent.com/aws/aws-cli/2f0143bab567386b930322b2b0e845740f7adfd0/tests/unit/customizations/cloudformation/modules 6 | Modules: 7 | Content: 8 | Source: !Sub ${Const::ModuleSource}/basic-module.yaml 9 | Properties: 10 | Name: foo 11 | Overrides: 12 | Bucket: 13 | Properties: 14 | OverrideMe: def 15 | TestPackage: 16 | Source: $abc/zip-module.yaml 17 | Resources: 18 | OtherResource: 19 | Type: AWS::S3::Bucket 20 | -------------------------------------------------------------------------------- /internal/aws/cfn/schemas/aws/iam/usertogroupaddition.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeName": "AWS::IAM::UserToGroupAddition", 3 | "description": "Resource Type definition for AWS::IAM::UserToGroupAddition", 4 | "additionalProperties": false, 5 | "properties": { 6 | "Id": { 7 | "type": "string" 8 | }, 9 | "GroupName": { 10 | "type": "string" 11 | }, 12 | "Users": { 13 | "type": "array", 14 | "uniqueItems": false, 15 | "items": { 16 | "type": "string" 17 | } 18 | } 19 | }, 20 | "required": [ 21 | "GroupName", 22 | "Users" 23 | ], 24 | "primaryIdentifier": [ 25 | "/properties/Id" 26 | ], 27 | "readOnlyProperties": [ 28 | "/properties/Id" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /internal/aws/cfn/schemas/aws/iot1click/device.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeName": "AWS::IoT1Click::Device", 3 | "description": "Resource Type definition for AWS::IoT1Click::Device", 4 | "additionalProperties": false, 5 | "properties": { 6 | "DeviceId": { 7 | "type": "string" 8 | }, 9 | "Enabled": { 10 | "type": "boolean" 11 | }, 12 | "Arn": { 13 | "type": "string" 14 | } 15 | }, 16 | "required": [ 17 | "Enabled", 18 | "DeviceId" 19 | ], 20 | "readOnlyProperties": [ 21 | "/properties/Arn", 22 | "/properties/DeviceId" 23 | ], 24 | "createOnlyProperties": [ 25 | "/properties/DeviceId" 26 | ], 27 | "primaryIdentifier": [ 28 | "/properties/DeviceId" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /scripts/one-schema.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Cache one schema 3 | # $1 is the resource type name 4 | # $RAIN_CACHE_DIR is the root cache dir 5 | 6 | set -eou pipefail 7 | 8 | if [ ! -d "$RAIN_CACHE_DIR" ]; then 9 | echo "$RAIN_CACHE_DIR does not exist." 10 | exit 1 11 | fi 12 | 13 | # Create a directory for the schema based on the resource name 14 | dn=$(echo "$1" | awk -F '::' '/^AWS/ {print tolower($1) "/" tolower($2) }') 15 | mkdir -p "$RAIN_CACHE_DIR/$dn" 16 | 17 | # The schema filename 18 | fn=$(echo "$1" | awk -F '::' '/^AWS/ {print tolower($1) "/" tolower($2) "/" tolower($3) ".json"}') 19 | 20 | ffn="$RAIN_CACHE_DIR/${fn}" 21 | 22 | echo Caching "${1}" to "${ffn}" 23 | 24 | ./rain build -s --no-cache "$1" | jq > "${ffn}" 25 | 26 | -------------------------------------------------------------------------------- /internal/aws/servicequotas/servicequotas.go: -------------------------------------------------------------------------------- 1 | package servicequotas 2 | 3 | import ( 4 | "context" 5 | 6 | aws "github.com/aws-cloudformation/rain/internal/aws" 7 | "github.com/aws/aws-sdk-go-v2/service/servicequotas" 8 | ) 9 | 10 | func getClient() *servicequotas.Client { 11 | return servicequotas.NewFromConfig(aws.Config()) 12 | } 13 | 14 | // Get the value for a service quota 15 | func GetQuota(serviceCode string, quotaCode string) (float64, error) { 16 | 17 | res, err := getClient().GetServiceQuota(context.Background(), 18 | &servicequotas.GetServiceQuotaInput{ 19 | QuotaCode: "aCode, 20 | ServiceCode: &serviceCode, 21 | }) 22 | if err != nil { 23 | return -1, nil 24 | } 25 | return *res.Quota.Value, nil 26 | } 27 | -------------------------------------------------------------------------------- /internal/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/aws-cloudformation/rain/internal/console" 7 | ) 8 | 9 | // Debug defines whether debug mode is enabled 10 | var Debug = false 11 | 12 | // Profile holds the requested AWS profile name 13 | var Profile = "" 14 | 15 | // Region holds the requested AWS region name 16 | var Region = "" 17 | 18 | // Debugf prints messages for stdout only if Debug is true 19 | func Debugf(message string, parts ...interface{}) { 20 | if Debug { 21 | fmt.Println(console.Grey("DEBUG: " + fmt.Sprintf(message, parts...))) 22 | } 23 | } 24 | 25 | func Debugln(message string) { 26 | if Debug { 27 | fmt.Println(console.Grey("DEBUG: " + fmt.Sprintln(message))) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/templates/comments.yaml: -------------------------------------------------------------------------------- 1 | # Comment on the first line 2 | Parameters: 3 | MyParam: 4 | Type: String 5 | 6 | # Multi-line comment between sections before Resources 7 | # Starting at indent 0 8 | 9 | Resources: 10 | 11 | # Comment by itself before MyBucket 12 | 13 | MyBucket: 14 | Type: AWS::S3::Bucket # Comment at the end of line 15 | 16 | # Multi-line comment between resources 17 | # Starting at indent 0 18 | # Between MyBucket and MyOtherBucket 19 | 20 | # Comment at the beginning of MyOtherBucket 21 | MyOtherBucket: 22 | # Comment in the middle of a resource 23 | Type: AWS::S3::Bucket 24 | # Multi line 25 | # comment 26 | Properties: 27 | BucketName: asdf 28 | 29 | # Comment at the end 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # If you prefer the allow list template instead of the deny list, see community template: 2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 3 | # 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Dependency directories (remove the comment below to include it) 18 | vendor/ 19 | 20 | # Go workspace file 21 | go.work 22 | 23 | .vscode/ 24 | main 25 | rain 26 | !internal/cmd/rain 27 | !cmd/rain 28 | parse-perf 29 | local/ 30 | .idea 31 | 32 | .env 33 | .out 34 | 35 | .DS_Store 36 | plugin.so 37 | dist/ 38 | -------------------------------------------------------------------------------- /docs/rain_check.md: -------------------------------------------------------------------------------- 1 | ## rain check 2 | 3 | Validate a CloudFormation template against the spec 4 | 5 | ### Synopsis 6 | 7 | Reads the specified CloudFormation template and validates it against the current CloudFormation specification. 8 | 9 | ``` 10 | rain check