diff --git a/coderd/coderdtest/dynamicparameters.go b/coderd/coderdtest/dynamicparameters.go index 28e01885560ca..c6adb6c97e786 100644 --- a/coderd/coderdtest/dynamicparameters.go +++ b/coderd/coderdtest/dynamicparameters.go @@ -29,7 +29,8 @@ type DynamicParameterTemplateParams struct { // TemplateID is used to update an existing template instead of creating a new one. TemplateID uuid.UUID - Version func(request *codersdk.CreateTemplateVersionRequest) + Version func(request *codersdk.CreateTemplateVersionRequest) + Variables []codersdk.TemplateVersionVariable } func DynamicParameterTemplate(t *testing.T, client *codersdk.Client, org uuid.UUID, args DynamicParameterTemplateParams) (codersdk.Template, codersdk.TemplateVersion) { @@ -48,6 +49,32 @@ func DynamicParameterTemplate(t *testing.T, client *codersdk.Client, org uuid.UU }, }} + userVars := make([]codersdk.VariableValue, 0, len(args.Variables)) + parseVars := make([]*proto.TemplateVariable, 0, len(args.Variables)) + for _, argv := range args.Variables { + parseVars = append(parseVars, &proto.TemplateVariable{ + Name: argv.Name, + Description: argv.Description, + Type: argv.Type, + DefaultValue: argv.DefaultValue, + Required: argv.Required, + Sensitive: argv.Sensitive, + }) + + userVars = append(userVars, codersdk.VariableValue{ + Name: argv.Name, + Value: argv.Value, + }) + } + + files.Parse = []*proto.Response{{ + Type: &proto.Response_Parse{ + Parse: &proto.ParseComplete{ + TemplateVariables: parseVars, + }, + }, + }} + mime := codersdk.ContentTypeTar if args.Zip { mime = codersdk.ContentTypeZip @@ -59,6 +86,7 @@ func DynamicParameterTemplate(t *testing.T, client *codersdk.Client, org uuid.UU if args.Version != nil { args.Version(request) } + request.UserVariableValues = userVars }) AwaitTemplateVersionJobCompleted(t, client, version.ID) diff --git a/coderd/dynamicparameters/render.go b/coderd/dynamicparameters/render.go index 8a5a80cd25d22..7f0a98f18ce55 100644 --- a/coderd/dynamicparameters/render.go +++ b/coderd/dynamicparameters/render.go @@ -9,6 +9,7 @@ import ( "time" "github.com/google/uuid" + "github.com/zclconf/go-cty/cty" "golang.org/x/xerrors" "github.com/coder/coder/v2/apiversion" @@ -41,9 +42,10 @@ type loader struct { templateVersionID uuid.UUID // cache of objects - templateVersion *database.TemplateVersion - job *database.ProvisionerJob - terraformValues *database.TemplateVersionTerraformValue + templateVersion *database.TemplateVersion + job *database.ProvisionerJob + terraformValues *database.TemplateVersionTerraformValue + templateVariableValues *[]database.TemplateVersionVariable } // Prepare is the entrypoint for this package. It loads the necessary objects & @@ -61,6 +63,12 @@ func Prepare(ctx context.Context, db database.Store, cache files.FileAcquirer, v return l.Renderer(ctx, db, cache) } +func WithTemplateVariableValues(vals []database.TemplateVersionVariable) func(r *loader) { + return func(r *loader) { + r.templateVariableValues = &vals + } +} + func WithTemplateVersion(tv database.TemplateVersion) func(r *loader) { return func(r *loader) { if tv.ID == r.templateVersionID { @@ -127,6 +135,14 @@ func (r *loader) loadData(ctx context.Context, db database.Store) error { r.terraformValues = &values } + if r.templateVariableValues == nil { + vals, err := db.GetTemplateVersionVariables(ctx, r.templateVersion.ID) + if err != nil && !xerrors.Is(err, sql.ErrNoRows) { + return xerrors.Errorf("template version variables: %w", err) + } + r.templateVariableValues = &vals + } + return nil } @@ -160,13 +176,17 @@ func (r *loader) dynamicRenderer(ctx context.Context, db database.Store, cache * } }() + tfVarValues, err := VariableValues(*r.templateVariableValues) + if err != nil { + return nil, xerrors.Errorf("parse variable values: %w", err) + } + // If they can read the template version, then they can read the file for // parameter loading purposes. //nolint:gocritic fileCtx := dbauthz.AsFileReader(ctx) var templateFS fs.FS - var err error templateFS, err = cache.Acquire(fileCtx, db, r.job.FileID) if err != nil { @@ -189,6 +209,7 @@ func (r *loader) dynamicRenderer(ctx context.Context, db database.Store, cache * db: db, ownerErrors: make(map[uuid.UUID]error), close: cache.Close, + tfvarValues: tfVarValues, }, nil } @@ -199,6 +220,7 @@ type dynamicRenderer struct { ownerErrors map[uuid.UUID]error currentOwner *previewtypes.WorkspaceOwner + tfvarValues map[string]cty.Value once sync.Once close func() @@ -229,6 +251,7 @@ func (r *dynamicRenderer) Render(ctx context.Context, ownerID uuid.UUID, values PlanJSON: r.data.terraformValues.CachedPlan, ParameterValues: values, Owner: *r.currentOwner, + TFVars: r.tfvarValues, // Do not emit parser logs to coderd output logs. // TODO: Returning this logs in the output would benefit the caller. // Unsure how large the logs can be, so for now we just discard them. diff --git a/coderd/dynamicparameters/variablevalues.go b/coderd/dynamicparameters/variablevalues.go new file mode 100644 index 0000000000000..574039119c786 --- /dev/null +++ b/coderd/dynamicparameters/variablevalues.go @@ -0,0 +1,65 @@ +package dynamicparameters + +import ( + "strconv" + + "github.com/zclconf/go-cty/cty" + "github.com/zclconf/go-cty/cty/json" + "golang.org/x/xerrors" + + "github.com/coder/coder/v2/coderd/database" +) + +// VariableValues is a helper function that converts a slice of TemplateVersionVariable +// into a map of cty.Value for use in coder/preview. +func VariableValues(vals []database.TemplateVersionVariable) (map[string]cty.Value, error) { + ctyVals := make(map[string]cty.Value, len(vals)) + for _, v := range vals { + value := v.Value + if value == "" && v.DefaultValue != "" { + value = v.DefaultValue + } + + if value == "" { + // Empty strings are unsupported I guess? + continue // omit non-set vals + } + + var err error + switch v.Type { + // Defaulting the empty type to "string" + // TODO: This does not match the terraform behavior, however it is too late + // at this point in the code to determine this, as the database type stores all values + // as strings. The code needs to be fixed in the `Parse` step of the provisioner. + // That step should determine the type of the variable correctly and store it in the database. + case "string", "": + ctyVals[v.Name] = cty.StringVal(value) + case "number": + ctyVals[v.Name], err = cty.ParseNumberVal(value) + if err != nil { + return nil, xerrors.Errorf("parse variable %q: %w", v.Name, err) + } + case "bool": + parsed, err := strconv.ParseBool(value) + if err != nil { + return nil, xerrors.Errorf("parse variable %q: %w", v.Name, err) + } + ctyVals[v.Name] = cty.BoolVal(parsed) + default: + // If it is a complex type, let the cty json code give it a try. + // TODO: Ideally we parse `list` & `map` and build the type ourselves. + ty, err := json.ImpliedType([]byte(value)) + if err != nil { + return nil, xerrors.Errorf("implied type for variable %q: %w", v.Name, err) + } + + jv, err := json.Unmarshal([]byte(value), ty) + if err != nil { + return nil, xerrors.Errorf("unmarshal variable %q: %w", v.Name, err) + } + ctyVals[v.Name] = jv + } + } + + return ctyVals, nil +} diff --git a/coderd/parameters_test.go b/coderd/parameters_test.go index 855d95eb1de59..c00d6f9224bfb 100644 --- a/coderd/parameters_test.go +++ b/coderd/parameters_test.go @@ -343,6 +343,36 @@ func TestDynamicParametersWithTerraformValues(t *testing.T) { require.Len(t, preview.Diagnostics, 1) require.Equal(t, preview.Diagnostics[0].Extra.Code, "owner_not_found") }) + + t.Run("TemplateVariables", func(t *testing.T) { + t.Parallel() + + dynamicParametersTerraformSource, err := os.ReadFile("testdata/parameters/variables/main.tf") + require.NoError(t, err) + + setup := setupDynamicParamsTest(t, setupDynamicParamsTestParams{ + provisionerDaemonVersion: provProto.CurrentVersion.String(), + mainTF: dynamicParametersTerraformSource, + variables: []codersdk.TemplateVersionVariable{ + {Name: "one", Value: "austin", DefaultValue: "alice", Type: "string"}, + }, + plan: nil, + static: nil, + }) + + ctx := testutil.Context(t, testutil.WaitShort) + stream := setup.stream + previews := stream.Chan() + + // Should see the output of the module represented + preview := testutil.RequireReceive(ctx, t, previews) + require.Equal(t, -1, preview.ID) + require.Empty(t, preview.Diagnostics) + + require.Len(t, preview.Parameters, 1) + coderdtest.AssertParameter(t, "variable_values", preview.Parameters). + Exists().Value("austin") + }) } type setupDynamicParamsTestParams struct { @@ -355,6 +385,7 @@ type setupDynamicParamsTestParams struct { static []*proto.RichParameter expectWebsocketError bool + variables []codersdk.TemplateVersionVariable } type dynamicParamsTest struct { @@ -380,6 +411,7 @@ func setupDynamicParamsTest(t *testing.T, args setupDynamicParamsTestParams) dyn Plan: args.plan, ModulesArchive: args.modulesArchive, StaticParams: args.static, + Variables: args.variables, }) ctx := testutil.Context(t, testutil.WaitShort) diff --git a/coderd/templateversions.go b/coderd/templateversions.go index fa5a7ed1fe757..72b18a2c47e92 100644 --- a/coderd/templateversions.go +++ b/coderd/templateversions.go @@ -18,6 +18,7 @@ import ( "github.com/google/uuid" "github.com/moby/moby/pkg/namesgenerator" "github.com/sqlc-dev/pqtype" + "github.com/zclconf/go-cty/cty" "golang.org/x/xerrors" "cdr.dev/slog" @@ -1585,7 +1586,7 @@ func (api *API) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *ht var parsedTags map[string]string var ok bool if dynamicTemplate { - parsedTags, ok = api.dynamicTemplateVersionTags(ctx, rw, organization.ID, apiKey.UserID, file) + parsedTags, ok = api.dynamicTemplateVersionTags(ctx, rw, organization.ID, apiKey.UserID, file, req.UserVariableValues) if !ok { return } @@ -1762,7 +1763,7 @@ func (api *API) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *ht warnings)) } -func (api *API) dynamicTemplateVersionTags(ctx context.Context, rw http.ResponseWriter, orgID uuid.UUID, owner uuid.UUID, file database.File) (map[string]string, bool) { +func (api *API) dynamicTemplateVersionTags(ctx context.Context, rw http.ResponseWriter, orgID uuid.UUID, owner uuid.UUID, file database.File, templateVariables []codersdk.VariableValue) (map[string]string, bool) { ownerData, err := dynamicparameters.WorkspaceOwner(ctx, api.Database, orgID, owner) if err != nil { if httpapi.Is404Error(err) { @@ -1800,11 +1801,19 @@ func (api *API) dynamicTemplateVersionTags(ctx context.Context, rw http.Response return nil, false } + // Pass in any manually specified template variables as TFVars. + // TODO: Does this break if the type is not a string? + tfVarValues := make(map[string]cty.Value) + for _, variable := range templateVariables { + tfVarValues[variable.Name] = cty.StringVal(variable.Value) + } + output, diags := preview.Preview(ctx, preview.Input{ PlanJSON: nil, // Template versions are before `terraform plan` ParameterValues: nil, // No user-specified parameters Owner: *ownerData, Logger: stdslog.New(stdslog.DiscardHandler), + TFVars: tfVarValues, }, files) tagErr := dynamicparameters.CheckTags(output, diags) if tagErr != nil { diff --git a/coderd/testdata/parameters/variables/main.tf b/coderd/testdata/parameters/variables/main.tf new file mode 100644 index 0000000000000..684ee4505abe3 --- /dev/null +++ b/coderd/testdata/parameters/variables/main.tf @@ -0,0 +1,30 @@ +// Base case for workspace tags + parameters. +terraform { + required_providers { + coder = { + source = "coder/coder" + } + docker = { + source = "kreuzwerker/docker" + version = "3.0.2" + } + } +} + +variable "one" { + default = "alice" + type = string +} + + +data "coder_parameter" "variable_values" { + name = "variable_values" + description = "Just to show the variable values" + type = "string" + default = var.one + + option { + name = "one" + value = var.one + } +} diff --git a/coderd/wsbuilder/wsbuilder.go b/coderd/wsbuilder/wsbuilder.go index 90ea02e966a09..d608682c58eee 100644 --- a/coderd/wsbuilder/wsbuilder.go +++ b/coderd/wsbuilder/wsbuilder.go @@ -633,10 +633,16 @@ func (b *Builder) getDynamicParameterRenderer() (dynamicparameters.Renderer, err return nil, xerrors.Errorf("get template version terraform values: %w", err) } + variableValues, err := b.getTemplateVersionVariables() + if err != nil { + return nil, xerrors.Errorf("get template version variables: %w", err) + } + renderer, err := dynamicparameters.Prepare(b.ctx, b.store, b.fileCache, tv.ID, dynamicparameters.WithTemplateVersion(*tv), dynamicparameters.WithProvisionerJob(*job), dynamicparameters.WithTerraformValues(*tfVals), + dynamicparameters.WithTemplateVariableValues(variableValues), ) if err != nil { return nil, xerrors.Errorf("get template version renderer: %w", err) diff --git a/enterprise/coderd/workspaces_test.go b/enterprise/coderd/workspaces_test.go index 1030536f2111d..d622748899aa0 100644 --- a/enterprise/coderd/workspaces_test.go +++ b/enterprise/coderd/workspaces_test.go @@ -2627,6 +2627,21 @@ func TestWorkspaceTemplateParamsChange(t *testing.T) { require.Equal(t, codersdk.WorkspaceStatusDeleted, build.Status) } +type testWorkspaceTagsTerraformCase struct { + name string + // tags to apply to the external provisioner + provisionerTags map[string]string + // tags to apply to the create template version request + createTemplateVersionRequestTags map[string]string + // the coder_workspace_tags bit of main.tf. + // you can add more stuff here if you need + tfWorkspaceTags string + templateImportUserVariableValues []codersdk.VariableValue + // if we need to set parameters on workspace build + workspaceBuildParameters []codersdk.WorkspaceBuildParameter + skipCreateWorkspace bool +} + // TestWorkspaceTagsTerraform tests that a workspace can be created with tags. // This is an end-to-end-style test, meaning that we actually run the // real Terraform provisioner and validate that the workspace is created @@ -2636,7 +2651,7 @@ func TestWorkspaceTemplateParamsChange(t *testing.T) { // config file so that we only reference those // nolint:paralleltest // t.Setenv func TestWorkspaceTagsTerraform(t *testing.T) { - mainTfTemplate := ` + coderProviderTemplate := ` terraform { required_providers { coder = { @@ -2644,33 +2659,11 @@ func TestWorkspaceTagsTerraform(t *testing.T) { } } } - provider "coder" {} - data "coder_workspace" "me" {} - data "coder_workspace_owner" "me" {} - data "coder_parameter" "unrelated" { - name = "unrelated" - type = "list(string)" - default = jsonencode(["a", "b"]) - } - %s ` - tfCliConfigPath := downloadProviders(t, fmt.Sprintf(mainTfTemplate, "")) + tfCliConfigPath := downloadProviders(t, coderProviderTemplate) t.Setenv("TF_CLI_CONFIG_FILE", tfCliConfigPath) - for _, tc := range []struct { - name string - // tags to apply to the external provisioner - provisionerTags map[string]string - // tags to apply to the create template version request - createTemplateVersionRequestTags map[string]string - // the coder_workspace_tags bit of main.tf. - // you can add more stuff here if you need - tfWorkspaceTags string - templateImportUserVariableValues []codersdk.VariableValue - // if we need to set parameters on workspace build - workspaceBuildParameters []codersdk.WorkspaceBuildParameter - skipCreateWorkspace bool - }{ + for _, tc := range []testWorkspaceTagsTerraformCase{ { name: "no tags", tfWorkspaceTags: ``, @@ -2803,56 +2796,114 @@ func TestWorkspaceTagsTerraform(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - client, owner := coderdenttest.New(t, &coderdenttest.Options{ - Options: &coderdtest.Options{ - // We intentionally do not run a built-in provisioner daemon here. - IncludeProvisionerDaemon: false, - }, - LicenseOptions: &coderdenttest.LicenseOptions{ - Features: license.Features{ - codersdk.FeatureExternalProvisionerDaemons: 1, - }, - }, + t.Run("dynamic", func(t *testing.T) { + workspaceTagsTerraform(t, tc, true) }) - templateAdmin, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleTemplateAdmin()) - member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) - - _ = coderdenttest.NewExternalProvisionerDaemonTerraform(t, client, owner.OrganizationID, tc.provisionerTags) - - // This can take a while, so set a relatively long timeout. - ctx := testutil.Context(t, 2*testutil.WaitSuperLong) - - // Creating a template as a template admin must succeed - templateFiles := map[string]string{"main.tf": fmt.Sprintf(mainTfTemplate, tc.tfWorkspaceTags)} - tarBytes := testutil.CreateTar(t, templateFiles) - fi, err := templateAdmin.Upload(ctx, "application/x-tar", bytes.NewReader(tarBytes)) - require.NoError(t, err, "failed to upload file") - tv, err := templateAdmin.CreateTemplateVersion(ctx, owner.OrganizationID, codersdk.CreateTemplateVersionRequest{ - Name: testutil.GetRandomName(t), - FileID: fi.ID, - StorageMethod: codersdk.ProvisionerStorageMethodFile, - Provisioner: codersdk.ProvisionerTypeTerraform, - ProvisionerTags: tc.createTemplateVersionRequestTags, - UserVariableValues: tc.templateImportUserVariableValues, + + // classic uses tfparse for tags. This sub test can be + // removed when tf parse is removed. + t.Run("classic", func(t *testing.T) { + workspaceTagsTerraform(t, tc, false) }) - require.NoError(t, err, "failed to create template version") - coderdtest.AwaitTemplateVersionJobCompleted(t, templateAdmin, tv.ID) - tpl := coderdtest.CreateTemplate(t, templateAdmin, owner.OrganizationID, tv.ID) - - if !tc.skipCreateWorkspace { - // Creating a workspace as a non-privileged user must succeed - ws, err := member.CreateUserWorkspace(ctx, memberUser.Username, codersdk.CreateWorkspaceRequest{ - TemplateID: tpl.ID, - Name: coderdtest.RandomUsername(t), - RichParameterValues: tc.workspaceBuildParameters, - }) - require.NoError(t, err, "failed to create workspace") - coderdtest.AwaitWorkspaceBuildJobCompleted(t, member, ws.LatestBuild.ID) - } }) } } +func workspaceTagsTerraform(t *testing.T, tc testWorkspaceTagsTerraformCase, dynamic bool) { + mainTfTemplate := ` + terraform { + required_providers { + coder = { + source = "coder/coder" + } + } + } + + provider "coder" {} + data "coder_workspace" "me" {} + data "coder_workspace_owner" "me" {} + data "coder_parameter" "unrelated" { + name = "unrelated" + type = "list(string)" + default = jsonencode(["a", "b"]) + } + %s + ` + + client, owner := coderdenttest.New(t, &coderdenttest.Options{ + Options: &coderdtest.Options{ + // We intentionally do not run a built-in provisioner daemon here. + IncludeProvisionerDaemon: false, + }, + LicenseOptions: &coderdenttest.LicenseOptions{ + Features: license.Features{ + codersdk.FeatureExternalProvisionerDaemons: 1, + }, + }, + }) + templateAdmin, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleTemplateAdmin()) + member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) + + // This can take a while, so set a relatively long timeout. + ctx := testutil.Context(t, 2*testutil.WaitSuperLong) + + emptyTar := testutil.CreateTar(t, map[string]string{"main.tf": ""}) + emptyFi, err := templateAdmin.Upload(ctx, "application/x-tar", bytes.NewReader(emptyTar)) + require.NoError(t, err) + + // This template version does not need to succeed in being created. + // It will be in pending forever. We just need it to create a template. + emptyTv, err := templateAdmin.CreateTemplateVersion(ctx, owner.OrganizationID, codersdk.CreateTemplateVersionRequest{ + Name: testutil.GetRandomName(t), + FileID: emptyFi.ID, + StorageMethod: codersdk.ProvisionerStorageMethodFile, + Provisioner: codersdk.ProvisionerTypeTerraform, + }) + require.NoError(t, err) + + tpl := coderdtest.CreateTemplate(t, templateAdmin, owner.OrganizationID, emptyTv.ID, func(request *codersdk.CreateTemplateRequest) { + request.UseClassicParameterFlow = ptr.Ref(!dynamic) + }) + + // The provisioner for the next template version + _ = coderdenttest.NewExternalProvisionerDaemonTerraform(t, client, owner.OrganizationID, tc.provisionerTags) + + // Creating a template as a template admin must succeed + templateFiles := map[string]string{"main.tf": fmt.Sprintf(mainTfTemplate, tc.tfWorkspaceTags)} + tarBytes := testutil.CreateTar(t, templateFiles) + fi, err := templateAdmin.Upload(ctx, "application/x-tar", bytes.NewReader(tarBytes)) + require.NoError(t, err, "failed to upload file") + tv, err := templateAdmin.CreateTemplateVersion(ctx, owner.OrganizationID, codersdk.CreateTemplateVersionRequest{ + Name: testutil.GetRandomName(t), + FileID: fi.ID, + StorageMethod: codersdk.ProvisionerStorageMethodFile, + Provisioner: codersdk.ProvisionerTypeTerraform, + ProvisionerTags: tc.createTemplateVersionRequestTags, + UserVariableValues: tc.templateImportUserVariableValues, + TemplateID: tpl.ID, + }) + require.NoError(t, err, "failed to create template version") + coderdtest.AwaitTemplateVersionJobCompleted(t, templateAdmin, tv.ID) + + err = templateAdmin.UpdateActiveTemplateVersion(ctx, tpl.ID, codersdk.UpdateActiveTemplateVersion{ + ID: tv.ID, + }) + require.NoError(t, err, "set to active template version") + + if !tc.skipCreateWorkspace { + // Creating a workspace as a non-privileged user must succeed + ws, err := member.CreateUserWorkspace(ctx, memberUser.Username, codersdk.CreateWorkspaceRequest{ + TemplateID: tpl.ID, + Name: coderdtest.RandomUsername(t), + RichParameterValues: tc.workspaceBuildParameters, + }) + require.NoError(t, err, "failed to create workspace") + tagJSON, _ := json.Marshal(ws.LatestBuild.Job.Tags) + t.Logf("Created workspace build [%s] with tags: %s", ws.LatestBuild.Job.Type, tagJSON) + coderdtest.AwaitWorkspaceBuildJobCompleted(t, member, ws.LatestBuild.ID) + } +} + // downloadProviders is a test helper that creates a temporary file and writes a // terraform CLI config file with a provider_installation stanza for coder/coder // using dev_overrides. It also fetches the latest provider release from GitHub @@ -3124,7 +3175,7 @@ func TestWorkspaceLock(t *testing.T) { require.NotNil(t, workspace.DeletingAt) require.NotNil(t, workspace.DormantAt) require.Equal(t, workspace.DormantAt.Add(dormantTTL), *workspace.DeletingAt) - require.WithinRange(t, *workspace.DormantAt, time.Now().Add(-time.Second*10), time.Now()) + require.WithinRange(t, *workspace.DormantAt, time.Now().Add(-time.Second), time.Now()) // Locking a workspace shouldn't update the last_used_at. require.Equal(t, lastUsedAt, workspace.LastUsedAt) diff --git a/go.mod b/go.mod index fa91932ceaecf..f2b12cbd6387c 100644 --- a/go.mod +++ b/go.mod @@ -483,7 +483,7 @@ require ( require ( github.com/coder/agentapi-sdk-go v0.0.0-20250505131810-560d1d88d225 github.com/coder/aisdk-go v0.0.9 - github.com/coder/preview v1.0.3-0.20250701142654-c3d6e86b9393 + github.com/coder/preview v1.0.3-0.20250714153828-a737d4750448 github.com/fsnotify/fsnotify v1.9.0 github.com/mark3labs/mcp-go v0.33.0 ) diff --git a/go.sum b/go.sum index e46a4eb61a477..1d6ae833a5dbe 100644 --- a/go.sum +++ b/go.sum @@ -916,8 +916,8 @@ github.com/coder/pq v1.10.5-0.20250630052411-a259f96b6102 h1:ahTJlTRmTogsubgRVGO github.com/coder/pq v1.10.5-0.20250630052411-a259f96b6102/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0 h1:3A0ES21Ke+FxEM8CXx9n47SZOKOpgSE1bbJzlE4qPVs= github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0/go.mod h1:5UuS2Ts+nTToAMeOjNlnHFkPahrtDkmpydBen/3wgZc= -github.com/coder/preview v1.0.3-0.20250701142654-c3d6e86b9393 h1:l+m2liikn8JoEv6C22QIV4qseolUfvNsyUNA6JJsD6Y= -github.com/coder/preview v1.0.3-0.20250701142654-c3d6e86b9393/go.mod h1:efDWGlO/PZPrvdt5QiDhMtTUTkPxejXo9c0wmYYLLjM= +github.com/coder/preview v1.0.3-0.20250714153828-a737d4750448 h1:S86sFp4Dr4dUn++fXOMOTu6ClnEZ/NrGCYv7bxZjYYc= +github.com/coder/preview v1.0.3-0.20250714153828-a737d4750448/go.mod h1:hQtBEqOFMJ3SHl9Q9pVvDA9CpeCEXBwbONNK29+3MLk= github.com/coder/quartz v0.2.1 h1:QgQ2Vc1+mvzewg2uD/nj8MJ9p9gE+QhGJm+Z+NGnrSE= github.com/coder/quartz v0.2.1/go.mod h1:vsiCc+AHViMKH2CQpGIpFgdHIEQsxwm8yCscqKmzbRA= github.com/coder/retry v1.5.1 h1:iWu8YnD8YqHs3XwqrqsjoBTAVqT9ml6z9ViJ2wlMiqc= diff --git a/provisioner/terraform/parse.go b/provisioner/terraform/parse.go index 7aa78e401c503..d5b59df327f65 100644 --- a/provisioner/terraform/parse.go +++ b/provisioner/terraform/parse.go @@ -15,6 +15,10 @@ import ( ) // Parse extracts Terraform variables from source-code. +// TODO: This Parse is incomplete. It uses tfparse instead of terraform. +// The inputs are incomplete, as values such as the user context, parameters, +// etc are all important to the parsing process. This should be replaced with +// preview and have all inputs. func (s *server) Parse(sess *provisionersdk.Session, _ *proto.ParseRequest, _ <-chan struct{}) *proto.ParseComplete { ctx := sess.Context() _, span := s.startTrace(ctx, tracing.FuncName()) 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