Skip to content

Commit f1dfbb8

Browse files
authored
SAM Policy document (#3)
* add json decoder * decode statements * implement root template decoder * add mkJson* functions * convert policy template to valid json * use pretty render * gen sam policy-template * refactor to use JSON.dhall * mk package.dhall * refactor:move sam module;remove union type for CfnText * update readme dhall * fix unit test * bump version * freeze JSON sha * fix dhall version * use nix to package * upload cache
1 parent 39afa5b commit f1dfbb8

File tree

1,226 files changed

+6420
-11970
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,226 files changed

+6420
-11970
lines changed

.github/workflows/build.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ jobs:
4949
docker tag ghcr.io/jcouyang/dhall-aws-cloudformation:latest ghcr.io/jcouyang/dhall-aws-cloudformation:$LOCAL_VERSION
5050
docker push ghcr.io/jcouyang/dhall-aws-cloudformation:latest
5151
docker push ghcr.io/jcouyang/dhall-aws-cloudformation:$LOCAL_VERSION
52+
- name: package cache
53+
run: |
54+
nix-build package.nix
55+
tar -czhf cache.tar.gz ./result
5256
- name: tag release
5357
env:
5458
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -57,7 +61,7 @@ jobs:
5761
LOCAL_VERSION=$(dhall text < ./version.dhall)
5862
echo "main version is $LAST_RELEASE and current version is $LOCAL_VERSION"
5963
if [ ${LAST_RELEASE:-0} != $LOCAL_VERSION ];then
60-
hub release create -m "${LOCAL_VERSION}" "${LOCAL_VERSION}"
64+
hub release create -m "${LOCAL_VERSION}" -a ./cache.tar.gz "${LOCAL_VERSION}"
6165
fi
6266
- name: publish doc
6367
env:

Fn.dhall

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
let JSON =
2-
https://raw.githubusercontent.com/dhall-lang/dhall-lang/v20.0.0/Prelude/JSON/package.dhall
1+
let JSON = (./Prelude.dhall).JSON
32

4-
let map =
5-
https://raw.githubusercontent.com/dhall-lang/dhall-lang/v20.0.0/Prelude/List/map.dhall
3+
let map = (./Prelude.dhall).List.map
64

75
let _Pi =
86
λ(Fn : Type)
@@ -160,12 +158,6 @@ let toJSON =
160158
, String = λ(x : Text) JSON.string x
161159
}
162160

163-
let CfnText = < Plain : Text | Fn : JSON.Type >
164-
165-
let string = λ(a : Text) CfnText.Plain a
166-
167-
let fn = λ(a : Fn/Type) CfnText.Fn (toJSON a)
168-
169161
let exampleImportValue =
170162
assert
171163
: toJSON (ImportValue (Sub "\${NetworkStackNameParameter}-SubnetID"))
@@ -302,7 +294,8 @@ in { Ref
302294
, GetAZs
303295
, Join
304296
, Select
305-
, string
306-
, fn
307-
, CfnText
297+
, Type = Fn/Type
298+
, CfnText = JSON.Type
299+
, render = toJSON
300+
, renderText = λ(s : Text) toJSON (String s)
308301
}

Prelude.dhall

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
https://prelude.dhall-lang.org/v20.1.0/package.dhall sha256:26b0ef498663d269e4dc6a82b0ee289ec565d683ef4c00d0ebdd25333a5a3c98

README.md.dhall

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,63 @@ in ''
5454
```
5555

5656
So the compiler can just help you find the correct attribute.
57+
#### Sam Policy Templates
58+
Cloudformation's Policy document is loosy type as just JSON, it is hard to get the policy right and too many boilerplates to create a Dhall JSON data
59+
60+
Thanks to [AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-policy-templates.html) there are some common policy documents we can laverage
61+
62+
All these templates are translated into Dhall functions, so you don't need to use SAM to be able to use these policy documents.
63+
64+
```dhall
65+
Policies = Some [Policy::{
66+
, PolicyDocument = DynamoDBReadPolicy (Fn.String "DBName")
67+
, PolicyName = s "dynamo read only"
68+
}]
69+
```
70+
71+
will generates
72+
73+
```json
74+
{
75+
"Policies": [
76+
{
77+
"PolicyDocument": {
78+
"Statement": [
79+
{
80+
"Action": [
81+
"dynamodb:GetItem",
82+
"dynamodb:Scan",
83+
"dynamodb:Query",
84+
"dynamodb:BatchGetItem",
85+
"dynamodb:DescribeTable"
86+
],
87+
"Effect": "Allow",
88+
"Resource": [
89+
{
90+
"Fn::Sub": [
91+
"arn:${AWS::Partition}:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${tableName}",
92+
{
93+
"tableName": "DBName"
94+
}
95+
]
96+
},
97+
{
98+
"Fn::Sub": [
99+
"arn:${AWS::Partition}:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${tableName}/index/*",
100+
{
101+
"tableName": "DBName"
102+
}
103+
]
104+
}
105+
]
106+
}
107+
]
108+
},
109+
"PolicyName": "dynamo read only"
110+
}
111+
]
112+
}
113+
```
57114

58115
## :mag: [Examples](./examples)
59116

@@ -65,7 +122,6 @@ in ''
65122
$ stack build
66123
$ stack test
67124
```
68-
69125
### Generate Type Definitions
70126

71127
Type definitions are generated from config file `./config.dhall` which contains specifications used by [AWS CDK](https://github.com/aws/aws-cdk/blob/master/packages/%40aws-cdk/cfnspec/build-tools/update.sh) as well:

UpdatePolicy.dhall

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
let JSON =
2-
https://raw.githubusercontent.com/dhall-lang/dhall-lang/v20.0.0/Prelude/JSON/package.dhall
1+
let JSON = (./Prelude.dhall).JSON
32

43
let CodeDeployPolicyType =
54
{ AfterAllowTrafficHook : Optional JSON.Type

app/Main.hs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,47 +10,64 @@ import Data.Foldable (traverse_)
1010
import Data.Map (Map, size, toList)
1111
import Data.Maybe
1212
import Data.Text (Text, unpack)
13-
import qualified Data.Text.IO as TIO
1413
import Data.Text.Lazy (pack)
14+
import qualified Data.Text.Lazy as Lazy
1515
import Data.Text.Lazy.Encoding (encodeUtf8)
16+
import qualified Data.Text.Lazy.IO as TIO
1617
import Dhall (Decoder, FromDhall, auto, field,
1718
input, inputFile, record, string)
1819
import Dhall.Cloudformation
19-
import Dhall.Core (pretty)
20+
import qualified Dhall.Core as Dhall
21+
import qualified Dhall.Pretty
22+
import Dhall.Sam.Template (parseTemplates)
2023
import GHC.Generics (Generic)
24+
import qualified Prettyprinter.Render.Text as Pretty.Text
2125
import System.Directory (createDirectoryIfMissing)
2226
import System.FilePath.Posix (takeDirectory, (</>))
2327

2428
data Config = Config
2529
{specifications :: Map Text Text
2630
,excludes :: [Text]
31+
,templates :: Map Text Text
2732
} deriving stock (Show)
2833

2934
readConfig :: Decoder Config
3035
readConfig =
3136
record
3237
( Config <$> field "specifications" auto
3338
<*> field "excludes" auto
39+
<*> field "templates" auto
3440
)
3541
main :: IO ()
3642
main = do
3743
config <- inputFile readConfig "./config.dhall" :: IO Config
3844
traverse_ (genRegionSpec (excludes config)) $ toList (specifications config)
45+
traverse_ genTemplate $ toList (templates config)
3946
where
4047
genRegionSpec :: [Text] -> (Text, Text) -> IO ()
4148
genRegionSpec excl (region, url) = do
4249
spec <- input string (url <> " as Text")
4350
case convert spec excl of
4451
Left e -> putStr e
4552
Right (v, s) -> traverse_ (genFile v region) (toList s)
46-
convert :: String -> [Text] -> Either String (Text, Map Text Text)
53+
genTemplate (name, url) = do
54+
template <- input auto (url <> " as Text")
55+
case (eitherDecode . encodeUtf8) template of
56+
Left e -> do
57+
putStr e
58+
Right maps -> traverse_ (genFile "" name) (toList $ prettyPrint <$> parseTemplates maps)
59+
convert :: String -> [Text] -> Either String (Text, Map Text Lazy.Text)
4760
convert spec excl= versioned excl <$> (decodeSpec spec :: Either String Spec)
48-
versioned excl s = (resourceSpecificationVersion s, ((fmap pretty) . convertSpec excl) s)
61+
versioned excl s = (resourceSpecificationVersion s, (fmap prettyPrint . convertSpec excl) s)
4962
decodeSpec = eitherDecode . encodeUtf8 . pack
5063
genFile _ region (k, v) = mkFile (unpack region) (unpack k) v
5164

52-
mkFile :: String -> FilePath -> Text -> IO ()
65+
prettyPrint :: DhallExpr -> Lazy.Text
66+
prettyPrint expr = Pretty.Text.renderLazy stream
67+
where
68+
stream = Dhall.Pretty.layout $ Dhall.Pretty.prettyCharacterSet Dhall.Pretty.ASCII expr
69+
mkFile :: String -> FilePath -> Lazy.Text -> IO ()
5370
mkFile prefix path content = do
54-
let d = prefix </> path
71+
let d = prefix </> path <> ".dhall"
5572
createDirectoryIfMissing True $ takeDirectory d
5673
TIO.writeFile d content

cloudformation/AWS::ACMPCA::Certificate/Resources.dhall

Lines changed: 2 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cloudformation/AWS::ACMPCA::CertificateAuthority.dhall

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cloudformation/AWS::ACMPCA::CertificateAuthority/OcspConfiguration.dhall

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cloudformation/AWS::ACMPCA::CertificateAuthority/Resources.dhall

Lines changed: 2 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cloudformation/AWS::ACMPCA::CertificateAuthority/RevocationConfiguration.dhall

Lines changed: 8 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cloudformation/AWS::ACMPCA::CertificateAuthorityActivation/Resources.dhall

Lines changed: 2 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cloudformation/AWS::AccessAnalyzer::Analyzer/Resources.dhall

Lines changed: 2 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cloudformation/AWS::AmazonMQ::Broker/Resources.dhall

Lines changed: 2 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)