From b631d54114982b4744a390ba7c502af1b3877da5 Mon Sep 17 00:00:00 2001 From: Isabel Andrade Date: Tue, 1 Jun 2021 13:50:32 +0100 Subject: [PATCH] Add `IsSensitive` to `AttributeSchema` So that sensitive attributes can be flagged. --- decoder/attribute_candidates.go | 19 ++++---- decoder/body_decoder_test.go | 2 +- decoder/candidates_test.go | 79 +++++++++++++++++++++++++++++---- decoder/hover_test.go | 22 ++++++++- schema/attribute_schema.go | 2 + schema/attribute_schema_test.go | 10 +++++ 6 files changed, 113 insertions(+), 21 deletions(-) diff --git a/decoder/attribute_candidates.go b/decoder/attribute_candidates.go index 2418b428..4eb961a4 100644 --- a/decoder/attribute_candidates.go +++ b/decoder/attribute_candidates.go @@ -28,23 +28,24 @@ func attributeSchemaToCandidate(name string, attr *schema.AttributeSchema, rng h } func detailForAttribute(attr *schema.AttributeSchema) string { - var detail string + details := []string{} + if attr.IsRequired { - detail = "Required" + details = append(details, "required") } else if attr.IsOptional { - detail = "Optional" + details = append(details, "optional") + } + + if attr.IsSensitive { + details = append(details, "sensitive") } friendlyName := attr.Expr.FriendlyName() if friendlyName != "" { - if detail != "" { - detail = strings.Join([]string{detail, friendlyName}, ", ") - } else { - detail = friendlyName - } + details = append(details, friendlyName) } - return detail + return strings.Join(details[:], ", ") } func snippetForAttribute(name string, attr *schema.AttributeSchema) string { diff --git a/decoder/body_decoder_test.go b/decoder/body_decoder_test.go index 32d17a4f..58cd35ef 100644 --- a/decoder/body_decoder_test.go +++ b/decoder/body_decoder_test.go @@ -127,7 +127,7 @@ func TestDecoder_CandidateAtPos_computedAttributes(t *testing.T) { List: []lang.Candidate{ { Label: "attr2", - Detail: "Optional, number", + Detail: "optional, number", TextEdit: lang.TextEdit{ Range: hcl.Range{ Filename: "test.tf", diff --git a/decoder/candidates_test.go b/decoder/candidates_test.go index 81d349d5..e140f5da 100644 --- a/decoder/candidates_test.go +++ b/decoder/candidates_test.go @@ -770,6 +770,16 @@ func TestDecoder_CandidatesAtPos_basic(t *testing.T) { "five": {Expr: schema.LiteralTypeOnly(cty.DynamicPseudoType)}, }, }, + schema.NewSchemaKey(schema.DependencyKeys{ + Labels: []schema.LabelDependent{ + {Index: 0, Value: "sensitive_resource"}, + }, + }): { + Attributes: map[string]*schema.AttributeSchema{ + "six": {Expr: schema.LiteralTypeOnly(cty.Number), IsSensitive: true}, + "seven": {Expr: schema.LiteralTypeOnly(cty.Number), IsRequired: true, IsSensitive: true}, + }, + }, }, } @@ -783,6 +793,10 @@ func TestDecoder_CandidatesAtPos_basic(t *testing.T) { count = 3 } +resource "sensitive_resource" "t" { + count = 2 +} + resource "random_resource" "test" { arg = "" } @@ -877,6 +891,19 @@ resource "random_resource" "test" { }, Kind: lang.LabelCandidateKind, }, + { + Label: "sensitive_resource", + TextEdit: lang.TextEdit{ + Range: hcl.Range{ + Filename: "test.tf", + Start: hcl.Pos{Line: 1, Column: 11, Byte: 10}, + End: hcl.Pos{Line: 1, Column: 25, Byte: 24}, + }, + NewText: "sensitive_resource", + Snippet: "sensitive_resource", + }, + Kind: lang.LabelCandidateKind, + }, }), }, { @@ -885,7 +912,7 @@ resource "random_resource" "test" { lang.CompleteCandidates([]lang.Candidate{ { Label: "one", - Detail: "Required, string", + Detail: "required, string", TextEdit: lang.TextEdit{ Range: hcl.Range{ Filename: "test.tf", @@ -899,7 +926,7 @@ resource "random_resource" "test" { }, { Label: "three", - Detail: "Optional, bool", + Detail: "optional, bool", TextEdit: lang.TextEdit{ Range: hcl.Range{ Filename: "test.tf", @@ -914,7 +941,7 @@ resource "random_resource" "test" { }, { Label: "two", - Detail: "Optional, number", + Detail: "optional, number", TextEdit: lang.TextEdit{ Range: hcl.Range{ Filename: "test.tf", @@ -934,7 +961,7 @@ resource "random_resource" "test" { lang.CompleteCandidates([]lang.Candidate{ { Label: "one", - Detail: "Required, string", + Detail: "required, string", TextEdit: lang.TextEdit{ Range: hcl.Range{ Filename: "test.tf", @@ -948,7 +975,7 @@ resource "random_resource" "test" { }, { Label: "three", - Detail: "Optional, bool", + Detail: "optional, bool", TextEdit: lang.TextEdit{ Range: hcl.Range{ Filename: "test.tf", @@ -963,7 +990,7 @@ resource "random_resource" "test" { }, { Label: "two", - Detail: "Optional, number", + Detail: "optional, number", TextEdit: lang.TextEdit{ Range: hcl.Range{ Filename: "test.tf", @@ -977,6 +1004,40 @@ resource "random_resource" "test" { }, }), }, + { + "second block attribute", + hcl.Pos{Line: 6, Column: 1, Byte: 89}, + lang.CompleteCandidates([]lang.Candidate{ + { + Label: "seven", + Detail: "required, sensitive, number", + TextEdit: lang.TextEdit{ + Range: hcl.Range{ + Filename: "test.tf", + Start: hcl.Pos{Line: 6, Column: 1, Byte: 89}, + End: hcl.Pos{Line: 6, Column: 1, Byte: 89}, + }, + NewText: "seven", + Snippet: "seven = ${1:1}", + }, + Kind: lang.AttributeCandidateKind, + }, + { + Label: "six", + Detail: "sensitive, number", + TextEdit: lang.TextEdit{ + Range: hcl.Range{ + Filename: "test.tf", + Start: hcl.Pos{Line: 6, Column: 1, Byte: 89}, + End: hcl.Pos{Line: 6, Column: 1, Byte: 89}, + }, + NewText: "six", + Snippet: "six = ${1:1}", + }, + Kind: lang.AttributeCandidateKind, + }, + }), + }, } for i, tc := range testCases { @@ -1110,7 +1171,7 @@ func TestDecoder_CandidatesAtPos_multipleTypes(t *testing.T) { expectedCandidates := lang.CompleteCandidates([]lang.Candidate{ { Label: "for_each", - Detail: "Optional, set of any single type or map of any single type", + Detail: "optional, set of any single type or map of any single type", TextEdit: lang.TextEdit{ Range: hcl.Range{ Filename: "test.tf", @@ -1194,7 +1255,7 @@ resource "any" "ref" { lang.CompleteCandidates([]lang.Candidate{ { Label: "count", - Detail: "Optional, number", + Detail: "optional, number", TextEdit: lang.TextEdit{ Range: hcl.Range{ Filename: "test.tf", @@ -1309,7 +1370,7 @@ resource "any" "ref" { lang.CompleteCandidates([]lang.Candidate{ { Label: "count", - Detail: "Optional, number", + Detail: "optional, number", TextEdit: lang.TextEdit{ Range: hcl.Range{ Filename: "test.tf", diff --git a/decoder/hover_test.go b/decoder/hover_test.go index 7bd63462..acf58358 100644 --- a/decoder/hover_test.go +++ b/decoder/hover_test.go @@ -285,6 +285,11 @@ func TestDecoder_HoverAtPos_basic(t *testing.T) { IsOptional: true, Description: lang.PlainText("Special attribute"), }, + "bool_attr": { + Expr: schema.LiteralTypeOnly(cty.Bool), + IsSensitive: true, + Description: lang.PlainText("Flag attribute"), + }, }, }, DependentBody: map[schema.SchemaKey]*schema.BodySchema{ @@ -314,6 +319,7 @@ func TestDecoder_HoverAtPos_basic(t *testing.T) { testConfig := []byte(`myblock "sushi" "salmon" { str_attr = "test" num_attr = 4 + bool_attr = true } `) d := NewDecoder() @@ -331,10 +337,10 @@ func TestDecoder_HoverAtPos_basic(t *testing.T) { expectedData *lang.HoverData }{ { - "attribute name", + "optional attribute name", hcl.Pos{Line: 2, Column: 6, Byte: 32}, &lang.HoverData{ - Content: lang.Markdown("**str_attr** _Optional, string_\n\nSpecial attribute"), + Content: lang.Markdown("**str_attr** _optional, string_\n\nSpecial attribute"), Range: hcl.Range{ Filename: "test.tf", Start: hcl.Pos{Line: 2, Column: 3, Byte: 29}, @@ -342,6 +348,18 @@ func TestDecoder_HoverAtPos_basic(t *testing.T) { }, }, }, + { + "sensitive attribute name", + hcl.Pos{Line: 4, Column: 6, Byte: 68}, + &lang.HoverData{ + Content: lang.Markdown("**bool_attr** _sensitive, bool_\n\nFlag attribute"), + Range: hcl.Range{ + Filename: "test.tf", + Start: hcl.Pos{Line: 4, Column: 3, Byte: 64}, + End: hcl.Pos{Line: 4, Column: 19, Byte: 80}, + }, + }, + }, { "block type", hcl.Pos{Line: 1, Column: 3, Byte: 2}, diff --git a/schema/attribute_schema.go b/schema/attribute_schema.go index b05d7136..47c5cb13 100644 --- a/schema/attribute_schema.go +++ b/schema/attribute_schema.go @@ -14,6 +14,7 @@ type AttributeSchema struct { IsOptional bool IsDeprecated bool IsComputed bool + IsSensitive bool Expr ExprConstraints @@ -85,6 +86,7 @@ func (as *AttributeSchema) Copy() *AttributeSchema { IsOptional: as.IsOptional, IsDeprecated: as.IsDeprecated, IsComputed: as.IsComputed, + IsSensitive: as.IsSensitive, IsDepKey: as.IsDepKey, Description: as.Description, Expr: as.Expr.Copy(), diff --git a/schema/attribute_schema_test.go b/schema/attribute_schema_test.go index 15dff35e..89448c09 100644 --- a/schema/attribute_schema_test.go +++ b/schema/attribute_schema_test.go @@ -160,6 +160,16 @@ func TestAttributeSchema_Validate(t *testing.T) { }, nil, }, + { + &AttributeSchema{ + Expr: ExprConstraints{ + TraversalExpr{OfType: cty.Number, OfScopeId: lang.ScopeId("blah")}, + }, + IsRequired: true, + IsSensitive: true, + }, + nil, + }, } for i, tc := range testCases {