Skip to content

Commit

Permalink
Merge pull request #440 from hashicorp/pselle/mark-objs
Browse files Browse the repository at this point in the history
Mark objects with keys that are sensitive
  • Loading branch information
Pam Selle authored Jan 5, 2021
2 parents 29a3c5e + b6fc34e commit e0dbad0
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 34 deletions.
39 changes: 11 additions & 28 deletions hclsyntax/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,7 @@ func (e *ObjectConsExpr) walkChildNodes(w internalWalkFunc) {
func (e *ObjectConsExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
var vals map[string]cty.Value
var diags hcl.Diagnostics
var marks []cty.ValueMarks

// This will get set to true if we fail to produce any of our keys,
// either because they are actually unknown or if the evaluation produces
Expand Down Expand Up @@ -825,18 +826,8 @@ func (e *ObjectConsExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics
continue
}

if key.IsMarked() {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Marked value as key",
Detail: "Can't use a marked value as a key.",
Subject: item.ValueExpr.Range().Ptr(),
Expression: item.KeyExpr,
EvalContext: ctx,
})
known = false
continue
}
key, keyMarks := key.Unmark()
marks = append(marks, keyMarks)

var err error
key, err = convert.Convert(key, cty.String)
Expand Down Expand Up @@ -867,7 +858,7 @@ func (e *ObjectConsExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics
return cty.DynamicVal, diags
}

return cty.ObjectVal(vals), diags
return cty.ObjectVal(vals).WithMarks(marks...), diags
}

func (e *ObjectConsExpr) Range() hcl.Range {
Expand Down Expand Up @@ -997,6 +988,7 @@ type ForExpr struct {

func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
var diags hcl.Diagnostics
var marks []cty.ValueMarks

collVal, collDiags := e.CollExpr.Value(ctx)
diags = append(diags, collDiags...)
Expand All @@ -1018,7 +1010,8 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
}
// Unmark collection before checking for iterability, because marked
// values cannot be iterated
collVal, marks := collVal.Unmark()
collVal, collMarks := collVal.Unmark()
marks = append(marks, collMarks)
if !collVal.CanIterateElements() {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Expand Down Expand Up @@ -1198,18 +1191,8 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
continue
}

if key.IsMarked() {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid object key",
Detail: "Marked values cannot be used as object keys.",
Subject: e.KeyExpr.Range().Ptr(),
Context: &e.SrcRange,
Expression: e.KeyExpr,
EvalContext: childCtx,
})
continue
}
key, keyMarks := key.Unmark()
marks = append(marks, keyMarks)

val, valDiags := e.ValExpr.Value(childCtx)
diags = append(diags, valDiags...)
Expand Down Expand Up @@ -1249,7 +1232,7 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
}
}

return cty.ObjectVal(vals).WithMarks(marks), diags
return cty.ObjectVal(vals).WithMarks(marks...), diags

} else {
// Producing a tuple
Expand Down Expand Up @@ -1335,7 +1318,7 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
return cty.DynamicVal, diags
}

return cty.TupleVal(vals).WithMarks(marks), diags
return cty.TupleVal(vals).WithMarks(marks...), diags
}
}

Expand Down
39 changes: 33 additions & 6 deletions hclsyntax/expression_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -516,8 +516,11 @@ upper(
}),
},
},
cty.DynamicVal,
1,
cty.ObjectVal(map[string]cty.Value{
"hello": cty.StringVal("world"),
"goodbye": cty.StringVal("earth"),
}).Mark("marked"),
0,
},
{
`{"${var.greeting}" = "world"}`,
Expand Down Expand Up @@ -918,20 +921,44 @@ upper(
}),
0,
},
{ // Error when using marked value as object key
{
// Mark object if keys include marked values, members retain
// their original marks in their values
`{for v in things: v => "${v}-friend"}`,
&hcl.EvalContext{
Variables: map[string]cty.Value{
"things": cty.MapVal(map[string]cty.Value{
"a": cty.StringVal("rosie").Mark("sensitive"),
"a": cty.StringVal("rosie").Mark("marked"),
"b": cty.StringVal("robin"),
// Check for double-marking when a key val has a duplicate mark
"c": cty.StringVal("rowan").Mark("marked"),
"d": cty.StringVal("ruben").Mark("also-marked"),
}),
},
},
cty.ObjectVal(map[string]cty.Value{
"rosie": cty.StringVal("rosie-friend").Mark("marked"),
"robin": cty.StringVal("robin-friend"),
}),
1,
"rowan": cty.StringVal("rowan-friend").Mark("marked"),
"ruben": cty.StringVal("ruben-friend").Mark("also-marked"),
}).WithMarks(cty.NewValueMarks("marked", "also-marked")),
0,
},
{ // object itself is marked, contains marked value
`{for v in things: v => "${v}-friend"}`,
&hcl.EvalContext{
Variables: map[string]cty.Value{
"things": cty.MapVal(map[string]cty.Value{
"a": cty.StringVal("rosie").Mark("marked"),
"b": cty.StringVal("robin"),
}).Mark("marks"),
},
},
cty.ObjectVal(map[string]cty.Value{
"rosie": cty.StringVal("rosie-friend").Mark("marked"),
"robin": cty.StringVal("robin-friend"),
}).WithMarks(cty.NewValueMarks("marked", "marks")),
0,
},
{ // Sequence for loop with marked conditional expression
`[for x in things: x if x != secret]`,
Expand Down

0 comments on commit e0dbad0

Please sign in to comment.