Skip to content

Commit e56cac7

Browse files
committed
fix(provisioner/terraform/tfparse): skip evaluation of defaults if no workspace_tags found
1 parent 94f5d52 commit e56cac7

File tree

4 files changed

+267
-59
lines changed

4 files changed

+267
-59
lines changed

coderd/templateversions_test.go

Lines changed: 86 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,11 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
293293
type = string
294294
default = "2"
295295
}
296+
data "coder_parameter" "unrelated" {
297+
name = "unrelated"
298+
type = "list(string)"
299+
default = jsonencode(["a", "b"])
300+
}
296301
resource "null_resource" "test" {}`,
297302
},
298303
wantTags: map[string]string{"owner": "", "scope": "organization"},
@@ -301,18 +306,23 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
301306
name: "main.tf with empty workspace tags",
302307
files: map[string]string{
303308
`main.tf`: `
304-
variable "a" {
305-
type = string
306-
default = "1"
307-
}
308-
data "coder_parameter" "b" {
309-
type = string
310-
default = "2"
311-
}
312-
resource "null_resource" "test" {}
313-
data "coder_workspace_tags" "tags" {
314-
tags = {}
315-
}`,
309+
variable "a" {
310+
type = string
311+
default = "1"
312+
}
313+
data "coder_parameter" "b" {
314+
type = string
315+
default = "2"
316+
}
317+
data "coder_parameter" "unrelated" {
318+
name = "unrelated"
319+
type = "list(string)"
320+
default = jsonencode(["a", "b"])
321+
}
322+
resource "null_resource" "test" {}
323+
data "coder_workspace_tags" "tags" {
324+
tags = {}
325+
}`,
316326
},
317327
wantTags: map[string]string{"owner": "", "scope": "organization"},
318328
},
@@ -328,6 +338,11 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
328338
type = string
329339
default = "2"
330340
}
341+
data "coder_parameter" "unrelated" {
342+
name = "unrelated"
343+
type = "list(string)"
344+
default = jsonencode(["a", "b"])
345+
}
331346
resource "null_resource" "test" {}
332347
data "coder_workspace_tags" "tags" {
333348
tags = {
@@ -343,22 +358,28 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
343358
name: "main.tf with workspace tags and request tags",
344359
files: map[string]string{
345360
`main.tf`: `
346-
variable "a" {
347-
type = string
348-
default = "1"
349-
}
350-
data "coder_parameter" "b" {
351-
type = string
352-
default = "2"
353-
}
354-
resource "null_resource" "test" {}
355-
data "coder_workspace_tags" "tags" {
356-
tags = {
357-
"foo": "bar",
358-
"a": var.a,
359-
"b": data.coder_parameter.b.value,
361+
// This file is the same as the above, except for this comment.
362+
variable "a" {
363+
type = string
364+
default = "1"
365+
}
366+
data "coder_parameter" "b" {
367+
type = string
368+
default = "2"
360369
}
361-
}`,
370+
data "coder_parameter" "unrelated" {
371+
name = "unrelated"
372+
type = "list(string)"
373+
default = jsonencode(["a", "b"])
374+
}
375+
resource "null_resource" "test" {}
376+
data "coder_workspace_tags" "tags" {
377+
tags = {
378+
"foo": "bar",
379+
"a": var.a,
380+
"b": data.coder_parameter.b.value,
381+
}
382+
}`,
362383
},
363384
reqTags: map[string]string{"baz": "zap", "foo": "noclobber"},
364385
wantTags: map[string]string{"owner": "", "scope": "organization", "foo": "bar", "baz": "zap", "a": "1", "b": "2"},
@@ -375,6 +396,11 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
375396
type = string
376397
default = "2"
377398
}
399+
data "coder_parameter" "unrelated" {
400+
name = "unrelated"
401+
type = "list(string)"
402+
default = jsonencode(["a", "b"])
403+
}
378404
resource "null_resource" "test" {
379405
name = "foo"
380406
}
@@ -401,6 +427,11 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
401427
type = string
402428
default = "2"
403429
}
430+
data "coder_parameter" "unrelated" {
431+
name = "unrelated"
432+
type = "list(string)"
433+
default = jsonencode(["a", "b"])
434+
}
404435
resource "null_resource" "test" {
405436
name = "foo"
406437
}
@@ -423,6 +454,11 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
423454
name: "main.tf with workspace tags that attempts to set user scope",
424455
files: map[string]string{
425456
`main.tf`: `
457+
data "coder_parameter" "unrelated" {
458+
name = "unrelated"
459+
type = "list(string)"
460+
default = jsonencode(["a", "b"])
461+
}
426462
resource "null_resource" "test" {}
427463
data "coder_workspace_tags" "tags" {
428464
tags = {
@@ -437,6 +473,11 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
437473
name: "main.tf with workspace tags that attempt to clobber org ID",
438474
files: map[string]string{
439475
`main.tf`: `
476+
data "coder_parameter" "unrelated" {
477+
name = "unrelated"
478+
type = "list(string)"
479+
default = jsonencode(["a", "b"])
480+
}
440481
resource "null_resource" "test" {}
441482
data "coder_workspace_tags" "tags" {
442483
tags = {
@@ -451,6 +492,11 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
451492
name: "main.tf with workspace tags that set scope=user",
452493
files: map[string]string{
453494
`main.tf`: `
495+
data "coder_parameter" "unrelated" {
496+
name = "unrelated"
497+
type = "list(string)"
498+
default = jsonencode(["a", "b"])
499+
}
454500
resource "null_resource" "test" {}
455501
data "coder_workspace_tags" "tags" {
456502
tags = {
@@ -460,6 +506,19 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) {
460506
},
461507
wantTags: map[string]string{"owner": templateAdminUser.ID.String(), "scope": "user"},
462508
},
509+
// Ref: https://github.com/coder/coder/issues/16021
510+
{
511+
name: "main.tf with no workspace_tags and a function call in a parameter default",
512+
files: map[string]string{
513+
`main.tf`: `
514+
data "coder_parameter" "unrelated" {
515+
name = "unrelated"
516+
type = "list(string)"
517+
default = jsonencode(["a", "b"])
518+
}`,
519+
},
520+
wantTags: map[string]string{"owner": "", "scope": "organization"},
521+
},
463522
} {
464523
tt := tt
465524
t.Run(tt.name, func(t *testing.T) {

enterprise/coderd/workspaces_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1412,6 +1412,11 @@ func TestWorkspaceTagsTerraform(t *testing.T) {
14121412
provider "coder" {}
14131413
data "coder_workspace" "me" {}
14141414
data "coder_workspace_owner" "me" {}
1415+
data "coder_parameter" "unrelated" {
1416+
name = "unrelated"
1417+
type = "list(string)"
1418+
default = jsonencode(["a", "b"])
1419+
}
14151420
%s
14161421
`
14171422

provisioner/terraform/tfparse/tfparse.go

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ func New(workdir string, opts ...Option) (*Parser, tfconfig.Diagnostics) {
8080
}
8181

8282
// WorkspaceTags looks for all coder_workspace_tags datasource in the module
83-
// and returns the raw values for the tags. Use
83+
// and returns the raw values for the tags.
8484
func (p *Parser) WorkspaceTags(ctx context.Context) (map[string]string, error) {
8585
tags := map[string]string{}
8686
var skipped []string
@@ -166,13 +166,17 @@ func (p *Parser) WorkspaceTagDefaults(ctx context.Context) (map[string]string, e
166166
return nil, xerrors.Errorf("extract workspace tags: %w", err)
167167
}
168168

169+
if len(tags) == 0 {
170+
return map[string]string{}, nil
171+
}
172+
169173
// To evaluate the expressions, we need to load the default values for
170174
// variables and parameters.
171-
varsDefaults, err := p.VariableDefaults(ctx)
175+
varsDefaults, err := p.VariableDefaults(ctx, tags)
172176
if err != nil {
173177
return nil, xerrors.Errorf("load variable defaults: %w", err)
174178
}
175-
paramsDefaults, err := p.CoderParameterDefaults(ctx, varsDefaults)
179+
paramsDefaults, err := p.CoderParameterDefaults(ctx, varsDefaults, tags)
176180
if err != nil {
177181
return nil, xerrors.Errorf("load parameter defaults: %w", err)
178182
}
@@ -247,28 +251,39 @@ func WriteArchive(bs []byte, mimetype string, path string) error {
247251
return nil
248252
}
249253

250-
// VariableDefaults returns the default values for all variables passed to it.
251-
func (p *Parser) VariableDefaults(ctx context.Context) (map[string]string, error) {
254+
// VariableDefaults returns the default values for all variables referenced in the values of tags.
255+
func (p *Parser) VariableDefaults(ctx context.Context, tags map[string]string) (map[string]string, error) {
256+
var skipped []string
252257
// iterate through vars to get the default values for all
253-
// variables.
258+
// required variables.
254259
m := make(map[string]string)
255260
for _, v := range p.module.Variables {
256261
if v == nil {
257262
continue
258263
}
264+
var found bool
265+
for _, tv := range tags {
266+
if strings.Contains(tv, v.Name) {
267+
found = true
268+
}
269+
}
270+
if !found {
271+
skipped = append(skipped, "var."+v.Name)
272+
continue
273+
}
259274
sv, err := interfaceToString(v.Default)
260275
if err != nil {
261276
return nil, xerrors.Errorf("can't convert variable default value to string: %v", err)
262277
}
263278
m[v.Name] = strings.Trim(sv, `"`)
264279
}
265-
p.logger.Debug(ctx, "found default values for variables", slog.F("defaults", m))
280+
p.logger.Debug(ctx, "found default values for variables", slog.F("defaults", m), slog.F("skipped", skipped))
266281
return m, nil
267282
}
268283

269284
// CoderParameterDefaults returns the default values of all coder_parameter data sources
270285
// in the parsed module.
271-
func (p *Parser) CoderParameterDefaults(ctx context.Context, varsDefaults map[string]string) (map[string]string, error) {
286+
func (p *Parser) CoderParameterDefaults(ctx context.Context, varsDefaults map[string]string, tags map[string]string) (map[string]string, error) {
272287
defaultsM := make(map[string]string)
273288
var (
274289
skipped []string
@@ -290,6 +305,18 @@ func (p *Parser) CoderParameterDefaults(ctx context.Context, varsDefaults map[st
290305
continue
291306
}
292307

308+
var found bool
309+
needle := strings.Join([]string{"data", dataResource.Type, dataResource.Name}, ".")
310+
for _, tv := range tags {
311+
if strings.Contains(tv, needle) {
312+
found = true
313+
}
314+
}
315+
if !found {
316+
skipped = append(skipped, needle)
317+
continue
318+
}
319+
293320
// We know in which HCL file is the data resource defined.
294321
// NOTE: hclparse.Parser will cache multiple successive calls to parse the same file.
295322
file, diags = p.underlying.ParseHCLFile(dataResource.Pos.Filename)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy