Skip to content

Commit 596505d

Browse files
committed
begin work to parse modules and tf plans
1 parent 5157b1c commit 596505d

File tree

10 files changed

+129
-39
lines changed

10 files changed

+129
-39
lines changed

go.mod

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ go 1.23.5
44

55
require (
66
github.com/aquasecurity/trivy v0.58.2
7+
github.com/coder/serpent v0.10.0
78
github.com/hashicorp/hcl/v2 v2.23.0
9+
github.com/hashicorp/terraform-json v0.24.0
10+
github.com/jedib0t/go-pretty/v6 v6.6.5
811
github.com/stretchr/testify v1.10.0
912
github.com/zclconf/go-cty v1.16.2
1013
)
@@ -34,7 +37,6 @@ require (
3437
github.com/cespare/xxhash/v2 v2.3.0 // indirect
3538
github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 // indirect
3639
github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0 // indirect
37-
github.com/coder/serpent v0.10.0 // indirect
3840
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
3941
github.com/envoyproxy/go-control-plane v0.13.1 // indirect
4042
github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect
@@ -54,9 +56,9 @@ require (
5456
github.com/hashicorp/go-safetemp v1.0.0 // indirect
5557
github.com/hashicorp/go-uuid v1.0.3 // indirect
5658
github.com/hashicorp/go-version v1.7.0 // indirect
57-
github.com/jedib0t/go-pretty/v6 v6.6.5 // indirect
5859
github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 // indirect
5960
github.com/klauspost/compress v1.17.11 // indirect
61+
github.com/liamg/memoryfs v1.6.0 // indirect
6062
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
6163
github.com/mattn/go-colorable v0.1.14 // indirect
6264
github.com/mattn/go-isatty v0.0.20 // indirect

go.sum

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,8 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
686686
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
687687
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
688688
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
689+
github.com/charmbracelet/lipgloss v0.8.0 h1:IS00fk4XAHcf8uZKc3eHeMUTCxUH6NkaTrdyCQk84RU=
690+
github.com/charmbracelet/lipgloss v0.8.0/go.mod h1:p4eYUZZJ/0oXTuCQKFF8mqyKCz0ja6y+7DniDDw5KKU=
689691
github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s=
690692
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
691693
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
@@ -934,6 +936,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
934936
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
935937
github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3qos=
936938
github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA=
939+
github.com/hashicorp/terraform-json v0.24.0 h1:rUiyF+x1kYawXeRth6fKFm/MdfBS6+lW4NbeATsYz8Q=
940+
github.com/hashicorp/terraform-json v0.24.0/go.mod h1:Nfj5ubo9xbu9uiAoZVBsNOjvNKB66Oyrvtit74kC7ow=
937941
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
938942
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
939943
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
@@ -1014,8 +1018,12 @@ github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
10141018
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
10151019
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
10161020
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
1021+
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
1022+
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
10171023
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
10181024
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
1025+
github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A=
1026+
github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM=
10191027
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
10201028
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
10211029
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=

mark.go

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,6 @@ import (
55
"github.com/zclconf/go-cty/cty"
66
)
77

8-
const (
9-
diagnosticsMark = "diagnostics"
10-
)
11-
128
func markWithDiagnostic(v cty.Value, diag hcl.Diagnostics) cty.Value {
139
return v.Mark(diag)
1410
}
15-
16-
func valueDiagnostic(v cty.Value) hcl.Diagnostics {
17-
x := v.Marks()
18-
var _ = x
19-
return nil
20-
}

hook.go renamed to paramhook.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,6 @@ func ParameterContextsEvalHook(input Input) func(ctx *tfcontext.Context, blocks
5050
}
5151

5252
func evaluateCoderParameterDefault(b *terraform.Block) (cty.Value, hcl.Diagnostics) {
53-
//if b.Label() == "" {
54-
// return cty.NilVal, errors.New("empty label - cannot resolve")
55-
//}
56-
5753
attributes := b.Attributes()
5854
var valType cty.Type
5955
var defaults *typeexpr.Defaults

plan.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package preview
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"io"
7+
"io/fs"
8+
9+
"github.com/aquasecurity/trivy/pkg/iac/scanners/terraformplan/tfjson/parser"
10+
"github.com/aquasecurity/trivy/pkg/iac/terraform"
11+
tfcontext "github.com/aquasecurity/trivy/pkg/iac/terraform/context"
12+
tfjson "github.com/hashicorp/terraform-json"
13+
"github.com/zclconf/go-cty/cty"
14+
)
15+
16+
func PlanJSONHook(dfs fs.FS, input Input) (func(ctx *tfcontext.Context, blocks terraform.Blocks, inputVars map[string]cty.Value), error) {
17+
if input.PlanJSONPath == "" {
18+
return func(ctx *tfcontext.Context, blocks terraform.Blocks, inputVars map[string]cty.Value) {}, nil
19+
}
20+
file, err := dfs.Open(input.PlanJSONPath)
21+
if err != nil {
22+
return nil, fmt.Errorf("unable to open plan JSON file: %w", err)
23+
}
24+
25+
plan, err := ParsePlanJSON(file)
26+
if err != nil {
27+
return nil, fmt.Errorf("unable to parse plan JSON: %w", err)
28+
}
29+
30+
//plan.PriorState
31+
32+
var _ = plan
33+
return func(ctx *tfcontext.Context, blocks terraform.Blocks, inputVars map[string]cty.Value) {
34+
// 'data' blocks are loaded into prior state
35+
//plan.PriorState.Values.RootModule.Resources
36+
37+
}, nil
38+
}
39+
40+
func extract(parents []string, mod *tfjson.StateModule) {
41+
42+
}
43+
44+
// ParsePlanJSON can parse the JSON output of a Terraform plan.
45+
// terraform plan out.plan
46+
// terraform show -json out.plan
47+
func ParsePlanJSON(reader io.Reader) (*tfjson.Plan, error) {
48+
plan := new(tfjson.Plan)
49+
return plan, json.NewDecoder(reader).Decode(plan)
50+
}
51+
52+
// ParsePlanJSON can parse the JSON output of a Terraform plan.
53+
// terraform plan out.plan
54+
// terraform show -json out.plan
55+
func TrivyParsePlanJSON(reader io.Reader) (*tfjson.Plan, error) {
56+
p := parser.New()
57+
plan, err := p.Parse(reader)
58+
var _ = plan
59+
60+
plan.ToFS()
61+
62+
return nil, err
63+
}

preview.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
)
1414

1515
type Input struct {
16+
PlanJSONPath string
1617
ParameterValues map[string]types.ParameterValue
1718
}
1819

@@ -28,12 +29,23 @@ func Preview(ctx context.Context, input Input, dir fs.FS) (*Output, hcl.Diagnost
2829
return nil, nil
2930
}
3031

31-
hook := ParameterContextsEvalHook(input)
32+
planHook, err := PlanJSONHook(dir, input)
33+
if err != nil {
34+
return nil, hcl.Diagnostics{
35+
{
36+
Severity: hcl.DiagError,
37+
Summary: "Parsing plan JSON",
38+
Detail: err.Error(),
39+
},
40+
}
41+
}
3242
// moduleSource is "" for a local module
3343
p := parser.New(dir, "",
3444
parser.OptionWithDownloads(false),
3545
parser.OptionWithTFVarsPaths(varFiles...),
36-
parser.OptionWithEvalHook(hook),
46+
parser.OptionWithEvalHook(planHook),
47+
parser.OptionWithEvalHook(ParameterContextsEvalHook(input)),
48+
parser.OptionWithSkipCachedModules(true),
3749
)
3850

3951
err = p.ParseFS(ctx, ".")

preview_test.go

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@ package preview_test
22

33
import (
44
"context"
5-
"embed"
65
"fmt"
7-
"io/fs"
6+
"os"
87
"path/filepath"
98
"testing"
109

@@ -16,16 +15,12 @@ import (
1615
"github.com/coder/preview/types"
1716
)
1817

19-
//go:embed testdata
20-
var testdata embed.FS
21-
2218
func Test_Extract(t *testing.T) {
2319
t.Parallel()
2420

2521
for _, tc := range []struct {
2622
name string
2723
dir string
28-
showJSON string
2924
failPreview bool
3025
input preview.Input
3126

@@ -122,21 +117,33 @@ func Test_Extract(t *testing.T) {
122117
expUnknowns: []string{
123118
"foo", "bar",
124119
},
120+
125121
input: preview.Input{},
126122
params: map[string]func(t *testing.T, parameter types.Parameter){},
127123
},
128124
{
129-
name: "external docker resource with plan data",
130-
dir: "dockerdata",
131-
showJSON: "show.json",
125+
name: "external docker resource with plan data",
126+
dir: "dockerdata",
132127
expTags: map[string]string{
133128
"qux": "quux",
134129
"foo": "ubuntu@sha256:80dd3c3b9c6cecb9f1667e9290b3bc61b78c2678c02cbdae5f0fea92cc6734ab",
135130
"bar": "centos@sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177",
136131
},
137132
expUnknowns: []string{},
138-
input: preview.Input{},
139-
params: map[string]func(t *testing.T, parameter types.Parameter){},
133+
input: preview.Input{
134+
PlanJSONPath: "plan.json",
135+
},
136+
params: map[string]func(t *testing.T, parameter types.Parameter){},
137+
},
138+
{
139+
name: "external module with external data",
140+
dir: "module",
141+
expTags: map[string]string{},
142+
expUnknowns: []string{},
143+
input: preview.Input{
144+
PlanJSONPath: "before.json",
145+
},
146+
params: map[string]func(t *testing.T, parameter types.Parameter){},
140147
},
141148
} {
142149
t.Run(tc.name, func(t *testing.T) {
@@ -148,8 +155,9 @@ func Test_Extract(t *testing.T) {
148155
tc.expTags = map[string]string{}
149156
}
150157

151-
dirFs, err := fs.Sub(testdata, filepath.Join("testdata", tc.dir))
152-
require.NoError(t, err)
158+
dirFs := os.DirFS(filepath.Join("testdata", tc.dir))
159+
//a, b := fs.ReadDir(dirFs, ".")
160+
//fmt.Println(a, b)
153161

154162
output, diags := preview.Preview(context.Background(), tc.input, dirFs)
155163
if tc.failPreview {

testdata/.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
*/.terraform*
22
*/terraform.tfstate
33
*/terraform.tfstate.backup
4-
*/out.plan
5-
*/plan.json
4+
*/out.plan

testdata/dockerdata/main.tf

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,13 @@ data "coder_workspace_tags" "custom_workspace_tags" {
1616
tags = {
1717
// If a value is required, you can do something like:
1818
// try(docker_image.ubuntu.repo_digest, "default-value")
19-
"foo" = docker_image.ubuntu.repo_digest
19+
"foo" = data.docker_registry_image.ubuntu.sha256_digest
2020
"bar" = docker_image.centos.repo_digest
2121
"qux" = "quux"
2222
}
2323
}
2424

2525
# Pulls the image
26-
resource "docker_image" "ubuntu" {
27-
name = "ubuntu:latest"
28-
}
29-
3026
resource "docker_image" "centos" {
3127
name = "centos:latest"
3228
}

testdata/module/main.tf

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ terraform {
33
coder = {
44
source = "coder/coder"
55
}
6+
docker = {
7+
source = "kreuzwerker/docker"
8+
version = "3.0.2"
9+
}
610
}
711
}
812

@@ -19,7 +23,19 @@ module "jetbrains_gateway" {
1923

2024
data "coder_workspace" "me" {}
2125
resource "coder_agent" "main" {
22-
2326
arch = "amd64"
2427
os = "linux"
28+
}
29+
30+
31+
data "coder_workspace_tags" "custom_workspace_tags" {
32+
tags = {
33+
"foo" = data.docker_registry_image.ubuntu.sha256_digest
34+
}
35+
}
36+
37+
38+
data "docker_registry_image" "ubuntu" {
39+
name = "ubuntu:precise"
40+
// sha256_digest
2541
}

0 commit comments

Comments
 (0)