Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

plugin2host: Send marked values over the wire #239

Merged
merged 1 commit into from
Mar 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 40 additions & 2 deletions plugin/fromproto/fromproto.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/hashicorp/hcl/v2"
"github.com/terraform-linters/tflint-plugin-sdk/hclext"
"github.com/terraform-linters/tflint-plugin-sdk/plugin/proto"
"github.com/terraform-linters/tflint-plugin-sdk/terraform/lang/marks"
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/msgpack"
Expand Down Expand Up @@ -161,7 +162,7 @@ func Expression(expr *proto.Expression) (hcl.Expression, hcl.Diagnostics) {
return nil, diags
}
if expr.Value != nil {
val, err := msgpack.Unmarshal(expr.Value, cty.DynamicPseudoType)
val, err := Value(expr.Value, cty.DynamicPseudoType, expr.ValueMarks)
if err != nil {
panic(fmt.Errorf("cannot unmarshal the bound expr: %w", err))
}
Expand Down Expand Up @@ -210,6 +211,43 @@ func Pos(pos *proto.Range_Pos) hcl.Pos {
}
}

// Value converts msgpack and []proto.ValueMark to cty.Value
func Value(value []byte, ty cty.Type, valueMarks []*proto.ValueMark) (cty.Value, error) {
val, err := msgpack.Unmarshal(value, ty)
if err != nil {
return cty.NilVal, err
}

pvm := make([]cty.PathValueMarks, len(valueMarks))
for idx, mark := range valueMarks {
pvm[idx] = cty.PathValueMarks{
Path: AttributePath(mark.Path),
}
if mark.Sensitive {
pvm[idx].Marks = cty.NewValueMarks(marks.Sensitive)
}
}

return val.MarkWithPaths(pvm), nil
}

// AttributePath converts proto.AttributePath to cty.Path
func AttributePath(path *proto.AttributePath) cty.Path {
ret := cty.Path{}

for _, step := range path.Steps {
switch s := step.Selector.(type) {
case *proto.AttributePath_Step_ElementKeyString:
ret = ret.IndexString(s.ElementKeyString)
case *proto.AttributePath_Step_ElementKeyInt:
ret = ret.IndexInt(int(s.ElementKeyInt))
case *proto.AttributePath_Step_AttributeName:
ret = ret.GetAttr(s.AttributeName)
}
}
return ret
}

// Config converts proto.ApplyGlobalConfig_Config to tflint.Config
func Config(config *proto.ApplyGlobalConfig_Config) *tflint.Config {
if config == nil {
Expand Down Expand Up @@ -313,7 +351,7 @@ func Error(err error) error {
case proto.ErrorCode_ERROR_CODE_UNEVALUABLE:
return fmt.Errorf("%s%w", st.Message(), tflint.ErrUnevaluable)
case proto.ErrorCode_ERROR_CODE_SENSITIVE:
return fmt.Errorf("%s%w", st.Message(), tflint.ErrSensitive)
return tflint.ErrSensitive
}
}

Expand Down
9 changes: 6 additions & 3 deletions plugin/plugin2host/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/gocty"
"github.com/zclconf/go-cty/cty/json"
"github.com/zclconf/go-cty/cty/msgpack"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
Expand Down Expand Up @@ -327,7 +326,7 @@ func (c *GRPCClient) EvaluateExpr(expr hcl.Expression, ret interface{}, opts *tf
return fromproto.Error(err)
}

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

// Returns an error if the value cannot be decoded to a Go value (e.g. unknown value, null).
// Returns an error if the value cannot be decoded to a Go value (e.g. unknown, null, sensitive).
// This allows the caller to handle the value by the errors package.
err = cty.Walk(val, func(path cty.Path, v cty.Value) (bool, error) {
if !v.IsKnown() {
Expand All @@ -347,6 +346,10 @@ func (c *GRPCClient) EvaluateExpr(expr hcl.Expression, ret interface{}, opts *tf
logger.Debug(fmt.Sprintf("null value found in %s", expr.Range()))
return false, tflint.ErrNullValue
}
if v.IsMarked() {
logger.Debug(fmt.Sprintf("sensitive value found in %s", expr.Range()))
return false, tflint.ErrSensitive
}
return true, nil
})
if err != nil {
Expand Down
93 changes: 93 additions & 0 deletions plugin/plugin2host/plugin2host_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/terraform-linters/tflint-plugin-sdk/hclext"
"github.com/terraform-linters/tflint-plugin-sdk/plugin/proto"
"github.com/terraform-linters/tflint-plugin-sdk/terraform/addrs"
"github.com/terraform-linters/tflint-plugin-sdk/terraform/lang/marks"
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
"github.com/zclconf/go-cty/cty"
"google.golang.org/grpc"
Expand Down Expand Up @@ -1855,6 +1856,98 @@ func TestEvaluateExpr(t *testing.T) {
return !errors.Is(err, tflint.ErrNullValue)
},
},
{
Name: "sensitive",
Expr: hclExpr(`var.foo`),
TargetType: reflect.TypeOf(""),
ServerImpl: func(expr hcl.Expression, opts tflint.EvaluateExprOption) (cty.Value, error) {
return evalExpr(expr, &hcl.EvalContext{
Variables: map[string]cty.Value{
"var": cty.MapVal(map[string]cty.Value{
"foo": cty.StringVal("bar").Mark(marks.Sensitive),
}),
},
})
},
Want: "",
GetFileImpl: fileExists,
ErrCheck: func(err error) bool {
return !errors.Is(err, tflint.ErrSensitive)
},
},
{
Name: "sensitive as cty.Value",
Expr: hclExpr(`var.foo`),
TargetType: reflect.TypeOf(cty.Value{}),
ServerImpl: func(expr hcl.Expression, opts tflint.EvaluateExprOption) (cty.Value, error) {
return evalExpr(expr, &hcl.EvalContext{
Variables: map[string]cty.Value{
"var": cty.MapVal(map[string]cty.Value{
"foo": cty.StringVal("bar").Mark(marks.Sensitive),
}),
},
})
},
Want: cty.StringVal("bar").Mark(marks.Sensitive),
GetFileImpl: fileExists,
ErrCheck: neverHappend,
},
{
Name: "sensitive in object",
Expr: hclExpr(`{ value = var.foo }`),
TargetType: reflect.TypeOf(map[string]string{}),
ServerImpl: func(expr hcl.Expression, opts tflint.EvaluateExprOption) (cty.Value, error) {
return evalExpr(expr, &hcl.EvalContext{
Variables: map[string]cty.Value{
"var": cty.MapVal(map[string]cty.Value{
"foo": cty.StringVal("bar").Mark(marks.Sensitive),
}),
},
})
},
Want: (map[string]string)(nil),
GetFileImpl: fileExists,
ErrCheck: func(err error) bool {
return !errors.Is(err, tflint.ErrSensitive)
},
},
{
Name: "sensitive object as cty.Value",
Expr: hclExpr(`var.foo`),
TargetType: reflect.TypeOf(cty.Value{}),
ServerImpl: func(expr hcl.Expression, opts tflint.EvaluateExprOption) (cty.Value, error) {
return evalExpr(expr, &hcl.EvalContext{
Variables: map[string]cty.Value{
"var": cty.MapVal(map[string]cty.Value{
"foo": cty.ObjectVal(map[string]cty.Value{
"bar": cty.StringVal("barval").Mark(marks.Sensitive),
"baz": cty.ListVal([]cty.Value{cty.NumberIntVal(1).Mark(marks.Sensitive)}),
"qux": cty.TupleVal([]cty.Value{cty.StringVal("quxval").Mark(marks.Sensitive)}),
"quux": cty.MapVal(map[string]cty.Value{
"foo": cty.StringVal("fooval").Mark(marks.Sensitive),
}),
"corge": cty.ObjectVal(map[string]cty.Value{
"bar": cty.NumberIntVal(2).Mark(marks.Sensitive),
}),
}),
}),
},
})
},
Want: cty.ObjectVal(map[string]cty.Value{
"bar": cty.StringVal("barval").Mark(marks.Sensitive),
"baz": cty.ListVal([]cty.Value{cty.NumberIntVal(1).Mark(marks.Sensitive)}),
"qux": cty.TupleVal([]cty.Value{cty.StringVal("quxval").Mark(marks.Sensitive)}),
"quux": cty.MapVal(map[string]cty.Value{
"foo": cty.StringVal("fooval").Mark(marks.Sensitive),
}),
"corge": cty.ObjectVal(map[string]cty.Value{
"bar": cty.NumberIntVal(2).Mark(marks.Sensitive),
}),
}),
GetFileImpl: fileExists,
ErrCheck: neverHappend,
},
}

for _, test := range tests {
Expand Down
5 changes: 2 additions & 3 deletions plugin/plugin2host/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/json"
"github.com/zclconf/go-cty/cty/msgpack"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
Expand Down Expand Up @@ -156,12 +155,12 @@ func (s *GRPCServer) EvaluateExpr(ctx context.Context, req *proto.EvaluateExpr_R
if err != nil {
return nil, toproto.Error(codes.FailedPrecondition, err)
}
val, err := msgpack.Marshal(value, ty)
val, marks, err := toproto.Value(value, ty)
if err != nil {
return nil, toproto.Error(codes.FailedPrecondition, err)
}

return &proto.EvaluateExpr_Response{Value: val}, nil
return &proto.EvaluateExpr_Response{Value: val, Marks: marks}, nil
}

// EmitIssue emits the issue with the passed rule, message, location
Expand Down
Loading