From 3665091a9459a77c476b735e0a787c597f1c9cc3 Mon Sep 17 00:00:00 2001 From: Alberto Donato Date: Mon, 9 Dec 2024 09:37:00 +0100 Subject: [PATCH] feat: support passing terraform.workspace name --- gotfparse/cmd/tfparse/main.go | 4 +++- gotfparse/pkg/converter/converter.go | 5 +++++ gotfparse/pkg/converter/options.go | 8 ++++++++ tests/terraform/workspace/main.tf | 15 +++++++++++++++ tests/test_tfparse.py | 14 ++++++++++++++ tfparse/__init__.py | 14 ++++++++++---- tfparse/build_cffi.py | 2 +- 7 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 tests/terraform/workspace/main.tf diff --git a/gotfparse/cmd/tfparse/main.go b/gotfparse/cmd/tfparse/main.go index ea7f0e1..6df2b42 100644 --- a/gotfparse/cmd/tfparse/main.go +++ b/gotfparse/cmd/tfparse/main.go @@ -15,7 +15,7 @@ import ( ) //export Parse -func Parse(a *C.char, stopHCL C.int, debug C.int, allowDownloads C.int, num_vars_files C.int, vars_files **C.char) (resp C.parseResponse) { +func Parse(a *C.char, stopHCL C.int, debug C.int, allowDownloads C.int, workspaceName *C.char, num_vars_files C.int, vars_files **C.char) (resp C.parseResponse) { input := C.GoString(a) options := []converter.TerraformConverterOption{} @@ -33,6 +33,8 @@ func Parse(a *C.char, stopHCL C.int, debug C.int, allowDownloads C.int, num_vars options = append(options, converter.WithAllowDownloads(false)) } + options = append(options, converter.WithWorkspaceName(C.GoString(workspaceName))) + var varFiles []string for _, v := range unsafe.Slice(vars_files, num_vars_files) { varFiles = append(varFiles, C.GoString(v)) diff --git a/gotfparse/pkg/converter/converter.go b/gotfparse/pkg/converter/converter.go index dcabeb1..420fb03 100644 --- a/gotfparse/pkg/converter/converter.go +++ b/gotfparse/pkg/converter/converter.go @@ -403,6 +403,11 @@ func (t *terraformConverter) SetTFVarsPaths(paths ...string) { t.parserOptions = append(t.parserOptions, parser.OptionWithTFVarsPaths(paths...)) } +// SetWorkspaceName is a TerraformConverter option that sets the value for the workspace name. +func (t *terraformConverter) SetWorkspaceName(workspace string) { + t.parserOptions = append(t.parserOptions, parser.OptionWithWorkspaceName(workspace)) +} + func getModuleName(b *terraform.Block) string { // This field is unexported, but necessary to generate the path of the // module. Hopefully aquasecurity/defsec exports this in a future release. diff --git a/gotfparse/pkg/converter/options.go b/gotfparse/pkg/converter/options.go index 18e822f..e9009bd 100644 --- a/gotfparse/pkg/converter/options.go +++ b/gotfparse/pkg/converter/options.go @@ -7,6 +7,7 @@ type TerraformConverterOptions interface { SetStopOnHCLError() SetAllowDownloads(allowed bool) SetTFVarsPaths(paths ...string) + SetWorkspaceName(workspace string) } type TerraformConverterOption func(t TerraformConverterOptions) @@ -38,3 +39,10 @@ func WithTFVarsPaths(paths ...string) TerraformConverterOption { t.SetTFVarsPaths(paths...) } } + +// WithWorkspaceName sets the Terraform workspace name. +func WithWorkspaceName(workspace string) TerraformConverterOption { + return func(t TerraformConverterOptions) { + t.SetWorkspaceName(workspace) + } +} diff --git a/tests/terraform/workspace/main.tf b/tests/terraform/workspace/main.tf new file mode 100644 index 0000000..1c1cf7a --- /dev/null +++ b/tests/terraform/workspace/main.tf @@ -0,0 +1,15 @@ +locals { + map = { + default = "DEFAULT" + other = "OTHER" + } + value = local.map[terraform.workspace] +} + +output "workspace" { + value = terraform.workspace +} + +output "value" { + value = local.value +} diff --git a/tests/test_tfparse.py b/tests/test_tfparse.py index 7eff9e1..8a1d8f2 100644 --- a/tests/test_tfparse.py +++ b/tests/test_tfparse.py @@ -532,3 +532,17 @@ def test_funcs(tmp_path): "modules_list": ["x", "y", "z"], } assert len(actual["check_fileset_abs_path"]) > 0 + + +def test_workspace(tmp_path): + mod_path = init_module("workspace", tmp_path) + + parsed = load_from_path(mod_path) + value, workspace = parsed["output"] + assert workspace["value"] == "default" + assert value["value"] == "DEFAULT" + + parsed = load_from_path(mod_path, workspace_name="other") + value, workspace = parsed["output"] + assert workspace["value"] == "other" + assert value["value"] == "OTHER" diff --git a/tfparse/__init__.py b/tfparse/__init__.py index f711554..3bd4c34 100644 --- a/tfparse/__init__.py +++ b/tfparse/__init__.py @@ -28,14 +28,14 @@ def load_from_path( stop_on_hcl_error: bool = False, debug: bool = False, allow_downloads: bool = False, + workspace_name: str = "default", vars_paths=None, # list[str] ) -> tp.Dict: if not isinstance(filePath, (str, Path)): raise ValueError("filePath must be str or Path, got %s" % type(filePath)) - filePath = str(filePath).encode("utf8") - - s = ffi.new("char[]", filePath) + path = ffi.new("char[]", str(filePath).encode("utf8")) + workspace = ffi.new("char[]", str(workspace_name).encode("utf8")) vars_paths = vars_paths or [] num_var_paths = len(vars_paths) @@ -44,7 +44,13 @@ def load_from_path( ] ret = lib.Parse( - s, stop_on_hcl_error, debug, allow_downloads, num_var_paths, c_var_paths + path, + stop_on_hcl_error, + debug, + allow_downloads, + workspace, + num_var_paths, + c_var_paths, ) if ret.err != ffi.NULL: diff --git a/tfparse/build_cffi.py b/tfparse/build_cffi.py index 20f7a77..b1bf32c 100644 --- a/tfparse/build_cffi.py +++ b/tfparse/build_cffi.py @@ -19,7 +19,7 @@ char *err; } parseResponse; - parseResponse Parse(char* a, int stop_on_error, int debug, int allow_downloads, int num_vars_files, char** vars_files); + parseResponse Parse(char* a, int stop_on_error, int debug, int allow_downloads, char* workspace_name, int num_vars_files, char** vars_files); void free(void *ptr); """ # noqa )