Skip to content

Commit

Permalink
feat: resolve single depth references (#8)
Browse files Browse the repository at this point in the history
* feat: resolve single depth of references

* feat: add tests for resolving of single depth references

* chore: format the json files for readability
  • Loading branch information
p0tr3c authored Feb 28, 2022
1 parent 615f7fa commit a4bba79
Show file tree
Hide file tree
Showing 7 changed files with 616 additions and 11 deletions.
67 changes: 67 additions & 0 deletions terraform_plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,20 @@ type TerraformPlanResourceChange struct {
Before map[string]interface{} // will be null when the action is `create`
After map[string]interface{} // will be null when then action is `delete`
}
Expressions interface{} `json:"expressions"`
}

type TerraformPlanModule struct {
Resources []TerraformPlanResourceChange `json:"resources"`
}

type TerraformPlanConfiguration struct {
RootModule TerraformPlanModule `json:"root_module"`
}

type TerraformPlanJson struct {
ResourceChanges []TerraformPlanResourceChange `json:"resource_changes"`
Configuration TerraformPlanConfiguration `json:"configuration"`
}

type TerraformScanInput map[string]map[string]map[string]interface{}
Expand Down Expand Up @@ -72,9 +82,66 @@ func parseTerraformPlan(planJson TerraformPlanJson, isFullScan bool) TerraformSc
}
}
}

// check root module for references in first depth of attributes
for _, resource := range planJson.Configuration.RootModule.Resources {
// don't care about references in data sources for time being
if resource.Mode == "data" {
continue
}
mode := "resource"
// only update the references in resources that have some resolved attributes already
if resolvedResource, ok := scanInput[mode][resource.Type][getResourceName(resource)].(map[string]interface{}); ok {
expressions := getExpressions(resource.Expressions)
for k, v := range expressions {
// only add non existing attributes. If we already have resolved value do not overwrite it with reference
if _, ok := resolvedResource[k]; !ok {
resolvedResource[k] = v
}
}
scanInput[mode][resource.Type][getResourceName(resource)] = resolvedResource
}
}

return scanInput
}

func getExpressions(expressions interface{}) map[string]interface{} {
result := make(map[string]interface{})
// expressions can be nested. we are only doing 1 depth to resolve top level depenencies
expressionMap, ok := expressions.(map[string]interface{})
if !ok {
return nil
}
for k, v := range expressionMap {
referenceKey, ok := getReference(v)
if ok {
result[k] = referenceKey
}
}
return result
}

// this is very naive implementation
// the referenences can be composed of number of keys
// we only going to use the first reference for time being
func getReference(value interface{}) (interface{}, bool) {
v, ok := value.(map[string]interface{})
if !ok {
return "", false
}
// we are only interested with "references" values
referencesInt, ok := v["references"]
if !ok {
return "", false
}
references, ok := referencesInt.([]interface{})
if !ok {
return "", false
}
return references[0], true
}

func getResourceName(resource TerraformPlanResourceChange) string {
if resource.Index == nil {
return resource.Name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@
],
"source_version": null,
"tags": null,
"vpc_config": []
"vpc_config": [],
"service_role": "aws_iam_role.terra_ci_job"
}
},
"aws_iam_role": {
Expand Down Expand Up @@ -97,11 +98,13 @@
"aws_iam_role_policy": {
"terra_ci_job": {
"name_prefix": null,
"role": "terra_ci_job"
"role": "terra_ci_job",
"policy": "data.aws_caller_identity.current"
},
"terra_ci_runner": {
"name_prefix": null,
"role": "terra_ci_runner"
"role": "terra_ci_runner",
"policy": "aws_codebuild_project.terra_ci"
}
},
"aws_iam_role_policy_attachment": {
Expand Down Expand Up @@ -147,7 +150,8 @@
"definition": "{\n \"Comment\": \"Run Terragrunt Jobs\",\n \"StartAt\": \"OnBranch?\",\n \"States\": {\n \"OnBranch?\": {\n \"Type\": \"Choice\",\n \"Choices\": [\n {\n \"Variable\": \"$.build.sourceversion\",\n \"IsPresent\": true,\n \"Next\": \"PlanBranch\"\n }\n ],\n \"Default\": \"Plan\"\n },\n \"Plan\": {\n \"Type\": \"Task\",\n \"Resource\": \"arn:aws:states:::codebuild:startBuild.sync\",\n \"Parameters\": {\n \"ProjectName\": \"terra-ci-runner\",\n \"EnvironmentVariablesOverride\": [\n {\n \"Name\": \"TERRA_CI_BUILD_NAME\",\n \"Value.$\": \"$$.Execution.Name\"\n },\n {\n \"Name\": \"TERRA_CI_RESOURCE\",\n \"Value.$\": \"$.build.environment.terra_ci_resource\"\n }\n ]\n },\n \"End\": true\n },\n \"PlanBranch\": {\n \"Type\": \"Task\",\n \"Resource\": \"arn:aws:states:::codebuild:startBuild.sync\",\n \"Parameters\": {\n \"ProjectName\": \"terra-ci-runner\",\n \"SourceVersion.$\": \"$.build.sourceversion\",\n \"EnvironmentVariablesOverride\": [\n {\n \"Name\": \"TERRA_CI_RESOURCE\",\n \"Value.$\": \"$.build.environment.terra_ci_resource\"\n }\n ]\n },\n \"End\": true\n }\n }\n}\n",
"name": "terra-ci-runner",
"tags": null,
"type": "STANDARD"
"type": "STANDARD",
"role_arn": "aws_iam_role.terra_ci_runner"
}
},
"aws_route": {
Expand Down Expand Up @@ -184,4 +188,4 @@
}
},
"data": {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"data": {},
"resource": {
"aws_s3_bucket": {
"denied": {
"bucket": "denied",
"bucket_prefix": null,
"force_destroy": false,
"tags": null
},
"duh": {
"bucket": "duh",
"bucket_prefix": null,
"force_destroy": false,
"tags": null
},
"logging2": {
"bucket": "logging2",
"bucket_prefix": null,
"force_destroy": false,
"tags": null
}
},
"aws_s3_bucket_logging": {
"example": {
"bucket": "aws_s3_bucket.logging2.id",
"target_bucket": "aws_s3_bucket.duh.id",
"expected_bucket_owner": null,
"target_grant": [],
"target_prefix": "log/"
},
"example2": {
"bucket": "aws_s3_bucket.logging2.id",
"target_bucket": "aws_s3_bucket.duh.id",
"expected_bucket_owner": null,
"target_grant": [],
"target_prefix": "log/"
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@
],
"source_version": null,
"tags": null,
"vpc_config": []
"vpc_config": [],
"service_role": "aws_iam_role.terra_ci_job"
}
},
"aws_iam_role": {
Expand Down Expand Up @@ -97,11 +98,13 @@
"aws_iam_role_policy": {
"terra_ci_job": {
"name_prefix": null,
"role": "terra_ci_job"
"role": "terra_ci_job",
"policy": "data.aws_caller_identity.current"
},
"terra_ci_runner": {
"name_prefix": null,
"role": "terra_ci_runner"
"role": "terra_ci_runner",
"policy": "aws_codebuild_project.terra_ci"
}
},
"aws_iam_role_policy_attachment": {
Expand Down Expand Up @@ -147,7 +150,8 @@
"definition": "{\n \"Comment\": \"Run Terragrunt Jobs\",\n \"StartAt\": \"OnBranch?\",\n \"States\": {\n \"OnBranch?\": {\n \"Type\": \"Choice\",\n \"Choices\": [\n {\n \"Variable\": \"$.build.sourceversion\",\n \"IsPresent\": true,\n \"Next\": \"PlanBranch\"\n }\n ],\n \"Default\": \"Plan\"\n },\n \"Plan\": {\n \"Type\": \"Task\",\n \"Resource\": \"arn:aws:states:::codebuild:startBuild.sync\",\n \"Parameters\": {\n \"ProjectName\": \"terra-ci-runner\",\n \"EnvironmentVariablesOverride\": [\n {\n \"Name\": \"TERRA_CI_BUILD_NAME\",\n \"Value.$\": \"$$.Execution.Name\"\n },\n {\n \"Name\": \"TERRA_CI_RESOURCE\",\n \"Value.$\": \"$.build.environment.terra_ci_resource\"\n }\n ]\n },\n \"End\": true\n },\n \"PlanBranch\": {\n \"Type\": \"Task\",\n \"Resource\": \"arn:aws:states:::codebuild:startBuild.sync\",\n \"Parameters\": {\n \"ProjectName\": \"terra-ci-runner\",\n \"SourceVersion.$\": \"$.build.sourceversion\",\n \"EnvironmentVariablesOverride\": [\n {\n \"Name\": \"TERRA_CI_RESOURCE\",\n \"Value.$\": \"$.build.environment.terra_ci_resource\"\n }\n ]\n },\n \"End\": true\n }\n }\n}\n",
"name": "terra-ci-runner",
"tags": null,
"type": "STANDARD"
"type": "STANDARD",
"role_arn": "aws_iam_role.terra_ci_runner"
}
},
"aws_route": {
Expand Down Expand Up @@ -184,4 +188,4 @@
}
},
"data": {}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"resource": {
"aws_codebuild_project": {
"terra_ci": {
"service_role": "aws_iam_role.terra_ci_job",
"arn": "arn:aws:codebuild:eu-west-1:719261439472:project/terra-ci-runner",
"artifacts": [
{
Expand Down Expand Up @@ -222,4 +223,4 @@
}
},
"data": {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"data": {},
"resource": {
"aws_s3_bucket": {
"denied": {
"bucket": "denied",
"bucket_prefix": null,
"force_destroy": false,
"tags": null
},
"duh": {
"bucket": "duh",
"bucket_prefix": null,
"force_destroy": false,
"tags": null
},
"logging2": {
"bucket": "logging2",
"bucket_prefix": null,
"force_destroy": false,
"tags": null
}
},
"aws_s3_bucket_logging": {
"example": {
"bucket": "aws_s3_bucket.logging2.id",
"target_bucket": "aws_s3_bucket.duh.id",
"expected_bucket_owner": null,
"target_grant": [],
"target_prefix": "log/"
},
"example2": {
"bucket": "aws_s3_bucket.logging2.id",
"target_bucket": "aws_s3_bucket.duh.id",
"expected_bucket_owner": null,
"target_grant": [],
"target_prefix": "log/"
}
}
}
}
Loading

0 comments on commit a4bba79

Please sign in to comment.