Skip to content

Commit f5d1807

Browse files
authored
Send marked values over the wire (#239)
1 parent 7b23e20 commit f5d1807

File tree

9 files changed

+1039
-500
lines changed

9 files changed

+1039
-500
lines changed

plugin/fromproto/fromproto.go

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/hashicorp/hcl/v2"
88
"github.com/terraform-linters/tflint-plugin-sdk/hclext"
99
"github.com/terraform-linters/tflint-plugin-sdk/plugin/proto"
10+
"github.com/terraform-linters/tflint-plugin-sdk/terraform/lang/marks"
1011
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
1112
"github.com/zclconf/go-cty/cty"
1213
"github.com/zclconf/go-cty/cty/msgpack"
@@ -161,7 +162,7 @@ func Expression(expr *proto.Expression) (hcl.Expression, hcl.Diagnostics) {
161162
return nil, diags
162163
}
163164
if expr.Value != nil {
164-
val, err := msgpack.Unmarshal(expr.Value, cty.DynamicPseudoType)
165+
val, err := Value(expr.Value, cty.DynamicPseudoType, expr.ValueMarks)
165166
if err != nil {
166167
panic(fmt.Errorf("cannot unmarshal the bound expr: %w", err))
167168
}
@@ -210,6 +211,43 @@ func Pos(pos *proto.Range_Pos) hcl.Pos {
210211
}
211212
}
212213

214+
// Value converts msgpack and []proto.ValueMark to cty.Value
215+
func Value(value []byte, ty cty.Type, valueMarks []*proto.ValueMark) (cty.Value, error) {
216+
val, err := msgpack.Unmarshal(value, ty)
217+
if err != nil {
218+
return cty.NilVal, err
219+
}
220+
221+
pvm := make([]cty.PathValueMarks, len(valueMarks))
222+
for idx, mark := range valueMarks {
223+
pvm[idx] = cty.PathValueMarks{
224+
Path: AttributePath(mark.Path),
225+
}
226+
if mark.Sensitive {
227+
pvm[idx].Marks = cty.NewValueMarks(marks.Sensitive)
228+
}
229+
}
230+
231+
return val.MarkWithPaths(pvm), nil
232+
}
233+
234+
// AttributePath converts proto.AttributePath to cty.Path
235+
func AttributePath(path *proto.AttributePath) cty.Path {
236+
ret := cty.Path{}
237+
238+
for _, step := range path.Steps {
239+
switch s := step.Selector.(type) {
240+
case *proto.AttributePath_Step_ElementKeyString:
241+
ret = ret.IndexString(s.ElementKeyString)
242+
case *proto.AttributePath_Step_ElementKeyInt:
243+
ret = ret.IndexInt(int(s.ElementKeyInt))
244+
case *proto.AttributePath_Step_AttributeName:
245+
ret = ret.GetAttr(s.AttributeName)
246+
}
247+
}
248+
return ret
249+
}
250+
213251
// Config converts proto.ApplyGlobalConfig_Config to tflint.Config
214252
func Config(config *proto.ApplyGlobalConfig_Config) *tflint.Config {
215253
if config == nil {
@@ -313,7 +351,7 @@ func Error(err error) error {
313351
case proto.ErrorCode_ERROR_CODE_UNEVALUABLE:
314352
return fmt.Errorf("%s%w", st.Message(), tflint.ErrUnevaluable)
315353
case proto.ErrorCode_ERROR_CODE_SENSITIVE:
316-
return fmt.Errorf("%s%w", st.Message(), tflint.ErrSensitive)
354+
return tflint.ErrSensitive
317355
}
318356
}
319357

plugin/plugin2host/client.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"github.com/zclconf/go-cty/cty"
2121
"github.com/zclconf/go-cty/cty/gocty"
2222
"github.com/zclconf/go-cty/cty/json"
23-
"github.com/zclconf/go-cty/cty/msgpack"
2423
"google.golang.org/grpc/codes"
2524
"google.golang.org/grpc/status"
2625
)
@@ -327,7 +326,7 @@ func (c *GRPCClient) EvaluateExpr(expr hcl.Expression, ret interface{}, opts *tf
327326
return fromproto.Error(err)
328327
}
329328

330-
val, err := msgpack.Unmarshal(resp.Value, ty)
329+
val, err := fromproto.Value(resp.Value, ty, resp.Marks)
331330
if err != nil {
332331
return err
333332
}
@@ -336,7 +335,7 @@ func (c *GRPCClient) EvaluateExpr(expr hcl.Expression, ret interface{}, opts *tf
336335
return gocty.FromCtyValue(val, ret)
337336
}
338337

339-
// Returns an error if the value cannot be decoded to a Go value (e.g. unknown value, null).
338+
// Returns an error if the value cannot be decoded to a Go value (e.g. unknown, null, sensitive).
340339
// This allows the caller to handle the value by the errors package.
341340
err = cty.Walk(val, func(path cty.Path, v cty.Value) (bool, error) {
342341
if !v.IsKnown() {
@@ -347,6 +346,10 @@ func (c *GRPCClient) EvaluateExpr(expr hcl.Expression, ret interface{}, opts *tf
347346
logger.Debug(fmt.Sprintf("null value found in %s", expr.Range()))
348347
return false, tflint.ErrNullValue
349348
}
349+
if v.IsMarked() {
350+
logger.Debug(fmt.Sprintf("sensitive value found in %s", expr.Range()))
351+
return false, tflint.ErrSensitive
352+
}
350353
return true, nil
351354
})
352355
if err != nil {

plugin/plugin2host/plugin2host_test.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/terraform-linters/tflint-plugin-sdk/hclext"
1616
"github.com/terraform-linters/tflint-plugin-sdk/plugin/proto"
1717
"github.com/terraform-linters/tflint-plugin-sdk/terraform/addrs"
18+
"github.com/terraform-linters/tflint-plugin-sdk/terraform/lang/marks"
1819
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
1920
"github.com/zclconf/go-cty/cty"
2021
"google.golang.org/grpc"
@@ -1855,6 +1856,98 @@ func TestEvaluateExpr(t *testing.T) {
18551856
return !errors.Is(err, tflint.ErrNullValue)
18561857
},
18571858
},
1859+
{
1860+
Name: "sensitive",
1861+
Expr: hclExpr(`var.foo`),
1862+
TargetType: reflect.TypeOf(""),
1863+
ServerImpl: func(expr hcl.Expression, opts tflint.EvaluateExprOption) (cty.Value, error) {
1864+
return evalExpr(expr, &hcl.EvalContext{
1865+
Variables: map[string]cty.Value{
1866+
"var": cty.MapVal(map[string]cty.Value{
1867+
"foo": cty.StringVal("bar").Mark(marks.Sensitive),
1868+
}),
1869+
},
1870+
})
1871+
},
1872+
Want: "",
1873+
GetFileImpl: fileExists,
1874+
ErrCheck: func(err error) bool {
1875+
return !errors.Is(err, tflint.ErrSensitive)
1876+
},
1877+
},
1878+
{
1879+
Name: "sensitive as cty.Value",
1880+
Expr: hclExpr(`var.foo`),
1881+
TargetType: reflect.TypeOf(cty.Value{}),
1882+
ServerImpl: func(expr hcl.Expression, opts tflint.EvaluateExprOption) (cty.Value, error) {
1883+
return evalExpr(expr, &hcl.EvalContext{
1884+
Variables: map[string]cty.Value{
1885+
"var": cty.MapVal(map[string]cty.Value{
1886+
"foo": cty.StringVal("bar").Mark(marks.Sensitive),
1887+
}),
1888+
},
1889+
})
1890+
},
1891+
Want: cty.StringVal("bar").Mark(marks.Sensitive),
1892+
GetFileImpl: fileExists,
1893+
ErrCheck: neverHappend,
1894+
},
1895+
{
1896+
Name: "sensitive in object",
1897+
Expr: hclExpr(`{ value = var.foo }`),
1898+
TargetType: reflect.TypeOf(map[string]string{}),
1899+
ServerImpl: func(expr hcl.Expression, opts tflint.EvaluateExprOption) (cty.Value, error) {
1900+
return evalExpr(expr, &hcl.EvalContext{
1901+
Variables: map[string]cty.Value{
1902+
"var": cty.MapVal(map[string]cty.Value{
1903+
"foo": cty.StringVal("bar").Mark(marks.Sensitive),
1904+
}),
1905+
},
1906+
})
1907+
},
1908+
Want: (map[string]string)(nil),
1909+
GetFileImpl: fileExists,
1910+
ErrCheck: func(err error) bool {
1911+
return !errors.Is(err, tflint.ErrSensitive)
1912+
},
1913+
},
1914+
{
1915+
Name: "sensitive object as cty.Value",
1916+
Expr: hclExpr(`var.foo`),
1917+
TargetType: reflect.TypeOf(cty.Value{}),
1918+
ServerImpl: func(expr hcl.Expression, opts tflint.EvaluateExprOption) (cty.Value, error) {
1919+
return evalExpr(expr, &hcl.EvalContext{
1920+
Variables: map[string]cty.Value{
1921+
"var": cty.MapVal(map[string]cty.Value{
1922+
"foo": cty.ObjectVal(map[string]cty.Value{
1923+
"bar": cty.StringVal("barval").Mark(marks.Sensitive),
1924+
"baz": cty.ListVal([]cty.Value{cty.NumberIntVal(1).Mark(marks.Sensitive)}),
1925+
"qux": cty.TupleVal([]cty.Value{cty.StringVal("quxval").Mark(marks.Sensitive)}),
1926+
"quux": cty.MapVal(map[string]cty.Value{
1927+
"foo": cty.StringVal("fooval").Mark(marks.Sensitive),
1928+
}),
1929+
"corge": cty.ObjectVal(map[string]cty.Value{
1930+
"bar": cty.NumberIntVal(2).Mark(marks.Sensitive),
1931+
}),
1932+
}),
1933+
}),
1934+
},
1935+
})
1936+
},
1937+
Want: cty.ObjectVal(map[string]cty.Value{
1938+
"bar": cty.StringVal("barval").Mark(marks.Sensitive),
1939+
"baz": cty.ListVal([]cty.Value{cty.NumberIntVal(1).Mark(marks.Sensitive)}),
1940+
"qux": cty.TupleVal([]cty.Value{cty.StringVal("quxval").Mark(marks.Sensitive)}),
1941+
"quux": cty.MapVal(map[string]cty.Value{
1942+
"foo": cty.StringVal("fooval").Mark(marks.Sensitive),
1943+
}),
1944+
"corge": cty.ObjectVal(map[string]cty.Value{
1945+
"bar": cty.NumberIntVal(2).Mark(marks.Sensitive),
1946+
}),
1947+
}),
1948+
GetFileImpl: fileExists,
1949+
ErrCheck: neverHappend,
1950+
},
18581951
}
18591952

18601953
for _, test := range tests {

plugin/plugin2host/server.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
1212
"github.com/zclconf/go-cty/cty"
1313
"github.com/zclconf/go-cty/cty/json"
14-
"github.com/zclconf/go-cty/cty/msgpack"
1514
"google.golang.org/grpc/codes"
1615
"google.golang.org/grpc/status"
1716
)
@@ -156,12 +155,12 @@ func (s *GRPCServer) EvaluateExpr(ctx context.Context, req *proto.EvaluateExpr_R
156155
if err != nil {
157156
return nil, toproto.Error(codes.FailedPrecondition, err)
158157
}
159-
val, err := msgpack.Marshal(value, ty)
158+
val, marks, err := toproto.Value(value, ty)
160159
if err != nil {
161160
return nil, toproto.Error(codes.FailedPrecondition, err)
162161
}
163162

164-
return &proto.EvaluateExpr_Response{Value: val}, nil
163+
return &proto.EvaluateExpr_Response{Value: val, Marks: marks}, nil
165164
}
166165

167166
// EmitIssue emits the issue with the passed rule, message, location

0 commit comments

Comments
 (0)