diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 87f39dc..6c0f476 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -98,12 +98,23 @@ jobs: matrix: # list whatever Terraform versions here you would like to support terraform: - - '1.8.*' - - '1.9.*' - - '1.10.*' - - '1.11.*' - - '1.12.*' + # the latest patch of each version will be used + - '1.5.0' + - '1.6.0' + - '1.7.0' + - '1.8.0' + - '1.9.0' + - '1.10.0' + - '1.11.0' + - '1.12.0' + - '1.13.0' steps: + - name: install-nix + run: | + curl -L https://nixos.org/nix/install | sh + source /home/runner/.nix-profile/etc/profile.d/nix.sh + nix --version + which nix - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 https://github.com/actions/checkout - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 https://github.com/actions/setup-go with: @@ -113,9 +124,12 @@ jobs: with: terraform_version: ${{ matrix.terraform }} terraform_wrapper: false - - run: go mod download - - run: go install gotest.tools/gotestsum@ddd0b05a6878e2e8257a2abe6e7df66cebc53d0e # v1.12.3 - - run: make test - - run: terraform fmt -check -recursive - - run: pushd ./examples/use-cases/basic; terraform init -input=false; popd - - run: pushd ./examples/use-cases/basic; terraform validate -no-color; popd + - name: run tests + shell: /home/runner/.nix-profile/bin/nix develop --ignore-environment --extra-experimental-features nix-command --extra-experimental-features flakes --keep HOME --keep NIX_SSL_CERT_FILE --keep NIX_ENV_LOADED --keep TERM --command bash -e {0} + run: | + go mod download + go install gotest.tools/gotestsum@ddd0b05a6878e2e8257a2abe6e7df66cebc53d0e # v1.12.3 + terraform fmt -check -recursive + tfswitch -s ${{ matrix.terraform }} + make test + make testacc diff --git a/.golangci.yml b/.golangci.yml index 8519993..87a0b1a 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,4 +1,4 @@ -# Copyright (c) HashiCorp, Inc. + version: "2" linters: diff --git a/.goreleaser.yml b/.goreleaser.yml index 80a3b6f..4468012 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,4 +1,4 @@ -# Copyright (c) HashiCorp, Inc. + # https://goreleaser.com for documentation diff --git a/GNUmakefile b/GNUmakefile index 075cdb8..887725d 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -20,14 +20,12 @@ test: testacc: build export REPO_ROOT="../../../."; \ - export TF_CLI_CONFIG_FILE="../../../test/.terraformrc"; \ pushd ./test; \ gotestsum --format standard-verbose --jsonfile report.json --post-run-command "./summarize.sh" -- ./... -v -p=1 -timeout=300s; \ popd; debug: build export REPO_ROOT="../../../."; \ - export TF_CLI_CONFIG_FILE="../../../test/.terraformrc"; \ export TF_LOG=DEBUG; \ pushd ./test; \ gotestsum --format standard-verbose --jsonfile report.json --post-run-command "./summarize.sh" -- ./... -v -p=1 -timeout=300s; \ diff --git a/docs/data-sources/local.md b/docs/data-sources/local.md new file mode 100644 index 0000000..eea207f --- /dev/null +++ b/docs/data-sources/local.md @@ -0,0 +1,39 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "file_local Data Source - file" +subcategory: "" +description: |- + Local File DataSource +--- + +# file_local (Data Source) + +Local File DataSource + +## Example Usage + +```terraform +# tflint-ignore: terraform_unused_declarations +data "file_local" "basic_example" { + name = "example.txt" + directory = "." +} +``` + + +## Schema + +### Required + +- `directory` (String) The directory where the file exists. +- `name` (String) File name, required. + +### Optional + +- `hmac_secret_key` (String, Sensitive) A string used to generate the file identifier, you can pass this value in the environment variable `TF_FILE_HMAC_SECRET_KEY`. + +### Read-Only + +- `contents` (String) The file contents. +- `id` (String) Identifier derived from sha256+HMAC hash of file contents. +- `permissions` (String) The file permissions. diff --git a/docs/index.md b/docs/index.md index 351daac..29f4d04 100644 --- a/docs/index.md +++ b/docs/index.md @@ -12,8 +12,6 @@ description: |- ## Example Usage ```terraform -# Copyright (c) HashiCorp, Inc. - # this provider has no configuration currently provider "file" {} ``` diff --git a/docs/resources/local.md b/docs/resources/local.md index dca1f4a..88c2f04 100644 --- a/docs/resources/local.md +++ b/docs/resources/local.md @@ -13,8 +13,6 @@ Local File resource ## Example Usage ```terraform -# Copyright (c) HashiCorp, Inc. - resource "file_local" "basic_example" { name = "example.txt" contents = "An example implementation writing a local file." @@ -59,8 +57,6 @@ Import is supported using the following syntax: The [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import) can be used, for example: ```shell -# Copyright (c) HashiCorp, Inc. - # echo "Test data" > data.txt # FILEPATH="./data.txt" # TF_FILE_HMAC_SECRET_KEY="super-secret-key" diff --git a/examples/data-sources/file_local/data-source.example b/examples/data-sources/file_local/data-source.example deleted file mode 100644 index 6643d2f..0000000 --- a/examples/data-sources/file_local/data-source.example +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) HashiCorp, Inc. - - -data "file_local" "example" { - configurable_attribute = "some-value" -} diff --git a/examples/data-sources/file_local/data-source.tf b/examples/data-sources/file_local/data-source.tf new file mode 100644 index 0000000..0f62801 --- /dev/null +++ b/examples/data-sources/file_local/data-source.tf @@ -0,0 +1,6 @@ + +# tflint-ignore: terraform_unused_declarations +data "file_local" "basic_example" { + name = "example.txt" + directory = "." +} diff --git a/examples/use-cases/protected/versions.tf b/examples/data-sources/file_local/versions.tf similarity index 82% rename from examples/use-cases/protected/versions.tf rename to examples/data-sources/file_local/versions.tf index a961537..2b7ea2e 100644 --- a/examples/use-cases/protected/versions.tf +++ b/examples/data-sources/file_local/versions.tf @@ -1,4 +1,4 @@ -# Copyright (c) HashiCorp, Inc. + terraform { required_version = ">= 1.5.0" diff --git a/examples/provider/provider.tf b/examples/provider/provider.tf index 248b599..172af9d 100644 --- a/examples/provider/provider.tf +++ b/examples/provider/provider.tf @@ -1,4 +1,4 @@ -# Copyright (c) HashiCorp, Inc. + # this provider has no configuration currently provider "file" {} diff --git a/examples/provider/versions.tf b/examples/provider/versions.tf index a961537..2b7ea2e 100644 --- a/examples/provider/versions.tf +++ b/examples/provider/versions.tf @@ -1,4 +1,4 @@ -# Copyright (c) HashiCorp, Inc. + terraform { required_version = ">= 1.5.0" diff --git a/examples/resources/file_local/import.sh b/examples/resources/file_local/import.sh index e477492..7ffdf15 100644 --- a/examples/resources/file_local/import.sh +++ b/examples/resources/file_local/import.sh @@ -1,4 +1,4 @@ -# Copyright (c) HashiCorp, Inc. + # echo "Test data" > data.txt # FILEPATH="./data.txt" diff --git a/examples/resources/file_local/resource.tf b/examples/resources/file_local/resource.tf index 4db3ef3..2b5ebc1 100644 --- a/examples/resources/file_local/resource.tf +++ b/examples/resources/file_local/resource.tf @@ -1,4 +1,4 @@ -# Copyright (c) HashiCorp, Inc. + resource "file_local" "basic_example" { name = "example.txt" diff --git a/examples/resources/file_local/versions.tf b/examples/resources/file_local/versions.tf index a961537..2b7ea2e 100644 --- a/examples/resources/file_local/versions.tf +++ b/examples/resources/file_local/versions.tf @@ -1,4 +1,4 @@ -# Copyright (c) HashiCorp, Inc. + terraform { required_version = ">= 1.5.0" diff --git a/examples/use-cases/protected/.terraformrc b/examples/use-cases/local/basic/.terraformrc similarity index 67% rename from examples/use-cases/protected/.terraformrc rename to examples/use-cases/local/basic/.terraformrc index dcdcbfe..cf3b6ac 100644 --- a/examples/use-cases/protected/.terraformrc +++ b/examples/use-cases/local/basic/.terraformrc @@ -1,6 +1,6 @@ provider_installation { dev_overrides { - "rancher/file" = "../../../bin" + "rancher/file" = "../../../../bin" } direct { exclude = [] diff --git a/examples/use-cases/basic/README.md b/examples/use-cases/local/basic/README.md similarity index 100% rename from examples/use-cases/basic/README.md rename to examples/use-cases/local/basic/README.md diff --git a/examples/use-cases/protected/backend.tf b/examples/use-cases/local/basic/backend.tf similarity index 53% rename from examples/use-cases/protected/backend.tf rename to examples/use-cases/local/basic/backend.tf index ec34186..066af9b 100644 --- a/examples/use-cases/protected/backend.tf +++ b/examples/use-cases/local/basic/backend.tf @@ -1,4 +1,4 @@ -# Copyright (c) HashiCorp, Inc. + terraform { diff --git a/examples/use-cases/basic/main.tf b/examples/use-cases/local/basic/main.tf similarity index 75% rename from examples/use-cases/basic/main.tf rename to examples/use-cases/local/basic/main.tf index 220a81a..c81c291 100644 --- a/examples/use-cases/basic/main.tf +++ b/examples/use-cases/local/basic/main.tf @@ -1,4 +1,4 @@ -# Copyright (c) HashiCorp, Inc. + provider "file" {} @@ -12,3 +12,8 @@ resource "file_local" "basic" { directory = local.directory contents = "An example of the \"most basic\" implementation writing a local file." } + +data "file_local" "basic" { + name = file_local.basic.name + directory = file_local.basic.directory +} diff --git a/examples/use-cases/local/basic/outputs.tf b/examples/use-cases/local/basic/outputs.tf new file mode 100644 index 0000000..9a855b4 --- /dev/null +++ b/examples/use-cases/local/basic/outputs.tf @@ -0,0 +1,11 @@ + + +output "file_resource" { + value = jsonencode(file_local.basic) + sensitive = true +} + +output "file_data_source" { + value = jsonencode(data.file_local.basic) + sensitive = true +} diff --git a/examples/use-cases/basic/variables.tf b/examples/use-cases/local/basic/variables.tf similarity index 80% rename from examples/use-cases/basic/variables.tf rename to examples/use-cases/local/basic/variables.tf index 81bd628..2fb50f1 100644 --- a/examples/use-cases/basic/variables.tf +++ b/examples/use-cases/local/basic/variables.tf @@ -1,4 +1,4 @@ -# Copyright (c) HashiCorp, Inc. + variable "directory" { type = string diff --git a/examples/use-cases/basic/versions.tf b/examples/use-cases/local/basic/versions.tf similarity index 82% rename from examples/use-cases/basic/versions.tf rename to examples/use-cases/local/basic/versions.tf index a961537..2b7ea2e 100644 --- a/examples/use-cases/basic/versions.tf +++ b/examples/use-cases/local/basic/versions.tf @@ -1,4 +1,4 @@ -# Copyright (c) HashiCorp, Inc. + terraform { required_version = ">= 1.5.0" diff --git a/examples/use-cases/basic/.terraformrc b/examples/use-cases/local/protected/.terraformrc similarity index 67% rename from examples/use-cases/basic/.terraformrc rename to examples/use-cases/local/protected/.terraformrc index dcdcbfe..cf3b6ac 100644 --- a/examples/use-cases/basic/.terraformrc +++ b/examples/use-cases/local/protected/.terraformrc @@ -1,6 +1,6 @@ provider_installation { dev_overrides { - "rancher/file" = "../../../bin" + "rancher/file" = "../../../../bin" } direct { exclude = [] diff --git a/examples/use-cases/protected/README.md b/examples/use-cases/local/protected/README.md similarity index 100% rename from examples/use-cases/protected/README.md rename to examples/use-cases/local/protected/README.md diff --git a/examples/use-cases/basic/backend.tf b/examples/use-cases/local/protected/backend.tf similarity index 53% rename from examples/use-cases/basic/backend.tf rename to examples/use-cases/local/protected/backend.tf index ec34186..066af9b 100644 --- a/examples/use-cases/basic/backend.tf +++ b/examples/use-cases/local/protected/backend.tf @@ -1,4 +1,4 @@ -# Copyright (c) HashiCorp, Inc. + terraform { diff --git a/examples/use-cases/protected/main.tf b/examples/use-cases/local/protected/main.tf similarity index 90% rename from examples/use-cases/protected/main.tf rename to examples/use-cases/local/protected/main.tf index 1732249..82bcb50 100644 --- a/examples/use-cases/protected/main.tf +++ b/examples/use-cases/local/protected/main.tf @@ -1,4 +1,4 @@ -# Copyright (c) HashiCorp, Inc. + provider "file" {} @@ -26,3 +26,8 @@ resource "file_local" "protected_env" { directory = local.directory contents = "An example implementation of a protected file." } + +data "file_local" "protected" { + name = file_local.protected.name + directory = file_local.protected.directory +} diff --git a/examples/use-cases/local/protected/outputs.tf b/examples/use-cases/local/protected/outputs.tf new file mode 100644 index 0000000..9731f49 --- /dev/null +++ b/examples/use-cases/local/protected/outputs.tf @@ -0,0 +1,16 @@ + + +output "file_resource" { + value = jsonencode(file_local.protected) + sensitive = true +} + +output "file_resource_env" { + value = jsonencode(file_local.protected_env) + sensitive = true +} + +output "file_data_source" { + value = jsonencode(data.file_local.protected) + sensitive = true +} diff --git a/examples/use-cases/protected/variables.tf b/examples/use-cases/local/protected/variables.tf similarity index 81% rename from examples/use-cases/protected/variables.tf rename to examples/use-cases/local/protected/variables.tf index 11c6933..8f5bc20 100644 --- a/examples/use-cases/protected/variables.tf +++ b/examples/use-cases/local/protected/variables.tf @@ -1,4 +1,4 @@ -# Copyright (c) HashiCorp, Inc. + variable "directory" { type = string diff --git a/examples/use-cases/local/protected/versions.tf b/examples/use-cases/local/protected/versions.tf new file mode 100644 index 0000000..2b7ea2e --- /dev/null +++ b/examples/use-cases/local/protected/versions.tf @@ -0,0 +1,11 @@ + + +terraform { + required_version = ">= 1.5.0" + required_providers { + file = { + source = "rancher/file" + version = ">= 0.0.1" + } + } +} diff --git a/flake.lock b/flake.lock index ab045cb..687bd22 100644 --- a/flake.lock +++ b/flake.lock @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1756128520, - "narHash": "sha256-R94HxJBi+RK1iCm8Y4Q9pdrHZl0GZoDPIaYwjxRNPh4=", + "lastModified": 1756819007, + "narHash": "sha256-12V64nKG/O/guxSYnr5/nq1EfqwJCdD2+cIGmhz3nrE=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "c53baa6685261e5253a1c355a1b322f82674a824", + "rev": "aaff8c16d7fc04991cac6245bee1baa31f72b1e1", "type": "github" }, "original": { diff --git a/internal/provider/data_source.example b/internal/provider/data_source.example deleted file mode 100644 index 585b9d2..0000000 --- a/internal/provider/data_source.example +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package provider - -import ( - "context" - "fmt" - "net/http" - - "github.com/hashicorp/terraform-plugin-framework/datasource" - "github.com/hashicorp/terraform-plugin-framework/datasource/schema" - "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-log/tflog" -) - -// Ensure provider defined types fully satisfy framework interfaces. -var _ datasource.DataSource = &ExampleDataSource{} - -func NewExampleDataSource() datasource.DataSource { - return &ExampleDataSource{} -} - -// ExampleDataSource defines the data source implementation. -type ExampleDataSource struct { - client *http.Client -} - -// ExampleDataSourceModel describes the data source data model. -type ExampleDataSourceModel struct { - ConfigurableAttribute types.String `tfsdk:"configurable_attribute"` - Id types.String `tfsdk:"id"` -} - -func (d *ExampleDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_example" -} - -func (d *ExampleDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { - resp.Schema = schema.Schema{ - // This description is used by the documentation generator and the language server. - MarkdownDescription: "Example data source", - - Attributes: map[string]schema.Attribute{ - "configurable_attribute": schema.StringAttribute{ - MarkdownDescription: "Example configurable attribute", - Optional: true, - }, - "id": schema.StringAttribute{ - MarkdownDescription: "Example identifier", - Computed: true, - }, - }, - } -} - -func (d *ExampleDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { - // Prevent panic if the provider has not been configured. - if req.ProviderData == nil { - return - } - - client, ok := req.ProviderData.(*http.Client) - - if !ok { - resp.Diagnostics.AddError( - "Unexpected Data Source Configure Type", - fmt.Sprintf("Expected *http.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), - ) - - return - } - - d.client = client -} - -func (d *ExampleDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var data ExampleDataSourceModel - - // Read Terraform configuration data into the model - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - - if resp.Diagnostics.HasError() { - return - } - - // If applicable, this is a great opportunity to initialize any necessary - // provider client data and make a call using it. - // httpResp, err := d.client.Do(httpReq) - // if err != nil { - // resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read example, got error: %s", err)) - // return - // } - - // For the purposes of this example code, hardcoding a response value to - // save into the Terraform state. - data.Id = types.StringValue("example-id") - - // Write logs using the tflog package - // Documentation: https://terraform.io/plugin/log - tflog.Trace(ctx, "read a data source") - - // Save data into Terraform state - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) -} diff --git a/internal/provider/data_source_test.example b/internal/provider/data_source_test.example deleted file mode 100644 index e53f5c4..0000000 --- a/internal/provider/data_source_test.example +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package provider - -import ( - "testing" - - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/knownvalue" - "github.com/hashicorp/terraform-plugin-testing/statecheck" - "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" -) - -func TestAccExampleDataSource(t *testing.T) { - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, - Steps: []resource.TestStep{ - // Read testing - { - Config: testAccExampleDataSourceConfig, - ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectKnownValue( - "data.file_example.test", - tfjsonpath.New("id"), - knownvalue.StringExact("example-id"), - ), - }, - }, - }, - }) -} - -const testAccExampleDataSourceConfig = ` -data "file_example" "test" { - configurable_attribute = "example" -} -` diff --git a/internal/provider/local/file_local_data_source.go b/internal/provider/local/file_local_data_source.go new file mode 100644 index 0000000..524283b --- /dev/null +++ b/internal/provider/local/file_local_data_source.go @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: MPL-2.0 + +package local + +import ( + "context" + "fmt" + "os" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" +) + +// The `var _` is a special Go construct that results in an unusable variable. +// The purpose of these lines is to make sure our LocalFileResource correctly implements the `resource.Resourceā€œ interface. +// These will fail at compilation time if the implementation is not satisfied. +var _ datasource.DataSource = &LocalDataSource{} + +func NewLocalDataSource() datasource.DataSource { + return &LocalDataSource{} +} + +type LocalDataSource struct { + client fileClient +} + +type LocalDataSourceModel struct { + Id types.String `tfsdk:"id"` + Name types.String `tfsdk:"name"` + Directory types.String `tfsdk:"directory"` + Contents types.String `tfsdk:"contents"` + Permissions types.String `tfsdk:"permissions"` + HmacSecretKey types.String `tfsdk:"hmac_secret_key"` +} + +func (r *LocalDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_local" // file_local datasource +} + +func (r *LocalDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + MarkdownDescription: "Local File DataSource", + + Attributes: map[string]schema.Attribute{ + "name": schema.StringAttribute{ + MarkdownDescription: "File name, required.", + Required: true, + }, + "directory": schema.StringAttribute{ + MarkdownDescription: "The directory where the file exists.", + Required: true, + }, + "hmac_secret_key": schema.StringAttribute{ + MarkdownDescription: "A string used to generate the file identifier, " + + "you can pass this value in the environment variable `TF_FILE_HMAC_SECRET_KEY`. ", + Optional: true, + Computed: true, + Sensitive: true, + }, + "contents": schema.StringAttribute{ + MarkdownDescription: "The file contents.", + Computed: true, + }, + "permissions": schema.StringAttribute{ + MarkdownDescription: "The file permissions.", + Computed: true, + }, + "id": schema.StringAttribute{ + MarkdownDescription: "Identifier derived from sha256+HMAC hash of file contents. ", + Computed: true, + }, + }, + } +} + +func (r *LocalDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } +} + +// Read runs before all other resources are run, datasources only get the Read function. +func (r *LocalDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + tflog.Debug(ctx, fmt.Sprintf("Request Object: %#v", req)) + + // Allow the ability to inject a file client, but use the osFileClient by default. + if r.client == nil { + tflog.Debug(ctx, "Configuring client with default osFileClient.") + r.client = &osFileClient{} + } + + var config LocalDataSourceModel + resp.Diagnostics.Append(req.Config.Get(ctx, &config)...) + if resp.Diagnostics.HasError() { + return + } + + cName := config.Name.ValueString() + cDirectory := config.Directory.ValueString() + cPerm := config.Permissions.ValueString() + cHmacSecretKey := config.HmacSecretKey.ValueString() + + cKey := cHmacSecretKey + if cKey == "" { + tflog.Debug(ctx, "Checking for secret key in environment variable TF_FILE_HMAC_SECRET_KEY.") + cKey = os.Getenv("TF_FILE_HMAC_SECRET_KEY") + } + + if cKey == "" { + tflog.Debug(ctx, "Key not found, attempting to use constant.") + cKey = unprotectedHmacSecret // this is a constant defined in file_local_resource.go + } + + perm, contents, err := r.client.Read(cDirectory, cName) + if err != nil && err.Error() == "File not found." { + resp.State.RemoveResource(ctx) + return + } + if err != nil { + resp.Diagnostics.AddError("Error reading file: ", err.Error()) + return + } + + // update state with actual contents + config.Contents = types.StringValue(contents) + id, err := calculateId(contents, cKey) + if err != nil { + resp.Diagnostics.AddError("Error reading file: ", "Problem calculating id from key: "+err.Error()) + return + } + config.Id = types.StringValue(id) + + if perm != cPerm { + // update the state with the actual mode + config.Permissions = types.StringValue(perm) + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &config)...) + tflog.Debug(ctx, fmt.Sprintf("Response Object: %#v", *resp)) +} diff --git a/internal/provider/local/file_local_data_source_test.go b/internal/provider/local/file_local_data_source_test.go new file mode 100644 index 0000000..36e7196 --- /dev/null +++ b/internal/provider/local/file_local_data_source_test.go @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: MPL-2.0 + +package local + +import ( + "context" + "slices" + "strconv" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" + "github.com/hashicorp/terraform-plugin-go/tftypes" +) + +func TestLocalDataSourceMetadata(t *testing.T) { + t.Run("Metadata function", func(t *testing.T) { + testCases := []struct { + name string + fit LocalDataSource + want datasource.MetadataResponse + }{ + {"Basic test", LocalDataSource{}, datasource.MetadataResponse{TypeName: "file_local"}}, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + res := datasource.MetadataResponse{} + tc.fit.Metadata(context.Background(), datasource.MetadataRequest{ProviderTypeName: "file"}, &res) + got := res + if got != tc.want { + t.Errorf("%#v.Metadata() is %v; want %v", tc.fit, got, tc.want) + } + }) + } + }) +} + +func TestLocalDataSourceRead(t *testing.T) { + t.Run("Read function", func(t *testing.T) { + testCases := []struct { + name string + fit LocalDataSource + have datasource.ReadRequest + want datasource.ReadResponse + setup map[string]string + }{ + { + "Unprotected", + LocalDataSource{client: &memoryFileClient{}}, + // have + getDataSourceReadRequest(t, map[string]string{ + "id": "60cef95046105ff4522c0c1f1aeeeba43d0d729dbcabdd8846c317c98cac60a2", + "name": "read.tmp", + "directory": defaultDirectory, + "permissions": defaultPerm, + "contents": "this is an unprotected read test", + "hmac_secret_key": defaultHmacSecretKey, + }), + // want + getDataSourceReadResponse(t, map[string]string{ + "id": "60cef95046105ff4522c0c1f1aeeeba43d0d729dbcabdd8846c317c98cac60a2", + "name": "read.tmp", + "directory": defaultDirectory, + "permissions": defaultPerm, + "contents": "this is an unprotected read test", + "hmac_secret_key": defaultHmacSecretKey, + }), + map[string]string{ + "mode": defaultPerm, + "directory": defaultDirectory, + "name": "read.tmp", + "contents": "this is an unprotected read test", + }, + }, + { + "Protected", + LocalDataSource{client: &memoryFileClient{}}, + // have + getDataSourceReadRequest(t, map[string]string{ + "id": "ec4407ba53b2c40ac2ac18ff7372a6fe6e4f7f8aa04f340503aefc7d9a5fa4e1", + "name": "read_protected.tmp", + "directory": defaultDirectory, + "permissions": defaultPerm, + "contents": "this is a protected read test", + "hmac_secret_key": "this-is-a-test-key", + }), + // want + getDataSourceReadResponse(t, map[string]string{ + "id": "ec4407ba53b2c40ac2ac18ff7372a6fe6e4f7f8aa04f340503aefc7d9a5fa4e1", + "name": "read_protected.tmp", + "directory": defaultDirectory, + "permissions": defaultPerm, + "contents": "this is a protected read test", + "hmac_secret_key": "this-is-a-test-key", + }), + // reality + map[string]string{ + "mode": defaultPerm, + "directory": defaultDirectory, + "name": "read_protected.tmp", + "contents": "this is a protected read test", + }, + }, + { + "Protected with content update", + LocalDataSource{client: &memoryFileClient{}}, + // have + getDataSourceReadRequest(t, map[string]string{ + "id": "ec4407ba53b2c40ac2ac18ff7372a6fe6e4f7f8aa04f340503aefc7d9a5fa4e1", + "name": "read_protected_content.tmp", + "directory": defaultDirectory, + "permissions": defaultPerm, + "contents": "this is a protected read test", + "hmac_secret_key": "this-is-a-test-key", + }), + // want + getDataSourceReadResponse(t, map[string]string{ + "id": "84326116e261654e44ca3cb73fa026580853794062d472bc817b7ec2c82ff648", + "name": "read_protected_content.tmp", + "directory": defaultDirectory, + "permissions": defaultPerm, + "contents": "this is a change in contents in the real file", + "hmac_secret_key": "this-is-a-test-key", + }), + // reality + map[string]string{ + "mode": defaultPerm, + "directory": defaultDirectory, + "name": "read_protected_content.tmp", + "contents": "this is a change in contents in the real file", + }, + }, + { + "Protected with mode update", + LocalDataSource{client: &memoryFileClient{}}, + // have + getDataSourceReadRequest(t, map[string]string{ + "id": "ec4407ba53b2c40ac2ac18ff7372a6fe6e4f7f8aa04f340503aefc7d9a5fa4e1", + "name": "read_protected_mode.tmp", + "directory": defaultDirectory, + "permissions": defaultPerm, + "contents": "this is a protected read test", + "hmac_secret_key": "this-is-a-test-key", + }), + // want + getDataSourceReadResponse(t, map[string]string{ + "id": "ec4407ba53b2c40ac2ac18ff7372a6fe6e4f7f8aa04f340503aefc7d9a5fa4e1", + "name": "read_protected_mode.tmp", + "directory": defaultDirectory, + "permissions": "0755", + "contents": "this is a protected read test", + "hmac_secret_key": "this-is-a-test-key", + }), + // reality + map[string]string{ + "mode": "0755", + "directory": defaultDirectory, + "name": "read_protected_mode.tmp", + "contents": "this is a protected read test", + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + if err := tc.fit.client.Create(tc.setup["directory"], tc.setup["name"], tc.setup["contents"], tc.setup["mode"]); err != nil { + t.Errorf("Error setting up: %v", err) + } + defer func() { + if err := tc.fit.client.Delete(tc.setup["directory"], tc.setup["name"]); err != nil { + t.Errorf("Error tearing down: %v", err) + } + }() + r := getDataSourceReadResponseContainer() + tc.fit.Read(context.Background(), tc.have, &r) + got := r + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Errorf("Read() mismatch (-want +got):\n%s", diff) + } + }) + } + }) +} + +// *** Test Helper Functions *** // + +func getDataSourceReadRequest(t *testing.T, data map[string]string) datasource.ReadRequest { + stateMap := make(map[string]tftypes.Value) + for key, value := range data { + if slices.Contains(booleanFields, key) { // booleanFields is a constant + v, err := strconv.ParseBool(value) + if err != nil { + t.Errorf("Error converting %s to bool %s: ", value, err.Error()) + } + stateMap[key] = tftypes.NewValue(tftypes.Bool, v) + } else { + stateMap[key] = tftypes.NewValue(tftypes.String, value) + } + } + stateValue := tftypes.NewValue(getDataSourceObjectAttributeTypes(), stateMap) + return datasource.ReadRequest{ + Config: tfsdk.Config{ + Raw: stateValue, + Schema: getLocalDataSourceSchema().Schema, + }, + } +} + +func getDataSourceReadResponseContainer() datasource.ReadResponse { + return datasource.ReadResponse{ + State: tfsdk.State{Schema: getLocalDataSourceSchema().Schema}, + } +} + +func getDataSourceReadResponse(t *testing.T, data map[string]string) datasource.ReadResponse { + stateMap := make(map[string]tftypes.Value) + for key, value := range data { + if slices.Contains(booleanFields, key) { // booleanFields is a constant + v, err := strconv.ParseBool(value) + if err != nil { + t.Errorf("Error converting %s to bool %s: ", value, err.Error()) + } + stateMap[key] = tftypes.NewValue(tftypes.Bool, v) + } else { + stateMap[key] = tftypes.NewValue(tftypes.String, value) + } + } + stateValue := tftypes.NewValue(getDataSourceObjectAttributeTypes(), stateMap) + return datasource.ReadResponse{ + State: tfsdk.State{ + Raw: stateValue, + Schema: getLocalDataSourceSchema().Schema, + }, + } +} + +func getDataSourceObjectAttributeTypes() tftypes.Object { + return tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + "name": tftypes.String, + "directory": tftypes.String, + "permissions": tftypes.String, + "contents": tftypes.String, + "hmac_secret_key": tftypes.String, + }, + } +} + +func getLocalDataSourceSchema() *datasource.SchemaResponse { + var testResource LocalDataSource + r := &datasource.SchemaResponse{} + testResource.Schema(context.Background(), datasource.SchemaRequest{}, r) + return r +} diff --git a/internal/provider/file_local_resource.go b/internal/provider/local/file_local_resource.go similarity index 90% rename from internal/provider/file_local_resource.go rename to internal/provider/local/file_local_resource.go index 9a56b62..8ec95d3 100644 --- a/internal/provider/file_local_resource.go +++ b/internal/provider/local/file_local_resource.go @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MPL-2.0 -package provider +package local import ( "context" @@ -10,8 +10,6 @@ import ( "fmt" "io" "os" - "path/filepath" - "strconv" "strings" "github.com/hashicorp/terraform-plugin-framework-validators/boolvalidator" @@ -34,6 +32,8 @@ import ( var _ resource.Resource = &LocalResource{} var _ resource.ResourceWithImportState = &LocalResource{} +const unprotectedHmacSecret = "this-is-the-hmac-secret-key-that-will-be-used-to-calculate-the-hash-of-unprotected-files" + // An interface for defining custom file managers. type fileClient interface { Create(directory string, name string, data string, permissions string) error @@ -43,58 +43,6 @@ type fileClient interface { Delete(directory string, name string) error } -// The default fileClient, using the os package. -type osFileClient struct{} - -var _ fileClient = &osFileClient{} // make sure the osFileClient implements the fileClient - -func (c *osFileClient) Create(directory string, name string, data string, permissions string) error { - path := filepath.Join(directory, name) - modeInt, err := strconv.ParseUint(permissions, 8, 32) - if err != nil { - return err - } - return os.WriteFile(path, []byte(data), os.FileMode(modeInt)) -} -func (c *osFileClient) Read(directory string, name string) (string, string, error) { - path := filepath.Join(directory, name) - info, err := os.Stat(path) - if err != nil && os.IsNotExist(err) { - return "", "", fmt.Errorf("file not found") - } - if err != nil { - return "", "", err - } - mode := fmt.Sprintf("%#o", info.Mode().Perm()) - contents, err := os.ReadFile(path) - if err != nil { - return "", "", err - } - return mode, string(contents), nil -} -func (c *osFileClient) Update(currentDirectory string, currentName string, newDirectory string, newName string, data string, permissions string) error { - currentPath := filepath.Join(currentDirectory, currentName) - newPath := filepath.Join(newDirectory, newName) - if currentPath != newPath { - err := os.Rename(currentPath, newPath) - if err != nil { - return err - } - } - modeInt, err := strconv.ParseUint(permissions, 8, 32) - if err != nil { - return err - } - if err = os.WriteFile(newPath, []byte(data), os.FileMode(modeInt)); err != nil { - return err - } - return nil -} -func (c *osFileClient) Delete(directory string, name string) error { - path := filepath.Join(directory, name) - return os.Remove(path) -} - func NewLocalResource() resource.Resource { return &LocalResource{} } @@ -212,6 +160,7 @@ func (r *LocalResource) Create(ctx context.Context, req resource.CreateRequest, var err error // Allow the ability to inject a file client, but use the osFileClient by default. + // see file_os_client.go if r.client == nil { tflog.Debug(ctx, "Configuring client with default osFileClient.") r.client = &osFileClient{} @@ -245,7 +194,7 @@ func (r *LocalResource) Create(ctx context.Context, req resource.CreateRequest, return } // at this point we have an id, key, contents, protected is true, and our calculated id matches what was provided } else { - id, err = calculateId(contents, "this-is-the-hmac-secret-key-that-will-be-used-to-calculate-the-hash-of-unprotected-files") + id, err = calculateId(contents, unprotectedHmacSecret) if err != nil { resp.Diagnostics.AddError("Error creating file: ", "Problem calculating id from hard coded key: "+err.Error()) return @@ -369,7 +318,7 @@ func (r *LocalResource) Update(ctx context.Context, req resource.UpdateRequest, return } } else { - id, err := calculateId(cContents, "this-is-the-hmac-secret-key-that-will-be-used-to-calculate-the-hash-of-unprotected-files") + id, err := calculateId(cContents, unprotectedHmacSecret) if err != nil { resp.Diagnostics.AddError("Error updating file: ", "Problem calculating id from hard coded key: "+err.Error()) return @@ -405,7 +354,7 @@ func (r *LocalResource) Update(ctx context.Context, req resource.UpdateRequest, return } } else { - _, err := calculateId(rContents, "this-is-the-hmac-secret-key-that-will-be-used-to-calculate-the-hash-of-unprotected-files") + _, err := calculateId(rContents, unprotectedHmacSecret) if err != nil { resp.Diagnostics.AddError("Error updating file: ", "Problem calculating id from hard coded key: "+err.Error()) return diff --git a/internal/provider/file_local_resource_test.go b/internal/provider/local/file_local_resource_test.go similarity index 93% rename from internal/provider/file_local_resource_test.go rename to internal/provider/local/file_local_resource_test.go index a6e89d0..f947329 100644 --- a/internal/provider/file_local_resource_test.go +++ b/internal/provider/local/file_local_resource_test.go @@ -1,10 +1,9 @@ // SPDX-License-Identifier: MPL-2.0 -package provider +package local import ( "context" - "fmt" "slices" "strconv" "testing" @@ -709,43 +708,3 @@ func getLocalResourceSchema() *resource.SchemaResponse { testResource.Schema(context.Background(), resource.SchemaRequest{}, r) return r } - -// type fileClient interface { -// Create(directory string, name string, data string, permissions string) error -// // If file isn't found the error message must have err.Error() == "File not found." -// Read(directory string, name string) (string, string, error)// permissions, contents, error -// Update(currentDirectory string, currentName string, newDirectory string, newName string, data string, permissions string) error -// Delete(directory string, name string) error -// } - -type memoryFileClient struct { - file map[string]string -} - -var _ fileClient = &memoryFileClient{} // make sure the memoryFileClient implements the fileClient -func (c *memoryFileClient) Create(directory string, name string, data string, permissions string) error { - - c.file = make(map[string]string) - c.file["directory"] = directory - c.file["name"] = name - c.file["contents"] = data - c.file["permissions"] = permissions - return nil -} -func (c *memoryFileClient) Read(directory string, name string) (string, string, error) { - if c.file["directory"] == "" || c.file["name"] == "" { - return "", "", fmt.Errorf("file not found") - } - return c.file["permissions"], c.file["contents"], nil -} -func (c *memoryFileClient) Update(currentDirectory string, currentName string, newDirectory string, newName string, data string, permissions string) error { - c.file["directory"] = newDirectory - c.file["name"] = newName - c.file["contents"] = data - c.file["permissions"] = permissions - return nil -} -func (c *memoryFileClient) Delete(directory string, name string) error { - c.file = nil - return nil -} diff --git a/internal/provider/local/file_memory_client.go b/internal/provider/local/file_memory_client.go new file mode 100644 index 0000000..17feadc --- /dev/null +++ b/internal/provider/local/file_memory_client.go @@ -0,0 +1,41 @@ +package local + +import ( + "fmt" +) + +type memoryFileClient struct { + file map[string]string +} + +var _ fileClient = &memoryFileClient{} // make sure the memoryFileClient implements the fileClient + +func (c *memoryFileClient) Create(directory string, name string, data string, permissions string) error { + + c.file = make(map[string]string) + c.file["directory"] = directory + c.file["name"] = name + c.file["contents"] = data + c.file["permissions"] = permissions + return nil +} + +func (c *memoryFileClient) Read(directory string, name string) (string, string, error) { + if c.file["directory"] == "" || c.file["name"] == "" { + return "", "", fmt.Errorf("file not found") + } + return c.file["permissions"], c.file["contents"], nil +} + +func (c *memoryFileClient) Update(currentDirectory string, currentName string, newDirectory string, newName string, data string, permissions string) error { + c.file["directory"] = newDirectory + c.file["name"] = newName + c.file["contents"] = data + c.file["permissions"] = permissions + return nil +} + +func (c *memoryFileClient) Delete(directory string, name string) error { + c.file = nil + return nil +} diff --git a/internal/provider/local/file_os_client.go b/internal/provider/local/file_os_client.go new file mode 100644 index 0000000..f075471 --- /dev/null +++ b/internal/provider/local/file_os_client.go @@ -0,0 +1,63 @@ +package local + +import ( + "fmt" + "os" + "path/filepath" + "strconv" +) + +// The default fileClient, using the os package. +type osFileClient struct{} + +var _ fileClient = &osFileClient{} // make sure the osFileClient implements the fileClient + +func (c *osFileClient) Create(directory string, name string, data string, permissions string) error { + path := filepath.Join(directory, name) + modeInt, err := strconv.ParseUint(permissions, 8, 32) + if err != nil { + return err + } + return os.WriteFile(path, []byte(data), os.FileMode(modeInt)) +} + +func (c *osFileClient) Read(directory string, name string) (string, string, error) { + path := filepath.Join(directory, name) + info, err := os.Stat(path) + if err != nil && os.IsNotExist(err) { + return "", "", fmt.Errorf("file not found") + } + if err != nil { + return "", "", err + } + mode := fmt.Sprintf("%#o", info.Mode().Perm()) + contents, err := os.ReadFile(path) + if err != nil { + return "", "", err + } + return mode, string(contents), nil +} + +func (c *osFileClient) Update(currentDirectory string, currentName string, newDirectory string, newName string, data string, permissions string) error { + currentPath := filepath.Join(currentDirectory, currentName) + newPath := filepath.Join(newDirectory, newName) + if currentPath != newPath { + err := os.Rename(currentPath, newPath) + if err != nil { + return err + } + } + modeInt, err := strconv.ParseUint(permissions, 8, 32) + if err != nil { + return err + } + if err = os.WriteFile(newPath, []byte(data), os.FileMode(modeInt)); err != nil { + return err + } + return nil +} + +func (c *osFileClient) Delete(directory string, name string) error { + path := filepath.Join(directory, name) + return os.Remove(path) +} diff --git a/internal/provider/provider.go b/internal/provider/provider.go index fbe8304..2940d3c 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/provider/schema" "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/rancher/terraform-provider-file/internal/provider/local" ) // The `var _` is a special Go construct that results in an unusable variable. @@ -48,13 +49,13 @@ func (p *FileProvider) Configure(ctx context.Context, req provider.ConfigureRequ func (p *FileProvider) Resources(ctx context.Context) []func() resource.Resource { return []func() resource.Resource{ - NewLocalResource, + local.NewLocalResource, } } func (p *FileProvider) DataSources(ctx context.Context) []func() datasource.DataSource { return []func() datasource.DataSource{ - // NewExampleDataSource, + local.NewLocalDataSource, } } diff --git a/main.go b/main.go index cea3a9d..7d6dd5e 100644 --- a/main.go +++ b/main.go @@ -1,5 +1,3 @@ -// Copyright (c) HashiCorp, Inc. - package main import ( diff --git a/test/.terraformrc b/test/.terraformrc index dcdcbfe..cf3b6ac 100644 --- a/test/.terraformrc +++ b/test/.terraformrc @@ -1,6 +1,6 @@ provider_installation { dev_overrides { - "rancher/file" = "../../../bin" + "rancher/file" = "../../../../bin" } direct { exclude = [] diff --git a/test/basic/basic_test.go b/test/local/basic/basic_test.go similarity index 87% rename from test/basic/basic_test.go rename to test/local/basic/basic_test.go index 87b6a20..af081b7 100644 --- a/test/basic/basic_test.go +++ b/test/local/basic/basic_test.go @@ -1,5 +1,3 @@ -// Copyright (c) HashiCorp, Inc. - package basic import ( @@ -14,7 +12,7 @@ func TestBasic(t *testing.T) { t.Parallel() id := util.GetId() - directory := "basic" + directory := "local/basic" repoRoot, err := util.GetRepoRoot(t) if err != nil { t.Fatalf("Error getting git root directory: %v", err) @@ -40,6 +38,7 @@ func TestBasic(t *testing.T) { }, EnvVars: map[string]string{ "TF_DATA_DIR": testDir, + "TF_CLI_CONFIG_FILE": filepath.Join(repoRoot, "test", ".terraformrc"), "TF_IN_AUTOMATION": "1", "TF_CLI_ARGS_init": "-no-color", "TF_CLI_ARGS_plan": "-no-color", @@ -50,6 +49,7 @@ func TestBasic(t *testing.T) { RetryableTerraformErrors: util.GetRetryableTerraformErrors(), NoColor: true, Upgrade: true, + // ExtraArgs: terraform.ExtraArgs{ Output: []string{"-json"} }, }) _, err = terraform.InitAndApplyE(t, terraformOptions) @@ -58,6 +58,10 @@ func TestBasic(t *testing.T) { util.TearDown(t, testDir, terraformOptions) t.Fatalf("Error creating file: %s", err) } + _, err = terraform.OutputAllE(t, terraformOptions) + if err != nil { + t.Log("Output failed, moving along...") + } fileExists, err := util.CheckFileExists(filepath.Join(testDir, "basic_test.txt")) if err != nil { diff --git a/test/protected/basic_test.go b/test/local/protected/basic_test.go similarity index 88% rename from test/protected/basic_test.go rename to test/local/protected/basic_test.go index 7e7a1b5..2c3bb04 100644 --- a/test/protected/basic_test.go +++ b/test/local/protected/basic_test.go @@ -1,5 +1,3 @@ -// Copyright (c) HashiCorp, Inc. - package protected import ( @@ -13,7 +11,7 @@ import ( func TestProtectedBasic(t *testing.T) { t.Parallel() id := util.GetId() - directory := "protected" + directory := "local/protected" repoRoot, err := util.GetRepoRoot(t) if err != nil { t.Fatalf("Error getting git root directory: %v", err) @@ -41,6 +39,7 @@ func TestProtectedBasic(t *testing.T) { EnvVars: map[string]string{ "TF_DATA_DIR": testDir, "TF_FILE_HMAC_SECRET_KEY": "thisisasupersecretkey", + "TF_CLI_CONFIG_FILE": filepath.Join(repoRoot, "test", ".terraformrc"), "TF_IN_AUTOMATION": "1", "TF_CLI_ARGS_init": "-no-color", "TF_CLI_ARGS_plan": "-no-color", @@ -51,6 +50,7 @@ func TestProtectedBasic(t *testing.T) { RetryableTerraformErrors: util.GetRetryableTerraformErrors(), NoColor: true, Upgrade: true, + // ExtraArgs: terraform.ExtraArgs{ Output: []string{"-json"} }, }) _, err = terraform.InitAndApplyE(t, terraformOptions) @@ -59,6 +59,10 @@ func TestProtectedBasic(t *testing.T) { util.TearDown(t, testDir, terraformOptions) t.Fatalf("Error creating file: %s", err) } + _, err = terraform.OutputAllE(t, terraformOptions) + if err != nil { + t.Log("Output failed, moving along...") + } fileAExists, err := util.CheckFileExists(filepath.Join(testDir, "a_protected_test.txt")) if err != nil { diff --git a/test/protected/protected_test.go b/test/local/protected/protected_test.go similarity index 90% rename from test/protected/protected_test.go rename to test/local/protected/protected_test.go index 4319cf0..c3e96fb 100644 --- a/test/protected/protected_test.go +++ b/test/local/protected/protected_test.go @@ -1,5 +1,3 @@ -// Copyright (c) HashiCorp, Inc. - package protected import ( @@ -13,7 +11,7 @@ import ( func TestProtectedProtects(t *testing.T) { t.Parallel() id := util.GetId() - directory := "protected" + directory := "local/protected" repoRoot, err := util.GetRepoRoot(t) if err != nil { t.Fatalf("Error getting git root directory: %v", err) @@ -41,6 +39,7 @@ func TestProtectedProtects(t *testing.T) { EnvVars: map[string]string{ "TF_DATA_DIR": testDir, "TF_FILE_HMAC_SECRET_KEY": "thisisasupersecretkey", + "TF_CLI_CONFIG_FILE": filepath.Join(repoRoot, "test", ".terraformrc"), "TF_IN_AUTOMATION": "1", "TF_CLI_ARGS_init": "-no-color", "TF_CLI_ARGS_plan": "-no-color", @@ -51,6 +50,7 @@ func TestProtectedProtects(t *testing.T) { RetryableTerraformErrors: util.GetRetryableTerraformErrors(), NoColor: true, Upgrade: true, + // ExtraArgs: terraform.ExtraArgs{ Output: []string{"-json"} }, }) _, err = terraform.InitAndApplyE(t, terraformOptions) @@ -59,6 +59,10 @@ func TestProtectedProtects(t *testing.T) { util.TearDown(t, testDir, terraformOptions) t.Fatalf("Error creating file: %s", err) } + _, err = terraform.OutputAllE(t, terraformOptions) + if err != nil { + t.Log("Output failed, moving along...") + } fileAExists, err := util.CheckFileExists(filepath.Join(testDir, "a_protected_test.txt")) if err != nil { diff --git a/test/summarize.sh b/test/summarize.sh index b5daba4..f0071d4 100755 --- a/test/summarize.sh +++ b/test/summarize.sh @@ -1,5 +1,5 @@ #!/bin/sh -# Copyright (c) HashiCorp, Inc. + # summarize.sh - reads report.json and prints a summary diff --git a/test/util.go b/test/util.go index 0e7b5ac..e031d5c 100644 --- a/test/util.go +++ b/test/util.go @@ -1,5 +1,3 @@ -// Copyright (c) HashiCorp, Inc. - package test import ( diff --git a/tools/tools.go b/tools/tools.go index 9c47fd6..cf3168d 100644 --- a/tools/tools.go +++ b/tools/tools.go @@ -1,4 +1,3 @@ -// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 //go:build generate @@ -6,13 +5,9 @@ package tools import ( - _ "github.com/hashicorp/copywrite" _ "github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs" ) -// Generate copyright headers -//go:generate go run github.com/hashicorp/copywrite headers -d .. --config ../.copywrite.hcl - // Format Terraform code for use in documentation. // If you do not have Terraform installed, you can remove the formatting command, but it is suggested // to ensure the documentation is formatted properly.