Skip to content

Commit e068f68

Browse files
committed
add some more work to tags and doing a lazy eval
1 parent 8c4cbf0 commit e068f68

File tree

5 files changed

+160
-66
lines changed

5 files changed

+160
-66
lines changed

cli/clidisplay/resources.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func WorkspaceTags(writer io.Writer, tags types.TagBlocks) hcl.Diagnostics {
3434
//}
3535
}
3636

37-
k := tag.SafeKeyString()
37+
k := tag.KeyString()
3838
refs := tag.References()
3939
tableWriter.AppendRow(table.Row{k, "??", strings.Join(refs, "\n")})
4040

testdata/notstringtag/main.tf

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
terraform {
2+
required_providers {
3+
coder = {
4+
source = "coder/coder"
5+
}
6+
docker = {
7+
source = "kreuzwerker/docker"
8+
version = "3.0.2"
9+
}
10+
}
11+
}
12+
13+
data "coder_workspace_tags" "custom_workspace_tags" {
14+
tags = {
15+
"zone" = 5
16+
10 = "hello"
17+
# "hello"
18+
}
19+
}
20+

types/tags.go

Lines changed: 13 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ package types
22

33
import (
44
"github.com/aquasecurity/trivy/pkg/iac/terraform"
5-
"github.com/hashicorp/hcl/v2"
6-
"github.com/zclconf/go-cty/cty"
75

86
"github.com/coder/preview/hclext"
97
)
@@ -48,11 +46,12 @@ func (b TagBlock) InvalidTags() Tags {
4846
func (b TagBlock) ValidTags() map[string]string {
4947
tags := make(map[string]string)
5048
for _, tag := range b.Tags {
51-
if !tag.Valid() {
49+
if !tag.Valid() || !tag.IsKnown() {
5250
continue
5351
}
5452

55-
tags[tag.Key.AsString()] = tag.Value.AsString()
53+
k, v := tag.AsStrings()
54+
tags[k] = v
5655
}
5756
return tags
5857
}
@@ -62,49 +61,32 @@ type Tags []Tag
6261
func (t Tags) SafeNames() []string {
6362
names := make([]string, 0)
6463
for _, tag := range t {
65-
names = append(names, tag.SafeKeyString())
64+
names = append(names, tag.KeyString())
6665
}
6766
return names
6867
}
6968

7069
type Tag struct {
71-
Key cty.Value
72-
// SafeKeyID can be used if the Key val is unknown
73-
SafeKeyID string
74-
KeyExpr hcl.Expression
75-
76-
Value cty.Value
77-
ValueExpr hcl.Expression
70+
Key HCLString
71+
Value HCLString
7872
}
7973

8074
func (t Tag) Valid() bool {
81-
if !t.Key.IsWhollyKnown() || !t.Value.IsWhollyKnown() {
82-
return false
83-
}
84-
if !t.Key.Type().Equals(cty.String) || !t.Value.Type().Equals(cty.String) {
85-
return false
86-
}
87-
if t.Key.IsNull() || t.Value.IsNull() {
88-
return false
89-
}
90-
return true
75+
return t.Key.Valid() && t.Value.Valid()
9176
}
9277

9378
func (t Tag) IsKnown() bool {
9479
return t.Key.IsKnown() && t.Value.IsKnown()
9580
}
9681

97-
func (t Tag) AsStrings() (string, string) {
98-
return t.Key.AsString(), t.Value.AsString()
82+
func (t Tag) KeyString() string {
83+
return t.Key.AsString()
9984
}
10085

101-
func (t Tag) References() []string {
102-
return append(hclext.ReferenceNames(t.KeyExpr), hclext.ReferenceNames(t.ValueExpr)...)
86+
func (t Tag) AsStrings() (string, string) {
87+
return t.KeyString(), t.Value.AsString()
10388
}
10489

105-
func (t Tag) SafeKeyString() string {
106-
if t.Key.Type().Equals(cty.String) {
107-
return t.Key.AsString()
108-
}
109-
return t.SafeKeyID
90+
func (t Tag) References() []string {
91+
return append(hclext.ReferenceNames(t.Key.ValueExpr), hclext.ReferenceNames(t.Value.ValueExpr)...)
11092
}

types/value.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package types
2+
3+
import (
4+
"github.com/hashicorp/hcl/v2"
5+
"github.com/zclconf/go-cty/cty"
6+
)
7+
8+
type HCLString struct {
9+
Value cty.Value
10+
11+
// ValueDiags are any diagnostics that occurred
12+
// while evaluating the value
13+
ValueDiags hcl.Diagnostics
14+
// ValueExp is the underlying source expression
15+
ValueExpr hcl.Expression
16+
// Source is the literal hcl text that was parsed.
17+
// This is a best effort, it may not be available.
18+
Source *string
19+
}
20+
21+
// AsString is a safe function. It will always return a string.
22+
// The caller should check if this value is Valid and known before
23+
// calling this function.
24+
func (s HCLString) AsString() string {
25+
if s.Valid() && s.Value.IsKnown() {
26+
return s.Value.AsString()
27+
}
28+
29+
if s.Source != nil {
30+
return *s.Source
31+
}
32+
33+
return "??"
34+
}
35+
36+
func (s HCLString) IsKnown() bool {
37+
return s.Valid() && s.Value.IsWhollyKnown()
38+
}
39+
40+
func (s HCLString) Valid() bool {
41+
if s.ValueDiags.HasErrors() {
42+
return false
43+
}
44+
45+
if !s.Value.Type().Equals(cty.String) {
46+
return false
47+
}
48+
49+
if s.Value.IsNull() {
50+
return false
51+
}
52+
53+
return true
54+
}

workspacetags.go

Lines changed: 72 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -50,43 +50,13 @@ func WorkspaceTags(modules terraform.Modules, files map[string]*hcl.File) (types
5050

5151
var tags []types.Tag
5252
for _, item := range tagsObj.Items {
53-
key, kdiags := item.KeyExpr.Value(evCtx)
54-
val, vdiags := item.ValueExpr.Value(evCtx)
55-
56-
// TODO: what do do with the diags?
57-
if kdiags.HasErrors() {
58-
key = cty.UnknownVal(cty.String)
59-
}
60-
if vdiags.HasErrors() {
61-
val = cty.UnknownVal(cty.String)
62-
}
63-
64-
if key.IsKnown() && key.Type() != cty.String {
65-
r := item.KeyExpr.Range()
66-
diags = diags.Append(&hcl.Diagnostic{
67-
Severity: hcl.DiagError,
68-
Summary: "Invalid key type for tags",
69-
Detail: fmt.Sprintf("Key must be a string, but got %s", key.Type().FriendlyName()),
70-
Subject: &r,
71-
Context: &tagsObj.SrcRange,
72-
Expression: item.KeyExpr,
73-
EvalContext: evCtx,
74-
})
53+
tag, tagDiag := NewTag(tagsObj, files, item, evCtx)
54+
if tagDiag != nil {
55+
diags = diags.Append(tagDiag)
7556
continue
7657
}
7758

78-
safe, err := source(item.KeyExpr.Range(), files)
79-
if err != nil {
80-
safe = []byte("???") // we could do more here
81-
}
82-
83-
tags = append(tags, types.Tag{
84-
Key: key,
85-
SafeKeyID: string(safe),
86-
KeyExpr: item.KeyExpr,
87-
Value: val,
88-
ValueExpr: item.ValueExpr,
89-
})
59+
tags = append(tags, tag)
9060
}
9161
tagBlocks = append(tagBlocks, types.TagBlock{
9262
Tags: tags,
@@ -97,3 +67,71 @@ func WorkspaceTags(modules terraform.Modules, files map[string]*hcl.File) (types
9767

9868
return tagBlocks, diags
9969
}
70+
71+
// NewTag creates a workspace tag from its hcl expression.
72+
func NewTag(block *hclsyntax.ObjectConsExpr, files map[string]*hcl.File, expr hclsyntax.ObjectConsItem, evCtx *hcl.EvalContext) (types.Tag, *hcl.Diagnostic) {
73+
key, kdiags := expr.KeyExpr.Value(evCtx)
74+
val, vdiags := expr.ValueExpr.Value(evCtx)
75+
76+
// TODO: ???
77+
78+
//if kdiags.HasErrors() {
79+
// key = cty.UnknownVal(cty.String)
80+
//}
81+
//if vdiags.HasErrors() {
82+
// val = cty.UnknownVal(cty.String)
83+
//}
84+
85+
if key.IsKnown() && key.Type() != cty.String {
86+
r := expr.KeyExpr.Range()
87+
return types.Tag{}, &hcl.Diagnostic{
88+
Severity: hcl.DiagError,
89+
Summary: "Invalid key type for tags",
90+
Detail: fmt.Sprintf("Key must be a string, but got %s", key.Type().FriendlyName()),
91+
Subject: &r,
92+
Context: &block.SrcRange,
93+
Expression: expr.KeyExpr,
94+
EvalContext: evCtx,
95+
}
96+
}
97+
98+
if val.IsKnown() && val.Type() != cty.String {
99+
r := expr.ValueExpr.Range()
100+
return types.Tag{}, &hcl.Diagnostic{
101+
Severity: hcl.DiagError,
102+
Summary: "Invalid value type for tag",
103+
Detail: fmt.Sprintf("Value must be a string, but got %s", val.Type().FriendlyName()),
104+
Subject: &r,
105+
Context: &block.SrcRange,
106+
Expression: expr.ValueExpr,
107+
EvalContext: evCtx,
108+
}
109+
}
110+
111+
tag := types.Tag{
112+
Key: types.HCLString{
113+
Value: key,
114+
ValueDiags: kdiags,
115+
ValueExpr: expr.KeyExpr,
116+
},
117+
Value: types.HCLString{
118+
Value: val,
119+
ValueDiags: vdiags,
120+
ValueExpr: expr.ValueExpr,
121+
},
122+
}
123+
124+
ks, err := source(expr.KeyExpr.Range(), files)
125+
if err == nil {
126+
src := string(ks)
127+
tag.Key.Source = &src
128+
}
129+
130+
vs, err := source(expr.ValueExpr.Range(), files)
131+
if err == nil {
132+
src := string(vs)
133+
tag.Value.Source = &src
134+
}
135+
136+
return tag, nil
137+
}

0 commit comments

Comments
 (0)