From 47802e4f236c420e32c4ae49df36bac5391279f6 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 27 Jun 2025 12:27:20 -0500 Subject: [PATCH 01/15] fix: `tags` argument in workspace tags block is optional (#157) It was marked as required, which is incorrect. The provider has it as optional. --- extract/parameter.go | 6 +++--- workspacetags.go | 11 +---------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/extract/parameter.go b/extract/parameter.go index 3b5f1d0..0d45a8b 100644 --- a/extract/parameter.go +++ b/extract/parameter.go @@ -252,7 +252,7 @@ func optionalStringEnum[T ~string](block *terraform.Block, key string, def T, va tyAttr := block.GetAttribute(key) return "", &hcl.Diagnostic{ Severity: hcl.DiagError, - Summary: fmt.Sprintf("Invalid %q attribute", key), + Summary: fmt.Sprintf("Invalid %q attribute for block %s", key, block.Label()), Detail: err.Error(), Subject: &(tyAttr.HCLAttribute().Range), //Context: &(block.HCLBlock().DefRange), @@ -275,7 +275,7 @@ func requiredString(block *terraform.Block, key string) (string, *hcl.Diagnostic diag := &hcl.Diagnostic{ Severity: hcl.DiagError, - Summary: fmt.Sprintf("Invalid %q attribute", key), + Summary: fmt.Sprintf("Invalid %q attribute for block %s", key, block.Label()), Detail: fmt.Sprintf("Expected a string, got %q", typeName), Subject: &(tyAttr.HCLAttribute().Range), //Context: &(block.HCLBlock().DefRange), @@ -393,7 +393,7 @@ func required(block *terraform.Block, keys ...string) hcl.Diagnostics { r := block.HCLBlock().Body.MissingItemRange() diags = diags.Append(&hcl.Diagnostic{ Severity: hcl.DiagError, - Summary: fmt.Sprintf("Missing required attribute %q", key), + Summary: fmt.Sprintf("Missing required attribute %q for block %q", key, block.Label()), Detail: fmt.Sprintf("The %s attribute is required", key), Subject: &r, Extra: nil, diff --git a/workspacetags.go b/workspacetags.go index d3f6c76..f0134ee 100644 --- a/workspacetags.go +++ b/workspacetags.go @@ -17,18 +17,9 @@ func workspaceTags(modules terraform.Modules, files map[string]*hcl.File) (types for _, mod := range modules { blocks := mod.GetDatasByType("coder_workspace_tags") for _, block := range blocks { - evCtx := block.Context().Inner() - tagsAttr := block.GetAttribute("tags") if tagsAttr.IsNil() { - r := block.HCLBlock().Body.MissingItemRange() - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Missing required argument", - Detail: `"tags" attribute is required by coder_workspace_tags blocks`, - Subject: &r, - EvalContext: evCtx, - }) + // Nil tags block is valid, just skip it. continue } From ae79d6dbe98a04b86b0ee3506dded3fb512a7e5f Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 27 Jun 2025 12:37:49 -0500 Subject: [PATCH 02/15] feat: prevent path expansion using host context (#158) Any references to `~` should return an error --- init.go | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 init.go diff --git a/init.go b/init.go new file mode 100644 index 0000000..57a308f --- /dev/null +++ b/init.go @@ -0,0 +1,40 @@ +package preview + +import ( + "github.com/aquasecurity/trivy/pkg/iac/scanners/terraform/parser/funcs" + "github.com/zclconf/go-cty/cty" + "github.com/zclconf/go-cty/cty/function" + "golang.org/x/xerrors" +) + +// init intends to override some of the default functions afforded by terraform. +// Specifically, any functions that require the context of the host. +// +// This is really unfortunate, but all the functions are globals, and this +// is the only way to override them. +func init() { + // PathExpandFunc looks for references to a home directory on the host. The + // preview rendering should not have access to the host's home directory path, + // and will return an error if it is used. + funcs.PathExpandFunc = function.New(&function.Spec{ + Params: []function.Parameter{ + { + Name: "path", + Type: cty.String, + }, + }, + Type: function.StaticReturnType(cty.String), + Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { + path := args[0].AsString() + if len(path) == 0 { + return cty.StringVal(path), nil + } + + if path[0] != '~' { + return cty.StringVal(path), nil + } + + return cty.NilVal, xerrors.Errorf("not allowed to expand paths starting with '~' in this context") + }, + }) +} From 80d1ef4ee64a526dcc1db8b3549b23602ce47d58 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Mon, 30 Jun 2025 11:37:18 -0500 Subject: [PATCH 03/15] chore: comment original source for the code change on path expansion (#161) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: ケイラ --- init.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/init.go b/init.go index 57a308f..86eaaad 100644 --- a/init.go +++ b/init.go @@ -25,6 +25,8 @@ func init() { }, Type: function.StaticReturnType(cty.String), Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { + // This code is taken directly from https://github.com/mitchellh/go-homedir/blob/af06845cf3004701891bf4fdb884bfe4920b3727/homedir.go#L58 + // The only change is that instead of expanding the path, we return an error path := args[0].AsString() if len(path) == 0 { return cty.StringVal(path), nil From 25471dda879f79f677f7f697fa1694cd1f3b2bbe Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Tue, 1 Jul 2025 08:35:24 -0500 Subject: [PATCH 04/15] feat: allow bool + number tag values (#160) Tag values accept bool & number in coder/coder. Maps, lists, and objects are rejected as invalid tags. `null` values are omitted from the tags, matching terraform apply/plan --- preview_test.go | 27 ++++++++++- testdata/sometags/main.tf | 29 ++++++++++++ testdata/sometags/skipe2e | 1 + testdata/static/main.tf | 1 + workspacetags.go | 97 ++++++++++----------------------------- 5 files changed, 81 insertions(+), 74 deletions(-) create mode 100644 testdata/sometags/main.tf create mode 100644 testdata/sometags/skipe2e diff --git a/preview_test.go b/preview_test.go index b0ea9b3..59a8761 100644 --- a/preview_test.go +++ b/preview_test.go @@ -49,13 +49,25 @@ func Test_Extract(t *testing.T) { dir: "badparam", failPreview: true, }, + { + name: "sometags", + dir: "sometags", + expTags: map[string]string{ + "string": "foo", + "number": "42", + "bool": "true", + // null tags are omitted + }, + unknownTags: []string{ + "complex", "map", "list", + }, + }, { name: "simple static values", dir: "static", expTags: map[string]string{ "zone": "developers", }, - unknownTags: []string{}, params: map[string]assertParam{ "region": ap().value("us"). def("us"). @@ -510,7 +522,18 @@ func Test_Extract(t *testing.T) { // Assert tags validTags := output.WorkspaceTags.Tags() - assert.Equal(t, tc.expTags, validTags) + for k, expected := range tc.expTags { + tag, ok := validTags[k] + if !ok { + t.Errorf("expected tag %q to be present in output, but it was not", k) + continue + } + if tag != expected { + assert.JSONEqf(t, expected, tag, "tag %q does not match expected, nor is it a json equivalent", k) + } + } + assert.Equal(t, len(tc.expTags), len(output.WorkspaceTags.Tags()), "unexpected number of tags in output") + assert.ElementsMatch(t, tc.unknownTags, output.WorkspaceTags.UnusableTags().SafeNames()) // Assert params diff --git a/testdata/sometags/main.tf b/testdata/sometags/main.tf new file mode 100644 index 0000000..3bbdb93 --- /dev/null +++ b/testdata/sometags/main.tf @@ -0,0 +1,29 @@ +terraform { + required_providers { + coder = { + source = "coder/coder" + version = "2.4.0-pre0" + } + } +} + +data "coder_workspace_tags" "custom_workspace_tags" { + tags = { + "string" = "foo" + "number" = 42 + "bool" = true + "list" = ["a", "b", "c"] + "map" = { + "key1" = "value1" + "key2" = "value2" + } + "complex" = { + "nested_list" = [1, 2, 3] + "nested" = { + "key" = "value" + } + } + "null" = null + } +} + diff --git a/testdata/sometags/skipe2e b/testdata/sometags/skipe2e new file mode 100644 index 0000000..8bcda2e --- /dev/null +++ b/testdata/sometags/skipe2e @@ -0,0 +1 @@ +Complex types are not supported by coder provider \ No newline at end of file diff --git a/testdata/static/main.tf b/testdata/static/main.tf index 8e67ac5..0260e72 100644 --- a/testdata/static/main.tf +++ b/testdata/static/main.tf @@ -15,6 +15,7 @@ terraform { data "coder_workspace_tags" "custom_workspace_tags" { tags = { "zone" = "developers" + "null" = null } } diff --git a/workspacetags.go b/workspacetags.go index f0134ee..4c4b0a7 100644 --- a/workspacetags.go +++ b/workspacetags.go @@ -38,23 +38,14 @@ func workspaceTags(modules terraform.Modules, files map[string]*hcl.File) (types continue } - // tagsObj, ok := tagsAttr.HCLAttribute().Expr.(*hclsyntax.ObjectConsExpr) - // if !ok { - // diags = diags.Append(&hcl.Diagnostic{ - // Severity: hcl.DiagError, - // Summary: "Incorrect type for \"tags\" attribute", - // // TODO: better error message for types - // Detail: fmt.Sprintf(`"tags" attribute must be an 'ObjectConsExpr', but got %T`, tagsAttr.HCLAttribute().Expr), - // Subject: &tagsAttr.HCLAttribute().NameRange, - // Context: &tagsAttr.HCLAttribute().Range, - // Expression: tagsAttr.HCLAttribute().Expr, - // EvalContext: block.Context().Inner(), - // }) - // continue - //} - var tags []types.Tag tagsValue.ForEachElement(func(key cty.Value, val cty.Value) (stop bool) { + if val.IsNull() { + // null tags with null values are omitted + // This matches the behavior of `terraform apply`` + return false + } + r := tagsAttr.HCLAttribute().Expr.Range() tag, tagDiag := newTag(&r, files, key, val) if tagDiag != nil { @@ -66,15 +57,7 @@ func workspaceTags(modules terraform.Modules, files map[string]*hcl.File) (types return false }) - // for _, item := range tagsObj.Items { - // tag, tagDiag := newTag(tagsObj, files, item, evCtx) - // if tagDiag != nil { - // diags = diags.Append(tagDiag) - // continue - // } - // - // tags = append(tags, tag) - //} + tagBlocks = append(tagBlocks, types.TagBlock{ Tags: tags, Block: block, @@ -87,71 +70,41 @@ func workspaceTags(modules terraform.Modules, files map[string]*hcl.File) (types // newTag creates a workspace tag from its hcl expression. func newTag(srcRange *hcl.Range, _ map[string]*hcl.File, key, val cty.Value) (types.Tag, *hcl.Diagnostic) { - // key, kdiags := expr.KeyExpr.Value(evCtx) - // val, vdiags := expr.ValueExpr.Value(evCtx) - - // TODO: ??? - - // if kdiags.HasErrors() { - // key = cty.UnknownVal(cty.String) - //} - // if vdiags.HasErrors() { - // val = cty.UnknownVal(cty.String) - //} - if key.IsKnown() && key.Type() != cty.String { return types.Tag{}, &hcl.Diagnostic{ Severity: hcl.DiagError, Summary: "Invalid key type for tags", Detail: fmt.Sprintf("Key must be a string, but got %s", key.Type().FriendlyName()), - //Subject: &r, - Context: srcRange, - //Expression: expr.KeyExpr, - //EvalContext: evCtx, - } - } - - if val.IsKnown() && val.Type() != cty.String { - fr := "" - if !val.Type().Equals(cty.NilType) { - fr = val.Type().FriendlyName() - } - // r := expr.ValueExpr.Range() - return types.Tag{}, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Invalid value type for tag", - Detail: fmt.Sprintf("Value must be a string, but got %s", fr), - //Subject: &r, - Context: srcRange, - //Expression: expr.ValueExpr, - //EvalContext: evCtx, + Context: srcRange, } } tag := types.Tag{ Key: types.HCLString{ Value: key, - //ValueDiags: kdiags, - //ValueExpr: expr.KeyExpr, }, Value: types.HCLString{ Value: val, - //ValueDiags: vdiags, - //ValueExpr: expr.ValueExpr, }, } - // ks, err := source(expr.KeyExpr.Range(), files) - // if err == nil { - // src := string(ks) - // tag.Key.Source = &src - //} - // - // vs, err := source(expr.ValueExpr.Range(), files) - // if err == nil { - // src := string(vs) - // tag.Value.Source = &src - //} + switch val.Type() { + case cty.String, cty.Bool, cty.Number: + // These types are supported and can be safely converted to a string. + default: + fr := "" + if !val.Type().Equals(cty.NilType) { + fr = val.Type().FriendlyName() + } + + // Unsupported types will be treated as errors. + tag.Value.ValueDiags = tag.Value.ValueDiags.Append(&hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: fmt.Sprintf("Invalid value type for tag %q", tag.KeyString()), + Detail: fmt.Sprintf("Value must be a string, but got %s.", fr), + Context: srcRange, + }) + } return tag, nil } From c3d6e86b9393abbee8b673b4b5b9db3bcb5e230e Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Tue, 1 Jul 2025 09:26:54 -0500 Subject: [PATCH 05/15] feat: add specific code to module missing warning (#162) --- types/diagnostics.go | 5 +++++ warnings.go | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/types/diagnostics.go b/types/diagnostics.go index 1884726..c13da4d 100644 --- a/types/diagnostics.go +++ b/types/diagnostics.go @@ -10,6 +10,11 @@ const ( // DiagnosticCodeRequired is used when a parameter value is `null`, but // the parameter is required. DiagnosticCodeRequired = "required" + + // DiagnosticModuleNotLoaded is used when a module block is present, but + // the mode failed to load. This can be because `.terraform/modules` is + // not present. + DiagnosticModuleNotLoaded = "module_not_loaded" ) type DiagnosticExtra struct { diff --git a/warnings.go b/warnings.go index 781f49a..12011f5 100644 --- a/warnings.go +++ b/warnings.go @@ -6,6 +6,8 @@ import ( "github.com/aquasecurity/trivy/pkg/iac/terraform" "github.com/hashicorp/hcl/v2" + + "github.com/coder/preview/types" ) func warnings(modules terraform.Modules) hcl.Diagnostics { @@ -53,12 +55,12 @@ func unresolvedModules(modules terraform.Modules) hcl.Diagnostics { label += " " + fmt.Sprintf("%q", l) } - diags = diags.Append(&hcl.Diagnostic{ + diags = diags.Append(types.DiagnosticCode(&hcl.Diagnostic{ Severity: hcl.DiagWarning, Summary: "Module not loaded. Did you run `terraform init`?", Detail: fmt.Sprintf("Module '%s' in file %q cannot be resolved. This module will be ignored.", label, block.HCLBlock().DefRange), Subject: &(block.HCLBlock().DefRange), - }) + }, types.DiagnosticModuleNotLoaded)) } } } From 9e7d207b6893da3d828d63e348caebafb2461245 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 3 Jul 2025 12:04:16 -0500 Subject: [PATCH 06/15] chore: do not call getwd, pass in static (#163) --- preview.go | 1 + 1 file changed, 1 insertion(+) diff --git a/preview.go b/preview.go index 5635bf1..62a94e6 100644 --- a/preview.go +++ b/preview.go @@ -132,6 +132,7 @@ func Preview(ctx context.Context, input Input, dir fs.FS) (output *Output, diagn parser.OptionWithTFVarsPaths(varFiles...), parser.OptionWithEvalHook(planHook), parser.OptionWithEvalHook(ownerHook), + parser.OptionWithWorkingDirectoryPath("/"), parser.OptionWithEvalHook(parameterContextsEvalHook(input)), ) From 9a7fd06dc09d97b892f59d6e279f2560aa6fab87 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Jul 2025 08:32:58 -0600 Subject: [PATCH 07/15] chore(deps): bump github.com/hashicorp/hcl/v2 from 2.23.0 to 2.24.0 (#166) Bumps [github.com/hashicorp/hcl/v2](https://github.com/hashicorp/hcl) from 2.23.0 to 2.24.0.
Release notes

Sourced from github.com/hashicorp/hcl/v2's releases.

v2.24.0

Enhancements

  • Add support for decoding block and attribute source ranges when using gohcl. (#703)
  • hclsyntax: Detect and reject invalid nested splat result. (#724)

Bugs Fixed

  • Correct handling of unknown objects in Index function. (#763)
Changelog

Sourced from github.com/hashicorp/hcl/v2's changelog.

v2.24.0 (July 7, 2025)

Enhancements

  • Add support for decoding block and attribute source ranges when using gohcl. (#703)
  • hclsyntax: Detect and reject invalid nested splat result. (#724)

Bugs Fixed

  • Correct handling of unknown objects in Index function. (#763)
Commits
  • 6b50680 Update CHANGELOG.md (#764)
  • 77ef278 ops: handle unknown objects correctly when looking up by index (#763)
  • dfa124f [Compliance] - PR Template Changes Required (#761)
  • 6b5c4c2 fix errors thrown by errcheck linter (#755)
  • 61bd79d suppress and fix lint errors by unused (#754)
  • 8b8cb9c build(deps): bump golangci/golangci-lint-action
  • aa4e447 build(deps): bump actions/setup-go
  • 7244363 Update go-cty to latest (#749)
  • b4e27ae test_suite: refactor schema validation of diagnostic file range, pos (#750)
  • 314d236 fix staticcheck lint errors
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/hashicorp/hcl/v2&package-manager=go_modules&previous-version=2.23.0&new-version=2.24.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 6db51d7..aae669c 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/hashicorp/go-cty v1.5.0 github.com/hashicorp/go-version v1.7.0 github.com/hashicorp/hc-install v0.9.2 - github.com/hashicorp/hcl/v2 v2.23.0 + github.com/hashicorp/hcl/v2 v2.24.0 github.com/hashicorp/terraform-exec v0.23.0 github.com/hashicorp/terraform-json v0.25.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0 diff --git a/go.sum b/go.sum index b60776c..c0d28a2 100644 --- a/go.sum +++ b/go.sum @@ -963,8 +963,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hc-install v0.9.2 h1:v80EtNX4fCVHqzL9Lg/2xkp62bbvQMnvPQ0G+OmtO24= github.com/hashicorp/hc-install v0.9.2/go.mod h1:XUqBQNnuT4RsxoxiM9ZaUk0NX8hi2h+Lb6/c0OZnC/I= -github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3qos= -github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA= +github.com/hashicorp/hcl/v2 v2.24.0 h1:2QJdZ454DSsYGoaE6QheQZjtKZSUs9Nh2izTWiwQxvE= +github.com/hashicorp/hcl/v2 v2.24.0/go.mod h1:oGoO1FIQYfn/AgyOhlg9qLC6/nOJPX3qGbkZpYAcqfM= github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/terraform-exec v0.23.0 h1:MUiBM1s0CNlRFsCLJuM5wXZrzA3MnPYEsiXmzATMW/I= From ce03bce60d6de5ac9ad6772a9abedd6e1a5fb748 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Mon, 14 Jul 2025 08:34:33 -0600 Subject: [PATCH 08/15] feat: terraform variables added to input (#165) Input can override template vars, implementing the equivalent of '-var' in terraform. --- internal/verify/exec.go | 9 +-- preview.go | 62 +++++++----------- preview_test.go | 32 +++++++++ previewe2e_test.go | 26 ++++++-- testdata/tfvars/.auto.tfvars.json | 1 + testdata/tfvars/main.tf | 61 +++++++++++++++++ testdata/tfvars/values.tfvars | 2 + tfvars/load.go | 105 ++++++++++++++++++++++++++++++ 8 files changed, 249 insertions(+), 49 deletions(-) create mode 100644 testdata/tfvars/.auto.tfvars.json create mode 100644 testdata/tfvars/main.tf create mode 100644 testdata/tfvars/values.tfvars create mode 100644 tfvars/load.go diff --git a/internal/verify/exec.go b/internal/verify/exec.go index 1294025..2c64bfd 100644 --- a/internal/verify/exec.go +++ b/internal/verify/exec.go @@ -56,14 +56,15 @@ func (e WorkingExecutable) Init(ctx context.Context) error { return e.TF.Init(ctx, tfexec.Upgrade(true)) } -func (e WorkingExecutable) Plan(ctx context.Context, outPath string) (bool, error) { - changes, err := e.TF.Plan(ctx, tfexec.Out(outPath)) +func (e WorkingExecutable) Plan(ctx context.Context, outPath string, opts ...tfexec.PlanOption) (bool, error) { + opts = append(opts, tfexec.Out(outPath)) + changes, err := e.TF.Plan(ctx, opts...) return changes, err } -func (e WorkingExecutable) Apply(ctx context.Context) ([]byte, error) { +func (e WorkingExecutable) Apply(ctx context.Context, opts ...tfexec.ApplyOption) ([]byte, error) { var out bytes.Buffer - err := e.TF.ApplyJSON(ctx, &out) + err := e.TF.ApplyJSON(ctx, &out, opts...) return out.Bytes(), err } diff --git a/preview.go b/preview.go index 62a94e6..7cf360d 100644 --- a/preview.go +++ b/preview.go @@ -6,7 +6,6 @@ import ( "fmt" "io/fs" "log/slog" - "path/filepath" "github.com/aquasecurity/trivy/pkg/iac/scanners/terraform/parser" "github.com/hashicorp/hcl/v2" @@ -14,6 +13,7 @@ import ( ctyjson "github.com/zclconf/go-cty/cty/json" "github.com/coder/preview/hclext" + "github.com/coder/preview/tfvars" "github.com/coder/preview/types" ) @@ -26,6 +26,9 @@ type Input struct { ParameterValues map[string]string Owner types.WorkspaceOwner Logger *slog.Logger + // TFVars will override any variables set in '.tfvars' files. + // The value set must be a cty.Value, as the type can be anything. + TFVars map[string]cty.Value } type Output struct { @@ -80,12 +83,7 @@ func Preview(ctx context.Context, input Input, dir fs.FS) (output *Output, diagn } }() - // TODO: Fix logging. There is no way to pass in an instanced logger to - // the parser. - // slog.SetLogLoggerLevel(slog.LevelDebug) - // slog.SetDefault(slog.New(log.NewHandler(os.Stderr, nil))) - - varFiles, err := tfVarFiles("", dir) + varFiles, err := tfvars.TFVarFiles("", dir) if err != nil { return nil, hcl.Diagnostics{ { @@ -96,6 +94,17 @@ func Preview(ctx context.Context, input Input, dir fs.FS) (output *Output, diagn } } + variableValues, err := tfvars.LoadTFVars(dir, varFiles) + if err != nil { + return nil, hcl.Diagnostics{ + { + Severity: hcl.DiagError, + Summary: "Failed to load tfvars from files", + Detail: err.Error(), + }, + } + } + planHook, err := planJSONHook(dir, input) if err != nil { return nil, hcl.Diagnostics{ @@ -123,17 +132,24 @@ func Preview(ctx context.Context, input Input, dir fs.FS) (output *Output, diagn logger = slog.New(slog.DiscardHandler) } + // Override with user-supplied variables + for k, v := range input.TFVars { + variableValues[k] = v + } + // moduleSource is "" for a local module p := parser.New(dir, "", parser.OptionWithLogger(logger), parser.OptionStopOnHCLError(false), parser.OptionWithDownloads(false), parser.OptionWithSkipCachedModules(true), - parser.OptionWithTFVarsPaths(varFiles...), parser.OptionWithEvalHook(planHook), parser.OptionWithEvalHook(ownerHook), parser.OptionWithWorkingDirectoryPath("/"), parser.OptionWithEvalHook(parameterContextsEvalHook(input)), + // 'OptionsWithTfVars' cannot be set with 'OptionWithTFVarsPaths'. So load the + // tfvars from the files ourselves and merge with the user-supplied tf vars. + parser.OptionsWithTfVars(variableValues), ) err = p.ParseFS(ctx, ".") @@ -179,33 +195,3 @@ func (i Input) RichParameterValue(key string) (string, bool) { p, ok := i.ParameterValues[key] return p, ok } - -// tfVarFiles extracts any .tfvars files from the given directory. -// TODO: Test nested directories and how that should behave. -func tfVarFiles(path string, dir fs.FS) ([]string, error) { - dp := "." - entries, err := fs.ReadDir(dir, dp) - if err != nil { - return nil, fmt.Errorf("read dir %q: %w", dp, err) - } - - files := make([]string, 0) - for _, entry := range entries { - if entry.IsDir() { - subD, err := fs.Sub(dir, entry.Name()) - if err != nil { - return nil, fmt.Errorf("sub dir %q: %w", entry.Name(), err) - } - newFiles, err := tfVarFiles(filepath.Join(path, entry.Name()), subD) - if err != nil { - return nil, err - } - files = append(files, newFiles...) - } - - if filepath.Ext(entry.Name()) == ".tfvars" { - files = append(files, filepath.Join(path, entry.Name())) - } - } - return files, nil -} diff --git a/preview_test.go b/preview_test.go index 59a8761..e92d9df 100644 --- a/preview_test.go +++ b/preview_test.go @@ -13,6 +13,7 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/zclconf/go-cty/cty" "github.com/coder/preview" "github.com/coder/preview/types" @@ -471,6 +472,37 @@ func Test_Extract(t *testing.T) { optNames("GoLand 2024.3", "IntelliJ IDEA Ultimate 2024.3", "PyCharm Professional 2024.3"), }, }, + { + name: "tfvars_from_file", + dir: "tfvars", + expTags: map[string]string{}, + input: preview.Input{ + ParameterValues: map[string]string{}, + }, + unknownTags: []string{}, + params: map[string]assertParam{ + "variable_values": ap(). + def("alex").optVals("alex", "bob", "claire", "jason"), + }, + }, + { + name: "tfvars_from_input", + dir: "tfvars", + expTags: map[string]string{}, + input: preview.Input{ + ParameterValues: map[string]string{}, + TFVars: map[string]cty.Value{ + "one": cty.StringVal("andrew"), + "two": cty.StringVal("bill"), + "three": cty.StringVal("carter"), + }, + }, + unknownTags: []string{}, + params: map[string]assertParam{ + "variable_values": ap(). + def("andrew").optVals("andrew", "bill", "carter", "jason"), + }, + }, { name: "unknownoption", dir: "unknownoption", diff --git a/previewe2e_test.go b/previewe2e_test.go index 3a9adb2..bcfeb0b 100644 --- a/previewe2e_test.go +++ b/previewe2e_test.go @@ -10,10 +10,12 @@ import ( "testing" "time" + "github.com/hashicorp/terraform-exec/tfexec" "github.com/stretchr/testify/require" "github.com/coder/preview" "github.com/coder/preview/internal/verify" + "github.com/coder/preview/tfvars" "github.com/coder/preview/types" ) @@ -102,11 +104,11 @@ func Test_VerifyE2E(t *testing.T) { entryWrkPath := t.TempDir() - for _, tfexec := range tfexecs { - tfexec := tfexec + for _, tfexecutable := range tfexecs { + tfexecutable := tfexecutable - t.Run(tfexec.Version, func(t *testing.T) { - wp := filepath.Join(entryWrkPath, tfexec.Version) + t.Run(tfexecutable.Version, func(t *testing.T) { + wp := filepath.Join(entryWrkPath, tfexecutable.Version) err := os.MkdirAll(wp, 0755) require.NoError(t, err, "creating working dir") @@ -118,7 +120,7 @@ func Test_VerifyE2E(t *testing.T) { err = verify.CopyTFFS(wp, subFS) require.NoError(t, err, "copying test data to working dir") - exe, err := tfexec.WorkingDir(wp) + exe, err := tfexecutable.WorkingDir(wp) require.NoError(t, err, "creating working executable") ctx, cancel := context.WithTimeout(context.Background(), time.Minute*2) @@ -126,9 +128,19 @@ func Test_VerifyE2E(t *testing.T) { err = exe.Init(ctx) require.NoError(t, err, "terraform init") + tfVarFiles, err := tfvars.TFVarFiles("", subFS) + require.NoError(t, err, "loading tfvars files") + + planOpts := make([]tfexec.PlanOption, 0) + applyOpts := make([]tfexec.ApplyOption, 0) + for _, varFile := range tfVarFiles { + planOpts = append(planOpts, tfexec.VarFile(varFile)) + applyOpts = append(applyOpts, tfexec.VarFile(varFile)) + } + planOutFile := "tfplan" planOutPath := filepath.Join(wp, planOutFile) - _, err = exe.Plan(ctx, planOutPath) + _, err = exe.Plan(ctx, planOutPath, planOpts...) require.NoError(t, err, "terraform plan") plan, err := exe.ShowPlan(ctx, planOutPath) @@ -141,7 +153,7 @@ func Test_VerifyE2E(t *testing.T) { err = os.WriteFile(filepath.Join(wp, "plan.json"), pd, 0644) require.NoError(t, err, "writing plan.json") - _, err = exe.Apply(ctx) + _, err = exe.Apply(ctx, applyOpts...) require.NoError(t, err, "terraform apply") state, err := exe.Show(ctx) diff --git a/testdata/tfvars/.auto.tfvars.json b/testdata/tfvars/.auto.tfvars.json new file mode 100644 index 0000000..879a3b1 --- /dev/null +++ b/testdata/tfvars/.auto.tfvars.json @@ -0,0 +1 @@ +{"four":"jason"} diff --git a/testdata/tfvars/main.tf b/testdata/tfvars/main.tf new file mode 100644 index 0000000..1c950f4 --- /dev/null +++ b/testdata/tfvars/main.tf @@ -0,0 +1,61 @@ +// 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 +} + +variable "two" { + default = "bob" + type = string +} + +variable "three" { + default = "charlie" + type = string +} + +variable "four" { + default = "jack" + 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 + } + + option { + name = "two" + value = var.two + } + + option { + name = "three" + value = var.three + } + + option { + name = "four" + value = var.four + } +} diff --git a/testdata/tfvars/values.tfvars b/testdata/tfvars/values.tfvars new file mode 100644 index 0000000..83cabd4 --- /dev/null +++ b/testdata/tfvars/values.tfvars @@ -0,0 +1,2 @@ +one="alex" +three="claire" diff --git a/tfvars/load.go b/tfvars/load.go new file mode 100644 index 0000000..ad98456 --- /dev/null +++ b/tfvars/load.go @@ -0,0 +1,105 @@ +// Code taken from https://github.com/aquasecurity/trivy/blob/0449787eb52854cbdd7f4c5794adbf58965e60f8/pkg/iac/scanners/terraform/parser/load_vars.go +package tfvars + +import ( + "fmt" + "io/fs" + "path/filepath" + "strings" + + "github.com/hashicorp/hcl/v2" + "github.com/hashicorp/hcl/v2/hclsyntax" + hcljson "github.com/hashicorp/hcl/v2/json" + "github.com/zclconf/go-cty/cty" +) + +// TFVarFiles extracts any .tfvars files from the given directory. +// TODO: Test nested directories and how that should behave. +func TFVarFiles(path string, dir fs.FS) ([]string, error) { + dp := "." + entries, err := fs.ReadDir(dir, dp) + if err != nil { + return nil, fmt.Errorf("read dir %q: %w", dp, err) + } + + files := make([]string, 0) + for _, entry := range entries { + if entry.IsDir() { + subD, err := fs.Sub(dir, entry.Name()) + if err != nil { + return nil, fmt.Errorf("sub dir %q: %w", entry.Name(), err) + } + newFiles, err := TFVarFiles(filepath.Join(path, entry.Name()), subD) + if err != nil { + return nil, err + } + files = append(files, newFiles...) + } + + if filepath.Ext(entry.Name()) == ".tfvars" || strings.HasSuffix(entry.Name(), ".tfvars.json") { + files = append(files, filepath.Join(path, entry.Name())) + } + } + return files, nil +} + +func LoadTFVars(srcFS fs.FS, filenames []string) (map[string]cty.Value, error) { + combinedVars := make(map[string]cty.Value) + + // Intentionally avoid loading terraform variables from the host environment. + // Trivy (and terraform) use os.Environ() to search for "TF_VAR_" prefixed + // environment variables. + // + // Preview should be sandboxed, so this code should not be included. + + for _, filename := range filenames { + vars, err := LoadTFVarsFile(srcFS, filename) + if err != nil { + return nil, fmt.Errorf("failed to load tfvars from %s: %w", filename, err) + } + for k, v := range vars { + combinedVars[k] = v + } + } + + return combinedVars, nil +} + +func LoadTFVarsFile(srcFS fs.FS, filename string) (map[string]cty.Value, error) { + inputVars := make(map[string]cty.Value) + if filename == "" { + return inputVars, nil + } + + src, err := fs.ReadFile(srcFS, filepath.ToSlash(filename)) + if err != nil { + return nil, err + } + + var attrs hcl.Attributes + if strings.HasSuffix(filename, ".json") { + variableFile, err := hcljson.Parse(src, filename) + if err != nil { + return nil, err + } + attrs, err = variableFile.Body.JustAttributes() + if err != nil { + return nil, err + } + } else { + variableFile, err := hclsyntax.ParseConfig(src, filename, hcl.Pos{Line: 1, Column: 1}) + if err != nil { + return nil, err + } + attrs, err = variableFile.Body.JustAttributes() + if err != nil { + return nil, err + } + } + + for _, attr := range attrs { + inputVars[attr.Name], _ = attr.Expr.Value(&hcl.EvalContext{}) + } + + return inputVars, nil +} From 99bbcdbeea5870676e4e5f9891245dbeca1c500e Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Mon, 14 Jul 2025 09:22:09 -0600 Subject: [PATCH 09/15] chore: remove typescript generated types (#167) --- site/src/types/preview.ts | 134 -------------------------------------- 1 file changed, 134 deletions(-) delete mode 100644 site/src/types/preview.ts diff --git a/site/src/types/preview.ts b/site/src/types/preview.ts deleted file mode 100644 index d415468..0000000 --- a/site/src/types/preview.ts +++ /dev/null @@ -1,134 +0,0 @@ -// Code generated by 'guts'. DO NOT EDIT. - -// From types/diagnostics.go -export const DiagnosticCodeRequired = "required"; - -// From types/diagnostics.go -export interface DiagnosticExtra { - readonly code: string; - // empty interface{} type, falling back to unknown - readonly Wrapped: unknown; -} - -// From types/diagnostics.go -export type DiagnosticSeverityString = "error" | "warning"; - -export const DiagnosticSeverityStrings: DiagnosticSeverityString[] = ["error", "warning"]; - -// From types/diagnostics.go -export type Diagnostics = readonly (FriendlyDiagnostic)[]; - -// From types/diagnostics.go -export interface FriendlyDiagnostic { - readonly severity: DiagnosticSeverityString; - readonly summary: string; - readonly detail: string; - readonly extra: DiagnosticExtra; -} - -// From types/value.go -export interface NullHCLString { - readonly value: string; - readonly valid: boolean; -} - -// From types/parameter.go -export interface Parameter extends ParameterData { - readonly value: NullHCLString; - readonly diagnostics: Diagnostics; -} - -// From types/parameter.go -export interface ParameterData { - readonly name: string; - readonly display_name: string; - readonly description: string; - readonly type: ParameterType; - // this is likely an enum in an external package "github.com/coder/terraform-provider-coder/v2/provider.ParameterFormType" - readonly form_type: string; - readonly styling: ParameterStyling; - readonly mutable: boolean; - readonly default_value: NullHCLString; - readonly icon: string; - readonly options: readonly (ParameterOption)[]; - readonly validations: readonly (ParameterValidation)[]; - readonly required: boolean; - readonly order: number; - readonly ephemeral: boolean; -} - -// From types/parameter.go -export interface ParameterOption { - readonly name: string; - readonly description: string; - readonly value: NullHCLString; - readonly icon: string; -} - -// From types/parameter.go -export interface ParameterStyling { - readonly placeholder?: string; - readonly disabled?: boolean; - readonly label?: string; -} - -// From types/enum.go -export type ParameterType = "bool" | "list(string)" | "number" | "string"; - -export const ParameterTypes: ParameterType[] = ["bool", "list(string)", "number", "string"]; - -// From types/parameter.go -export interface ParameterValidation { - readonly validation_error: string; - readonly validation_regex: string | null; - readonly validation_min: number | null; - readonly validation_max: number | null; - readonly validation_monotonic: string | null; -} - -// From web/session.go -export interface Request { - readonly id: number; - readonly inputs: Record; -} - -// From web/session.go -export interface Response { - readonly id: number; - readonly diagnostics: Diagnostics; - readonly parameters: readonly Parameter[]; -} - -// From web/session.go -export interface SessionInputs { - readonly PlanPath: string; - readonly User: WorkspaceOwner; -} - -// From types/value.go -export const UnknownStringValue = ""; - -// From types/parameter.go -export const ValidationMonotonicDecreasing = "decreasing"; - -// From types/parameter.go -export const ValidationMonotonicIncreasing = "increasing"; - -// From types/owner.go -export interface WorkspaceOwner { - readonly id: string; - readonly name: string; - readonly full_name: string; - readonly email: string; - readonly ssh_public_key: string; - readonly groups: readonly string[]; - readonly login_type: string; - readonly rbac_roles: readonly WorkspaceOwnerRBACRole[]; -} - -// From types/owner.go -export interface WorkspaceOwnerRBACRole { - readonly name: string; - readonly org_id: string; -} - From a737d4750448579135a7c8f8c3d39f40149d7603 Mon Sep 17 00:00:00 2001 From: Sas Swart Date: Mon, 14 Jul 2025 17:38:28 +0200 Subject: [PATCH 10/15] feat: Preview can now show presets and validate them (#149) This PR provides a mechanism to "lint" presets to ensure that they refer to parameters that actually exist and define values that are actually valid for those parameters. Relates to: https://github.com/coder/coder/issues/17333 Screenshot 2025-06-18 at 12 03 37 --- cli/clidisplay/resources.go | 29 +++++++++++++++ cli/root.go | 28 ++++++++++++++- extract/parameter.go | 15 ++++---- extract/preset.go | 45 +++++++++++++++++++++++ preset.go | 58 ++++++++++++++++++++++++++++++ preview.go | 3 ++ preview_test.go | 62 ++++++++++++++++++++++++++++++++ testdata/invalidpresets/main.tf | 63 +++++++++++++++++++++++++++++++++ types/preset.go | 18 ++++++++++ 9 files changed, 314 insertions(+), 7 deletions(-) create mode 100644 extract/preset.go create mode 100644 preset.go create mode 100644 testdata/invalidpresets/main.tf create mode 100644 types/preset.go diff --git a/cli/clidisplay/resources.go b/cli/clidisplay/resources.go index f7eab6e..063086a 100644 --- a/cli/clidisplay/resources.go +++ b/cli/clidisplay/resources.go @@ -74,6 +74,35 @@ func Parameters(writer io.Writer, params []types.Parameter, files map[string]*hc _, _ = fmt.Fprintln(writer, tableWriter.Render()) } +func Presets(writer io.Writer, presets []types.Preset, files map[string]*hcl.File) { + tableWriter := table.NewWriter() + tableWriter.SetStyle(table.StyleLight) + tableWriter.Style().Options.SeparateColumns = false + row := table.Row{"Preset"} + tableWriter.AppendHeader(row) + for _, p := range presets { + tableWriter.AppendRow(table.Row{ + fmt.Sprintf("%s\n%s", p.Name, formatPresetParameters(p.Parameters)), + }) + if hcl.Diagnostics(p.Diagnostics).HasErrors() { + var out bytes.Buffer + WriteDiagnostics(&out, files, hcl.Diagnostics(p.Diagnostics)) + tableWriter.AppendRow(table.Row{out.String()}) + } + + tableWriter.AppendSeparator() + } + _, _ = fmt.Fprintln(writer, tableWriter.Render()) +} + +func formatPresetParameters(presetParameters map[string]string) string { + var str strings.Builder + for presetParamName, PresetParamValue := range presetParameters { + _, _ = str.WriteString(fmt.Sprintf("%s = %s\n", presetParamName, PresetParamValue)) + } + return str.String() +} + func formatOptions(selected []string, options []*types.ParameterOption) string { var str strings.Builder sep := "" diff --git a/cli/root.go b/cli/root.go index ab1afc5..0971018 100644 --- a/cli/root.go +++ b/cli/root.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "os" + "slices" "strings" "github.com/hashicorp/hcl/v2" @@ -27,6 +28,7 @@ func (r *RootCmd) Root() *serpent.Command { vars []string groups []string planJSON string + preset string ) cmd := &serpent.Command{ Use: "codertf", @@ -64,10 +66,26 @@ func (r *RootCmd) Root() *serpent.Command { Default: "", Value: serpent.StringArrayOf(&groups), }, + { + Name: "preset", + Description: "Name of the preset to define parameters. Run preview without this flag first to see a list of presets.", + Flag: "preset", + FlagShorthand: "s", + Default: "", + Value: serpent.StringOf(&preset), + }, }, Handler: func(i *serpent.Invocation) error { dfs := os.DirFS(dir) + ctx := i.Context() + + output, _ := preview.Preview(ctx, preview.Input{}, dfs) + presets := output.Presets + chosenPresetIndex := slices.IndexFunc(presets, func(p types.Preset) bool { + return p.Name == preset + }) + rvars := make(map[string]string) for _, val := range vars { parts := strings.Split(val, "=") @@ -76,6 +94,11 @@ func (r *RootCmd) Root() *serpent.Command { } rvars[parts[0]] = parts[1] } + if chosenPresetIndex != -1 { + for paramName, paramValue := range presets[chosenPresetIndex].Parameters { + rvars[paramName] = paramValue + } + } input := preview.Input{ PlanJSONPath: planJSON, @@ -85,7 +108,6 @@ func (r *RootCmd) Root() *serpent.Command { }, } - ctx := i.Context() output, diags := preview.Preview(ctx, input, dfs) if output == nil { return diags @@ -103,6 +125,10 @@ func (r *RootCmd) Root() *serpent.Command { clidisplay.WriteDiagnostics(os.Stderr, output.Files, diags) } + if chosenPresetIndex == -1 { + clidisplay.Presets(os.Stdout, presets, output.Files) + } + clidisplay.Parameters(os.Stdout, output.Parameters, output.Files) if !output.ModuleOutput.IsNull() && !(output.ModuleOutput.Type().IsObjectType() && output.ModuleOutput.LengthInt() == 0) { diff --git a/extract/parameter.go b/extract/parameter.go index 0d45a8b..d40a6cc 100644 --- a/extract/parameter.go +++ b/extract/parameter.go @@ -274,15 +274,18 @@ func requiredString(block *terraform.Block, key string) (string, *hcl.Diagnostic } diag := &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: fmt.Sprintf("Invalid %q attribute for block %s", key, block.Label()), - Detail: fmt.Sprintf("Expected a string, got %q", typeName), - Subject: &(tyAttr.HCLAttribute().Range), - //Context: &(block.HCLBlock().DefRange), - Expression: tyAttr.HCLAttribute().Expr, + Severity: hcl.DiagError, + Summary: fmt.Sprintf("Invalid %q attribute for block %s", key, block.Label()), + Detail: fmt.Sprintf("Expected a string, got %q", typeName), EvalContext: block.Context().Inner(), } + if tyAttr.IsNotNil() { + diag.Subject = &(tyAttr.HCLAttribute().Range) + // diag.Context = &(block.HCLBlock().DefRange) + diag.Expression = tyAttr.HCLAttribute().Expr + } + if !tyVal.IsWhollyKnown() { refs := hclext.ReferenceNames(tyAttr.HCLAttribute().Expr) if len(refs) > 0 { diff --git a/extract/preset.go b/extract/preset.go new file mode 100644 index 0000000..01c9310 --- /dev/null +++ b/extract/preset.go @@ -0,0 +1,45 @@ +package extract + +import ( + "github.com/aquasecurity/trivy/pkg/iac/terraform" + "github.com/coder/preview/types" + "github.com/hashicorp/hcl/v2" +) + +func PresetFromBlock(block *terraform.Block) types.Preset { + p := types.Preset{ + PresetData: types.PresetData{ + Parameters: make(map[string]string), + }, + Diagnostics: types.Diagnostics{}, + } + + if !block.IsResourceType(types.BlockTypePreset) { + p.Diagnostics = append(p.Diagnostics, &hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Invalid Preset", + Detail: "Block is not a preset", + }) + return p + } + + pName, nameDiag := requiredString(block, "name") + if nameDiag != nil { + p.Diagnostics = append(p.Diagnostics, nameDiag) + } + p.Name = pName + + // GetAttribute and AsMapValue both gracefully handle `nil`, `null` and `unknown` values. + // All of these return an empty map, which then makes the loop below a no-op. + params := block.GetAttribute("parameters").AsMapValue() + for presetParamName, presetParamValue := range params.Value() { + p.Parameters[presetParamName] = presetParamValue + } + + defaultAttr := block.GetAttribute("default") + if defaultAttr != nil { + p.Default = defaultAttr.Value().True() + } + + return p +} diff --git a/preset.go b/preset.go new file mode 100644 index 0000000..0e5ca74 --- /dev/null +++ b/preset.go @@ -0,0 +1,58 @@ +package preview + +import ( + "fmt" + "slices" + + "github.com/aquasecurity/trivy/pkg/iac/terraform" + "github.com/hashicorp/hcl/v2" + + "github.com/coder/preview/extract" + "github.com/coder/preview/types" +) + +// presets extracts all presets from the given modules. It then validates the name, +// parameters and default preset. +func presets(modules terraform.Modules, parameters []types.Parameter) []types.Preset { + foundPresets := make([]types.Preset, 0) + var defaultPreset *types.Preset + + for _, mod := range modules { + blocks := mod.GetDatasByType(types.BlockTypePreset) + for _, block := range blocks { + preset := extract.PresetFromBlock(block) + switch true { + case defaultPreset != nil && preset.Default: + preset.Diagnostics = append(preset.Diagnostics, &hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Multiple default presets", + Detail: fmt.Sprintf("Only one preset can be marked as default. %q is already marked as default", defaultPreset.Name), + }) + case defaultPreset == nil && preset.Default: + defaultPreset = &preset + } + + for paramName, paramValue := range preset.Parameters { + templateParamIndex := slices.IndexFunc(parameters, func(p types.Parameter) bool { + return p.Name == paramName + }) + if templateParamIndex == -1 { + preset.Diagnostics = append(preset.Diagnostics, &hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Undefined Parameter", + Detail: fmt.Sprintf("Preset parameter %q is not defined by the template.", paramName), + }) + continue + } + templateParam := parameters[templateParamIndex] + for _, diag := range templateParam.Valid(types.StringLiteral(paramValue)) { + preset.Diagnostics = append(preset.Diagnostics, diag) + } + } + + foundPresets = append(foundPresets, preset) + } + } + + return foundPresets +} diff --git a/preview.go b/preview.go index 7cf360d..06db808 100644 --- a/preview.go +++ b/preview.go @@ -41,6 +41,7 @@ type Output struct { Parameters []types.Parameter `json:"parameters"` WorkspaceTags types.TagBlocks `json:"workspace_tags"` + Presets []types.Preset `json:"presets"` // Files is included for printing diagnostics. // They can be marshalled, but not unmarshalled. This is a limitation // of the HCL library. @@ -178,6 +179,7 @@ func Preview(ctx context.Context, input Input, dir fs.FS) (output *Output, diagn diags := make(hcl.Diagnostics, 0) rp, rpDiags := parameters(modules) + presets := presets(modules, rp) tags, tagDiags := workspaceTags(modules, p.Files()) // Add warnings @@ -187,6 +189,7 @@ func Preview(ctx context.Context, input Input, dir fs.FS) (output *Output, diagn ModuleOutput: outputs, Parameters: rp, WorkspaceTags: tags, + Presets: presets, Files: p.Files(), }, diags.Extend(rpDiags).Extend(tagDiags) } diff --git a/preview_test.go b/preview_test.go index e92d9df..435fb93 100644 --- a/preview_test.go +++ b/preview_test.go @@ -43,6 +43,7 @@ func Test_Extract(t *testing.T) { expTags map[string]string unknownTags []string params map[string]assertParam + presets func(t *testing.T, presets []types.Preset) warnings []*regexp.Regexp }{ { @@ -243,6 +244,62 @@ func Test_Extract(t *testing.T) { errorDiagnostics("Required"), }, }, + { + name: "invalid presets", + dir: "invalidpresets", + expTags: map[string]string{}, + input: preview.Input{}, + unknownTags: []string{}, + params: map[string]assertParam{ + "valid_parameter_name": ap(). + optVals("valid_option_value"), + }, + presets: func(t *testing.T, presets []types.Preset) { + presetMap := map[string]func(t *testing.T, preset types.Preset){ + "empty_parameters": func(t *testing.T, preset types.Preset) { + require.Len(t, preset.Diagnostics, 0) + }, + "no_parameters": func(t *testing.T, preset types.Preset) { + require.Len(t, preset.Diagnostics, 0) + }, + "invalid_parameter_name": func(t *testing.T, preset types.Preset) { + require.Len(t, preset.Diagnostics, 1) + require.Equal(t, preset.Diagnostics[0].Summary, "Undefined Parameter") + require.Equal(t, preset.Diagnostics[0].Detail, "Preset parameter \"invalid_parameter_name\" is not defined by the template.") + }, + "invalid_parameter_value": func(t *testing.T, preset types.Preset) { + require.Len(t, preset.Diagnostics, 1) + require.Equal(t, preset.Diagnostics[0].Summary, "Value must be a valid option") + require.Equal(t, preset.Diagnostics[0].Detail, "the value \"invalid_value\" must be defined as one of options") + }, + "valid_preset": func(t *testing.T, preset types.Preset) { + require.Len(t, preset.Diagnostics, 0) + require.Equal(t, preset.Parameters, map[string]string{ + "valid_parameter_name": "valid_option_value", + }) + }, + } + + for _, preset := range presets { + if fn, ok := presetMap[preset.Name]; ok { + fn(t, preset) + } + } + + var defaultPresetsWithError int + for _, preset := range presets { + if preset.Name == "default_preset" || preset.Name == "another_default_preset" { + for _, diag := range preset.Diagnostics { + if diag.Summary == "Multiple default presets" { + defaultPresetsWithError++ + break + } + } + } + } + require.Equal(t, 1, defaultPresetsWithError, "exactly one default preset should have the multiple defaults error") + }, + }, { name: "required", dir: "required", @@ -575,6 +632,11 @@ func Test_Extract(t *testing.T) { require.True(t, ok, "unknown parameter %s", param.Name) check(t, param) } + + // Assert presets + if tc.presets != nil { + tc.presets(t, output.Presets) + } }) } } diff --git a/testdata/invalidpresets/main.tf b/testdata/invalidpresets/main.tf new file mode 100644 index 0000000..d9abd56 --- /dev/null +++ b/testdata/invalidpresets/main.tf @@ -0,0 +1,63 @@ +terraform { + required_providers { + coder = { + source = "coder/coder" + version = "2.8.0" + } + } +} + +data "coder_parameter" "valid_parameter" { + name = "valid_parameter_name" + default = "valid_option_value" + option { + name = "valid_option_name" + value = "valid_option_value" + } +} + +data "coder_workspace_preset" "no_parameters" { + name = "no_parameters" +} + +data "coder_workspace_preset" "empty_parameters" { + name = "empty_parameters" + parameters = {} +} + +data "coder_workspace_preset" "invalid_parameter_name" { + name = "invalid_parameter_name" + parameters = { + "invalid_parameter_name" = "irrelevant_value" + } +} + +data "coder_workspace_preset" "invalid_parameter_value" { + name = "invalid_parameter_value" + parameters = { + "valid_parameter_name" = "invalid_value" + } +} + +data "coder_workspace_preset" "valid_preset" { + name = "valid_preset" + parameters = { + "valid_parameter_name" = "valid_option_value" + } +} + +data "coder_workspace_preset" "default_preset" { + name = "default_preset" + parameters = { + "valid_parameter_name" = "valid_option_value" + } + default = true +} + +data "coder_workspace_preset" "another_default_preset" { + name = "another_default_preset" + parameters = { + "valid_parameter_name" = "valid_option_value" + } + default = true +} \ No newline at end of file diff --git a/types/preset.go b/types/preset.go new file mode 100644 index 0000000..da05e41 --- /dev/null +++ b/types/preset.go @@ -0,0 +1,18 @@ +package types + +const ( + BlockTypePreset = "coder_workspace_preset" +) + +type Preset struct { + PresetData + // Diagnostics is used to store any errors that occur during parsing + // of the preset. + Diagnostics Diagnostics `json:"diagnostics"` +} + +type PresetData struct { + Name string `json:"name"` + Parameters map[string]string `json:"parameters"` + Default bool `json:"default"` +} From 04b30642dedcd8f66cb78c7028d6abe5b5f0b640 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 6 Aug 2025 11:40:22 -0500 Subject: [PATCH 11/15] chore: fix nil ptr deref on terraform plan data (#171) Could hit a deref if the plan was empty. --- plan.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/plan.go b/plan.go index bcf44fa..ef19c36 100644 --- a/plan.go +++ b/plan.go @@ -80,8 +80,15 @@ func planJSONHook(dfs fs.FS, input Input) (func(ctx *tfcontext.Context, blocks t // priorPlanModule returns the state data of the module a given block is in. func priorPlanModule(plan *tfjson.Plan, block *terraform.Block) *tfjson.StateModule { + if plan.PriorState == nil || plan.PriorState.Values == nil { + return nil // No root module available in the plan, nothing to do + } + + rootModule := plan.PriorState.Values.RootModule + if !block.InModule() { - return plan.PriorState.Values.RootModule + // If the block is not in a module, then we can just return the root module. + return rootModule } var modPath []string @@ -94,9 +101,12 @@ func priorPlanModule(plan *tfjson.Plan, block *terraform.Block) *tfjson.StateMod } } - current := plan.PriorState.Values.RootModule + current := rootModule for i := range modPath { idx := slices.IndexFunc(current.ChildModules, func(m *tfjson.StateModule) bool { + if m == nil { + return false + } return m.Address == strings.Join(modPath[:i+1], ".") }) if idx == -1 { From d3c65fb5e3cf0f51f9dcbe62f7ae5492333b42a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Aug 2025 07:17:40 -0500 Subject: [PATCH 12/15] chore(deps): bump actions/checkout from 4.2.2 to 5.0.0 (#176) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/checkout](https://github.com/actions/checkout) from 4.2.2 to 5.0.0.
Release notes

Sourced from actions/checkout's releases.

v5.0.0

What's Changed

⚠️ Minimum Compatible Runner Version

v2.327.1
Release Notes

Make sure your runner is updated to this version or newer to use this release.

Full Changelog: https://github.com/actions/checkout/compare/v4...v5.0.0

v4.3.0

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v4...v4.3.0

Changelog

Sourced from actions/checkout's changelog.

V5.0.0

V4.3.0

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4.2.2&new-version=5.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/gen.yaml | 2 +- .github/workflows/gotest.yml | 2 +- .github/workflows/lint.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/gen.yaml b/.github/workflows/gen.yaml index c97c5bd..e2027b8 100644 --- a/.github/workflows/gen.yaml +++ b/.github/workflows/gen.yaml @@ -18,7 +18,7 @@ jobs: - uses: actions/setup-go@v5 with: go-version: 1.22.8 - - uses: actions/checkout@v4.2.2 + - uses: actions/checkout@v5.0.0 - name: Make Gen run: make --output-sync -B gen - name: Check for unstaged files diff --git a/.github/workflows/gotest.yml b/.github/workflows/gotest.yml index 3253c57..9ab5ef0 100644 --- a/.github/workflows/gotest.yml +++ b/.github/workflows/gotest.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/setup-go@v5 with: go-version: 1.22.8 - - uses: actions/checkout@v4.2.2 + - uses: actions/checkout@v5.0.0 - name: Install gotestsum shell: bash run: go install gotest.tools/gotestsum@latest diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 4de789f..262b907 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 5 steps: - - uses: actions/checkout@v4.2.2 + - uses: actions/checkout@v5.0.0 - uses: actions/setup-go@v5 with: go-version: 1.22.8 From e221dcdcef0180775faf4f45ddcde0e6205e8b01 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Aug 2025 08:57:14 -0500 Subject: [PATCH 13/15] chore(deps): bump github.com/stretchr/testify from 1.10.0 to 1.11.0 (#179) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.10.0 to 1.11.0.
Release notes

Sourced from github.com/stretchr/testify's releases.

v1.11.0

What's Changed

Functional Changes

v1.11.0 Includes a number of performance improvements.

Fixes

Documentation, Build & CI

... (truncated)

Commits
  • b7801fb Merge pull request #1778 from stretchr/dependabot/github_actions/actions/chec...
  • 69831f3 build(deps): bump actions/checkout from 4 to 5
  • a53be35 Improve captureTestingT helper
  • aafb604 mock: improve formatting of error message
  • 7218e03 improve error msg
  • 929a212 Merge pull request #1758 from stretchr/dolmen/suite-faster-method-filtering
  • bc7459e suite: faster filtering of methods (-testify.m)
  • 7d37b5c suite: refactor methodFilter
  • c58bc90 Merge pull request #1764 from stretchr/dolmen/suite-refactor-stats-for-readab...
  • 87101a6 suite.Run: refactor handling of stats
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/stretchr/testify&package-manager=go_modules&previous-version=1.10.0&new-version=1.11.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index aae669c..7fa5583 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0 github.com/jedib0t/go-pretty/v6 v6.6.7 github.com/quasilyte/go-ruleguard/dsl v0.3.22 - github.com/stretchr/testify v1.10.0 + github.com/stretchr/testify v1.11.0 github.com/zclconf/go-cty v1.16.3 golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da ) diff --git a/go.sum b/go.sum index c0d28a2..387b250 100644 --- a/go.sum +++ b/go.sum @@ -1164,8 +1164,8 @@ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1F github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.0 h1:ib4sjIrwZKxE5u/Japgo/7SJV3PvgjGiRNAvTVGqQl8= +github.com/stretchr/testify v1.11.0/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/testcontainers/testcontainers-go v0.37.0 h1:L2Qc0vkTw2EHWQ08djon0D2uw7Z/PtHS/QzZZ5Ra/hg= github.com/testcontainers/testcontainers-go v0.37.0/go.mod h1:QPzbxZhQ6Bclip9igjLFj6z0hs01bU8lrl2dHQmgFGM= github.com/testcontainers/testcontainers-go/modules/localstack v0.37.0 h1:nPuxUYseqS0eYJg7KDJd95PhoMhdpTnSNtkDLwWFngo= From 8f67d5f72de00dd74dfe108338e99f23f8ae257e Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 29 Aug 2025 06:59:18 -0500 Subject: [PATCH 14/15] chore: update trivy dependency (#182) Updated to https://github.com/coder/trivy/pull/19 Solve an issue when a module is located in a subdirectory of a `git` source. This PR: https://github.com/aquasecurity/trivy/pull/9294 --- go.mod | 70 +++++++++++++----------- go.sum | 167 ++++++++++++++++++++++++++++++--------------------------- 2 files changed, 128 insertions(+), 109 deletions(-) diff --git a/go.mod b/go.mod index 7fa5583..ac42d7c 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,12 @@ module github.com/coder/preview -go 1.24.2 +go 1.24.4 + +toolchain go1.24.6 require ( cdr.dev/slog v1.6.2-0.20240126064726-20367d4aede6 - github.com/aquasecurity/trivy v0.58.2 + github.com/aquasecurity/trivy v0.61.1-0.20250407075540-f1329c7ea1aa github.com/coder/serpent v0.10.0 github.com/coder/terraform-provider-coder/v2 v2.8.0 github.com/coder/websocket v1.8.13 @@ -24,26 +26,30 @@ require ( ) require ( - cel.dev/expr v0.20.0 // indirect + cel.dev/expr v0.24.0 // indirect cloud.google.com/go v0.118.3 // indirect cloud.google.com/go/auth v0.15.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect - cloud.google.com/go/compute/metadata v0.6.0 // indirect + cloud.google.com/go/compute/metadata v0.7.0 // indirect cloud.google.com/go/iam v1.4.1 // indirect cloud.google.com/go/monitoring v1.24.0 // indirect cloud.google.com/go/storage v1.50.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.26.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0 // indirect - github.com/ProtonMail/go-crypto v1.1.6 // indirect + github.com/ProtonMail/go-crypto v1.3.0 // indirect github.com/agext/levenshtein v1.2.3 // indirect + github.com/alecthomas/chroma v0.10.0 // indirect github.com/apparentlymart/go-cidr v1.1.0 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/aquasecurity/go-version v0.0.1 // indirect + github.com/aquasecurity/iamgo v0.0.10 // indirect + github.com/aquasecurity/jfather v0.0.8 // indirect + github.com/aquasecurity/trivy-checks v1.11.3-0.20250604022615-9a7efa7c9169 // indirect github.com/aws/aws-sdk-go v1.55.7 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect - github.com/bmatcuk/doublestar/v4 v4.8.1 // indirect + github.com/bmatcuk/doublestar/v4 v4.9.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/charmbracelet/lipgloss v0.8.0 // indirect github.com/cloudflare/circl v1.6.1 // indirect @@ -56,10 +62,11 @@ require ( github.com/fatih/color v1.18.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-jose/go-jose/v4 v4.0.5 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/go-cmp v0.7.0 // indirect + github.com/google/go-containerregistry v0.20.6 // indirect github.com/google/s2a-go v0.1.9 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect @@ -69,7 +76,7 @@ require ( github.com/hashicorp/go-getter v1.7.8 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-retryablehttp v0.7.7 // indirect + github.com/hashicorp/go-retryablehttp v0.7.8 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/logutils v1.0.0 // indirect @@ -89,14 +96,15 @@ require ( github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/muesli/reflow v0.3.0 // indirect github.com/muesli/termenv v0.15.2 // indirect + github.com/package-url/packageurl-go v0.1.3 // indirect github.com/pion/transport/v2 v2.0.0 // indirect github.com/pion/udp v0.1.4 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect - github.com/samber/lo v1.50.0 // indirect - github.com/spf13/pflag v1.0.6 // indirect + github.com/samber/lo v1.51.0 // indirect + github.com/spf13/pflag v1.0.7 // indirect github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect github.com/ulikunitz/xz v0.5.12 // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect @@ -107,29 +115,29 @@ require ( go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/contrib/detectors/gcp v1.34.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect - go.opentelemetry.io/otel v1.35.0 // indirect - go.opentelemetry.io/otel/metric v1.35.0 // indirect - go.opentelemetry.io/otel/sdk v1.35.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.35.0 // indirect - go.opentelemetry.io/otel/trace v1.35.0 // indirect - golang.org/x/crypto v0.38.0 // indirect - golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect - golang.org/x/mod v0.24.0 // indirect - golang.org/x/net v0.40.0 // indirect - golang.org/x/oauth2 v0.28.0 // indirect - golang.org/x/sync v0.14.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/term v0.32.0 // indirect - golang.org/x/text v0.25.0 // indirect - golang.org/x/time v0.11.0 // indirect - golang.org/x/tools v0.33.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect + go.opentelemetry.io/otel v1.36.0 // indirect + go.opentelemetry.io/otel/metric v1.36.0 // indirect + go.opentelemetry.io/otel/sdk v1.36.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.36.0 // indirect + go.opentelemetry.io/otel/trace v1.36.0 // indirect + golang.org/x/crypto v0.40.0 // indirect + golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 // indirect + golang.org/x/mod v0.26.0 // indirect + golang.org/x/net v0.42.0 // indirect + golang.org/x/oauth2 v0.30.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/term v0.33.0 // indirect + golang.org/x/text v0.27.0 // indirect + golang.org/x/time v0.12.0 // indirect + golang.org/x/tools v0.34.1-0.20250610205101-c26dd3ba555e // indirect google.golang.org/api v0.228.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 // indirect - google.golang.org/grpc v1.72.1 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect + google.golang.org/grpc v1.72.2 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect @@ -137,4 +145,4 @@ require ( // Trivy has some issues that we're floating patches for, and will hopefully // be upstreamed eventually. -replace github.com/aquasecurity/trivy => github.com/coder/trivy v0.0.0-20250527170238-9416a59d7019 +replace github.com/aquasecurity/trivy => github.com/coder/trivy v0.0.0-20250807211036-0bb0acd620a8 diff --git a/go.sum b/go.sum index 387b250..8ff6087 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ cdr.dev/slog v1.6.2-0.20240126064726-20367d4aede6 h1:KHblWIE/KHOwQ6lEbMZt6YpcGve2FEZ1sDtrW1Am5UI= cdr.dev/slog v1.6.2-0.20240126064726-20367d4aede6/go.mod h1:NaoTA7KwopCrnaSb0JXTC0PTp/O/Y83Lndnq0OEV3ZQ= -cel.dev/expr v0.20.0 h1:OunBvVCfvpWlt4dN7zg3FM6TDkzOePe1+foGJ9AXeeI= -cel.dev/expr v0.20.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= +cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= +cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -186,8 +186,8 @@ cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZ cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= -cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= +cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU= +cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo= cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= @@ -621,8 +621,8 @@ dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.26.0 h1:f2Qw/Ehhimh5uO1fayV0QIW7DShEQqhtUfhYc+cBPlw= @@ -637,8 +637,8 @@ github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0 github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw= -github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= +github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw= +github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= @@ -663,6 +663,8 @@ github.com/aquasecurity/iamgo v0.0.10 h1:t/HG/MI1eSephztDc+Rzh/YfgEa+NqgYRSfr6pH github.com/aquasecurity/iamgo v0.0.10/go.mod h1:GI9IQJL2a+C+V2+i3vcwnNKuIJXZ+HAfqxZytwy+cPk= github.com/aquasecurity/jfather v0.0.8 h1:tUjPoLGdlkJU0qE7dSzd1MHk2nQFNPR0ZfF+6shaExE= github.com/aquasecurity/jfather v0.0.8/go.mod h1:Ag+L/KuR/f8vn8okUi8Wc1d7u8yOpi2QTaGX10h71oY= +github.com/aquasecurity/trivy-checks v1.11.3-0.20250604022615-9a7efa7c9169 h1:TckzIxUX7lZaU9f2lNxCN0noYYP8fzmSQf6a4JdV83w= +github.com/aquasecurity/trivy-checks v1.11.3-0.20250604022615-9a7efa7c9169/go.mod h1:nT69xgRcBD4NlHwTBpWMYirpK5/Zpl8M+XDOgmjMn2k= github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE= github.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= @@ -670,8 +672,8 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiE github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= -github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38= -github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= +github.com/bmatcuk/doublestar/v4 v4.9.0 h1:DBvuZxjdKkRP/dr4GVV4w2fnmrk5Hxc90T51LZjv0JA= +github.com/bmatcuk/doublestar/v4 v4.9.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= @@ -714,10 +716,14 @@ github.com/coder/serpent v0.10.0 h1:ofVk9FJXSek+SmL3yVE3GoArP83M+1tX+H7S4t8BSuM= github.com/coder/serpent v0.10.0/go.mod h1:cZFW6/fP+kE9nd/oRkEHJpG6sXCtQ+AX7WMMEHv0Y3Q= github.com/coder/terraform-provider-coder/v2 v2.8.0 h1:pbWfegCPI0v8eATgE8kGwIyuaMPgMRIcdLF2GTVkgG0= github.com/coder/terraform-provider-coder/v2 v2.8.0/go.mod h1:WrdLSbihuzH1RZhwrU+qmkqEhUbdZT/sjHHdarm5b5g= -github.com/coder/trivy v0.0.0-20250527170238-9416a59d7019 h1:MHkv/W7l9eRAN9gOG0qZ1TLRGWIIfNi92273vPAQ8Fs= -github.com/coder/trivy v0.0.0-20250527170238-9416a59d7019/go.mod h1:eqk+w9RLBmbd/cB5XfPZFuVn77cf/A6fB7qmEVeSmXk= +github.com/coder/trivy v0.0.0-20250807211036-0bb0acd620a8 h1:VYB/6cIIKsVkwXOAWbqpj4Ux+WwF/XTnRyvHcwfHZ7A= +github.com/coder/trivy v0.0.0-20250807211036-0bb0acd620a8/go.mod h1:O73tP+UvJlI2GQZD060Jt0sf+6alKcGAgORh6sgB0+M= github.com/coder/websocket v1.8.13 h1:f3QZdXy7uGVz+4uCJy2nTZyM0yTBj8yANEHhqlXZ9FE= github.com/coder/websocket v1.8.13/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= +github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= +github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= +github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/containerd/platforms v1.0.0-rc.1 h1:83KIq4yy1erSRgOVHNk1HYdPvzdJ5CnsWaRoJX4C41E= @@ -733,18 +739,19 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo= github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/docker/docker v28.1.1+incompatible h1:49M11BFLsVO1gxY9UX9p/zwkE/rswggs8AdFmXQw51I= -github.com/docker/docker v28.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI= +github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I= -github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= +github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -790,8 +797,8 @@ github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66D github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM= github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= -github.com/go-git/go-git/v5 v5.16.0 h1:k3kuOEpkc0DeY7xlL6NaaNg39xdgQbtH5mwCafHO9AQ= -github.com/go-git/go-git/v5 v5.16.0/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8= +github.com/go-git/go-git/v5 v5.16.2 h1:fT6ZIOjE5iEnkzKyxTHK1W4HGAsPhqEqiSAssSO77hM= +github.com/go-git/go-git/v5 v5.16.2/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -800,16 +807,16 @@ github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JS github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= -github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= -github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= +github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v4.3.1+incompatible h1:0/KbAdpx3UXAx1kEOWHJeOkpbgRFGHVgv+CFIY7dBJI= github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -878,6 +885,8 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-containerregistry v0.20.6 h1:cvWX87UxxLgaH76b4hIvya6Dzz9qHB31qAwjAohdSTU= +github.com/google/go-containerregistry v0.20.6/go.mod h1:T0x8MuoAoKX/873bkeSfLD2FAkwCDf9/HZgsFJ02E2Y= github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -950,8 +959,8 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-plugin v1.6.3 h1:xgHB+ZUSYeuJi96WtxEjzi23uh7YQpznjGh0U0UUrwg= github.com/hashicorp/go-plugin v1.6.3/go.mod h1:MRobyh+Wc/nYy1V4KAXUiYfzxoYhs7V1mlH1Z7iY2h0= -github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= -github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= +github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48= +github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw= github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= @@ -1071,8 +1080,8 @@ github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= -github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= -github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= +github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= @@ -1087,6 +1096,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= +github.com/package-url/packageurl-go v0.1.3 h1:4juMED3hHiz0set3Vq3KeQ75KD1avthoXLtmE3I0PLs= +github.com/package-url/packageurl-go v0.1.3/go.mod h1:nKAWB8E6uk1MHqiS/lQb9pYBGH2+mdJ2PJc2s50dQY0= github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= @@ -1127,16 +1138,16 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= -github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= -github.com/samber/lo v1.50.0 h1:XrG0xOeHs+4FQ8gJR97zDz5uOFMW7OwFWiFVzqopKgY= -github.com/samber/lo v1.50.0/go.mod h1:RjZyNk6WSnUFRKK6EyOhsRJMqft3G+pg7dCWHQCWvsc= +github.com/samber/lo v1.51.0 h1:kysRYLbHy/MB7kQZf5DSN50JHmMsNEdeY24VzJFu7wI= +github.com/samber/lo v1.51.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= -github.com/shirou/gopsutil/v4 v4.25.1 h1:QSWkTc+fu9LTAWfkZwZ6j8MSUk4A2LV7rbH0ZqmLjXs= -github.com/shirou/gopsutil/v4 v4.25.1/go.mod h1:RoUCUpndaJFtT+2zsZzzmhvbfGoDCJ7nFXKJf8GqJbI= +github.com/shirou/gopsutil/v4 v4.25.5 h1:rtd9piuSMGeU8g1RMXjZs9y9luK5BwtnG7dZaQUJAsc= +github.com/shirou/gopsutil/v4 v4.25.5/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= @@ -1147,8 +1158,8 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= +github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE= github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -1166,10 +1177,10 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.11.0 h1:ib4sjIrwZKxE5u/Japgo/7SJV3PvgjGiRNAvTVGqQl8= github.com/stretchr/testify v1.11.0/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/testcontainers/testcontainers-go v0.37.0 h1:L2Qc0vkTw2EHWQ08djon0D2uw7Z/PtHS/QzZZ5Ra/hg= -github.com/testcontainers/testcontainers-go v0.37.0/go.mod h1:QPzbxZhQ6Bclip9igjLFj6z0hs01bU8lrl2dHQmgFGM= -github.com/testcontainers/testcontainers-go/modules/localstack v0.37.0 h1:nPuxUYseqS0eYJg7KDJd95PhoMhdpTnSNtkDLwWFngo= -github.com/testcontainers/testcontainers-go/modules/localstack v0.37.0/go.mod h1:Mw+N4qqJ5iWbg45yWsdLzICfeCEwvYNudfAHHFqCU8Q= +github.com/testcontainers/testcontainers-go v0.38.0 h1:d7uEapLcv2P8AvH8ahLqDMMxda2W9gQN1nRbHS28HBw= +github.com/testcontainers/testcontainers-go v0.38.0/go.mod h1:C52c9MoHpWO+C4aqmgSU+hxlR5jlEayWtgYrb8Pzz1w= +github.com/testcontainers/testcontainers-go/modules/localstack v0.38.0 h1:3ljIy6FmHtFhZsZwsaMIj/27nCRm0La7N/dl5Jou8AA= +github.com/testcontainers/testcontainers-go/modules/localstack v0.38.0/go.mod h1:BTsbqWC9huPV8Jg8k46Jz4x1oRAA9XGxneuuOOIrtKY= github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4= github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0= github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4= @@ -1219,20 +1230,20 @@ go.opentelemetry.io/contrib/detectors/gcp v1.34.0 h1:JRxssobiPg23otYU5SbWtQC//sn go.opentelemetry.io/contrib/detectors/gcp v1.34.0/go.mod h1:cV4BMFcscUR/ckqLkbfQmF0PRsq8w/lMGzdbCSveBHo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ= -go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= -go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= +go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= +go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0 h1:WDdP9acbMYjbKIyJUhTvtzj601sVJOqgWdUxSdR/Ysc= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0/go.mod h1:BLbf7zbNIONBLPwvFnwNHGj4zge8uTCM/UPIVW1Mq2I= -go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= -go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= -go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= -go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= -go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= -go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= -go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= -go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE= +go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= +go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs= +go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= +go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis= +go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= +go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= +go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= @@ -1249,8 +1260,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= -golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= -golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1266,8 +1277,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= -golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= -golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= +golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 h1:bsqhLWFR6G6xiQcb+JoGqdKdRU6WzPWmK8E0jxTjzo4= +golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -1313,8 +1324,8 @@ golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= -golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1378,8 +1389,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= -golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= -golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1409,8 +1420,8 @@ golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= -golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= -golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1431,8 +1442,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= -golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1517,8 +1528,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1534,8 +1545,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= -golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1556,16 +1567,16 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= -golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= -golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= +golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1629,8 +1640,8 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= -golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +golang.org/x/tools v0.34.1-0.20250610205101-c26dd3ba555e h1:XnjOegqwH6kBJoae6InSGbIFPHcLtUT/Eq8HjrZKbmQ= +golang.org/x/tools v0.34.1-0.20250610205101-c26dd3ba555e/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1851,10 +1862,10 @@ google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOl google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb h1:ITgPrl429bc6+2ZraNSzMDk3I95nmQln2fuPstKwFDE= google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:sAo5UzpjUwgFBCzupwhcLcxHVDK7vG5IqI30YnwX2eE= -google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950= -google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 h1:iK2jbkWL86DXjEx0qiHcRE9dE4/Ahua5k6V8OWFb//c= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= +google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY= +google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1896,8 +1907,8 @@ google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5v google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= -google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8= +google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From 442072e2f4c0719d8826a6eedd0e6cd4d5ae26b5 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 29 Aug 2025 07:04:22 -0500 Subject: [PATCH 15/15] chore: remove all possible AsString panics (#183) Any call to `AsString` is unsafe. All places where the error is ignored is used in errors, so a placeholder or empty string is ok. A panic was observed by a customer. I am not sure where it occured. To be safe, I am using the function we have to protect these `AsString` calls. I added a custom linter to prevent these calls, this PR just removes all calls that were not fixed already. --- extract/parameter.go | 21 +++++++++++-- hclext/merge.go | 10 +++---- hclext/references.go | 7 ++++- init.go | 8 ++++- paramhook.go | 6 ++-- types/primitive.go | 70 -------------------------------------------- 6 files changed, 40 insertions(+), 82 deletions(-) delete mode 100644 types/primitive.go diff --git a/extract/parameter.go b/extract/parameter.go index d40a6cc..5516cba 100644 --- a/extract/parameter.go +++ b/extract/parameter.go @@ -267,6 +267,7 @@ func optionalStringEnum[T ~string](block *terraform.Block, key string, def T, va func requiredString(block *terraform.Block, key string) (string, *hcl.Diagnostic) { tyAttr := block.GetAttribute(key) tyVal := tyAttr.Value() + if tyVal.Type() != cty.String { typeName := "" if !tyVal.Type().Equals(cty.NilType) { @@ -282,7 +283,6 @@ func requiredString(block *terraform.Block, key string) (string, *hcl.Diagnostic if tyAttr.IsNotNil() { diag.Subject = &(tyAttr.HCLAttribute().Range) - // diag.Context = &(block.HCLBlock().DefRange) diag.Expression = tyAttr.HCLAttribute().Expr } @@ -297,8 +297,23 @@ func requiredString(block *terraform.Block, key string) (string, *hcl.Diagnostic return "", diag } - // nolint:gocritic // string type asserted - return tyVal.AsString(), nil + tyValStr, ok := hclext.AsString(tyVal) + if !ok { + // Either the val is unknown or null + diag := &hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: fmt.Sprintf("Invalid %q attribute for block %s", key, block.Label()), + Detail: "Expected a string, got an unknown or null value", + EvalContext: block.Context().Inner(), + } + + if tyAttr.IsNotNil() { + diag.Subject = &(tyAttr.HCLAttribute().Range) + diag.Expression = tyAttr.HCLAttribute().Expr + } + return "", diag + } + return tyValStr, nil } func optionalBoolean(block *terraform.Block, key string) bool { diff --git a/hclext/merge.go b/hclext/merge.go index caeb762..1c5974e 100644 --- a/hclext/merge.go +++ b/hclext/merge.go @@ -11,12 +11,12 @@ func MergeObjects(a, b cty.Value) cty.Value { output[key] = val } b.ForEachElement(func(key, val cty.Value) (stop bool) { - // TODO: Should this error be captured? - if key.Type() != cty.String { - return true - } //nolint:gocritic // string type asserted above - k := key.AsString() + k, ok := AsString(key) + if !ok { + // TODO: Should this error be captured? + return stop + } old := output[k] if old.IsKnown() && isNotEmptyObject(old) && isNotEmptyObject(val) { output[k] = MergeObjects(old, val) diff --git a/hclext/references.go b/hclext/references.go index ba23e3f..4e61e21 100644 --- a/hclext/references.go +++ b/hclext/references.go @@ -68,7 +68,12 @@ func CreateDotReferenceFromTraversal(traversals ...hcl.Traversal) string { switch { case part.Key.Type().Equals(cty.String): //nolint:gocritic // string type asserted above - refParts = append(refParts, fmt.Sprintf("[%s]", part.Key.AsString())) + stringName, ok := AsString(part.Key) + if !ok { + // Nothing we can do, just put a placeholder + stringName = "??" + } + refParts = append(refParts, fmt.Sprintf("[%s]", stringName)) case part.Key.Type().Equals(cty.Number): idx, _ := part.Key.AsBigFloat().Int64() refParts = append(refParts, fmt.Sprintf("[%d]", idx)) diff --git a/init.go b/init.go index 86eaaad..fdec618 100644 --- a/init.go +++ b/init.go @@ -5,6 +5,8 @@ import ( "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/function" "golang.org/x/xerrors" + + "github.com/coder/preview/hclext" ) // init intends to override some of the default functions afforded by terraform. @@ -27,7 +29,11 @@ func init() { Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { // This code is taken directly from https://github.com/mitchellh/go-homedir/blob/af06845cf3004701891bf4fdb884bfe4920b3727/homedir.go#L58 // The only change is that instead of expanding the path, we return an error - path := args[0].AsString() + path, ok := hclext.AsString(args[0]) + if !ok { + return cty.NilVal, xerrors.Errorf("invalid path argument") + } + if len(path) == 0 { return cty.StringVal(path), nil } diff --git a/paramhook.go b/paramhook.go index 0b8427f..d945750 100644 --- a/paramhook.go +++ b/paramhook.go @@ -39,8 +39,10 @@ func parameterContextsEvalHook(input Input) func(ctx *tfcontext.Context, blocks continue } - //nolint:gocritic // string type asserted - name := nameVal.AsString() + name, ok := hclext.AsString(nameVal) + if !ok { + continue + } var value cty.Value pv, ok := input.RichParameterValue(name) if ok { diff --git a/types/primitive.go b/types/primitive.go deleted file mode 100644 index 8f74317..0000000 --- a/types/primitive.go +++ /dev/null @@ -1,70 +0,0 @@ -package types - -import ( - "encoding/json" - "fmt" - - "github.com/zclconf/go-cty/cty" -) - -func CtyValueStringDefault(def string, val cty.Value) string { - str, err := CtyValueString(val) - if err != nil { - return def - } - return str -} - -// CtyValueString converts a cty.Value to a string. -// It supports only primitive types - bool, number, and string. -// As a special case, it also supports map[string]interface{} with key "value". -func CtyValueString(val cty.Value) (string, error) { - switch { - case val.Type().IsListType(): - vals := val.AsValueSlice() - strs := make([]string, 0, len(vals)) - for _, ele := range vals { - str, err := CtyValueString(ele) - if err != nil { - return "", err - } - strs = append(strs, str) - } - d, _ := json.Marshal(strs) - return string(d), nil - case val.Type().IsMapType(): - output := make(map[string]string) - for k, v := range val.AsValueMap() { - str, err := CtyValueString(v) - if err != nil { - return "", err - } - output[k] = str - } - - d, _ := json.Marshal(output) - return string(d), nil - } - - switch val.Type() { - case cty.Bool: - if val.True() { - return "true", nil - } - return "false", nil - case cty.Number: - return val.AsBigFloat().String(), nil - case cty.String: - //nolint:gocritic // string type asserted above - return val.AsString(), nil - // We may also have a map[string]interface{} with key "value". - case cty.Map(cty.String): - valval, ok := val.AsValueMap()["value"] - if !ok { - return "", fmt.Errorf("map does not have key 'value'") - } - return CtyValueString(valval) - default: - return "", fmt.Errorf("only primitive types are supported - bool, number, and string. Found %s", val.Type().GoString()) - } -}