From 53fdc269ebf6d77c90cba729a983e2ed308040a3 Mon Sep 17 00:00:00 2001
From: Lucas TESSON <lucastesson@protonmail.com>
Date: Fri, 6 Oct 2023 17:41:51 +0200
Subject: [PATCH] WIP: transfer repository to ctfer.io organization, moving on
 from terraform to opentofu

---
 .github/workflows/scoreboard.yaml             |   2 +-
 CODE_OF_CONDUCT.md                            |   2 +-
 LICENSE                                       | 222 ++++++++++++++++--
 README.md                                     |  24 +-
 SECURITY.md                                   |   6 +-
 .../provider-install-verification/main.tf     |   2 +-
 go.mod                                        |  44 +++-
 go.sum                                        | 134 ++++++++++-
 .../provider/challenge/file_subdata_source.go |   4 +-
 .../provider/challenge/file_subresource.go    |  26 +-
 .../provider/challenge/flag_subdata_source.go |   4 +-
 .../provider/challenge/flag_subresource.go    |  26 +-
 .../provider/challenge/hint_subdata_source.go |   6 +-
 .../provider/challenge/hint_subresource.go    |  26 +-
 .../challenge/requirements_subresource.go     |  25 +-
 .../{challenge => }/challenge_data_source.go  |  45 ++--
 .../provider/challenge_data_source_test.go    |  20 ++
 .../{challenge => }/challenge_resource.go     | 150 ++++++------
 internal/provider/provider.go                 |  21 +-
 internal/provider/provider_test.go            |  22 ++
 internal/provider/utils.go                    |   2 +-
 .../provider/{challenge => utils}/utils.go    |  12 +-
 internal/provider/validators/string_enum.go   |   4 +-
 main.go                                       |   6 +-
 24 files changed, 607 insertions(+), 228 deletions(-)
 rename internal/provider/{challenge => }/challenge_data_source.go (82%)
 create mode 100644 internal/provider/challenge_data_source_test.go
 rename internal/provider/{challenge => }/challenge_resource.go (81%)
 create mode 100644 internal/provider/provider_test.go
 rename internal/provider/{challenge => utils}/utils.go (64%)

diff --git a/.github/workflows/scoreboard.yaml b/.github/workflows/scoreboard.yaml
index 973b598..5041581 100644
--- a/.github/workflows/scoreboard.yaml
+++ b/.github/workflows/scoreboard.yaml
@@ -2,7 +2,7 @@ name: Scorecard supply-chain security
 on:
   branch_protection_rule:
   schedule:
-    - cron: '30 0 * * 6'
+    - cron: '30 6 * * 6'
   push:
     branches: [ "main" ]
 
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
index 516c72d..7d59bf3 100644
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -60,7 +60,7 @@ representative at an online or offline event.
 
 Instances of abusive, harassing, or otherwise unacceptable behavior may be
 reported to the community leaders responsible for enforcement at
-lucastesson@protonmail.com.
+ctfer-io@protonmail.com.
 All complaints will be reviewed and investigated promptly and fairly.
 
 All community leaders are obligated to respect the privacy and security of the
diff --git a/LICENSE b/LICENSE
index c342233..743bd88 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,21 +1,201 @@
-MIT License
-
-Copyright (c) 2023 Lucas TESSON - PandatiX <lucastesson@protonmail.com>
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 2023 CTFer.io
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/README.md b/README.md
index c07598a..37b0788 100644
--- a/README.md
+++ b/README.md
@@ -1,29 +1,29 @@
 <div align="center">
-    <h1>Terraform Provider for CTFd</h1>
+    <h1>OpenTofu Provider for CTFd</h1>
     <p><b>Time for CTF(d) as Code</b><p>
-    <a href="https://pkg.go.dev/github.com/pandatix/terraform-provider-ctfd"><img src="https://shields.io/badge/-reference-blue?logo=go&style=for-the-badge" alt="reference"></a>
-	<a href="https://goreportcard.com/report/github.com/pandatix/terraform-provider-ctfd"><img src="https://goreportcard.com/badge/github.com/pandatix/terraform-provider-ctfd?style=for-the-badge" alt="go report"></a>
-	<a href="https://coveralls.io/github/pandatix/terraform-provider-ctfd?branch=main"><img src="https://img.shields.io/coverallsCoverage/github/pandatix/terraform-provider-ctfd?style=for-the-badge" alt="Coverage Status"></a>
+    <a href="https://pkg.go.dev/github.com/ctfer-io/tofu-provider-ctfd"><img src="https://shields.io/badge/-reference-blue?logo=go&style=for-the-badge" alt="reference"></a>
+	<a href="https://goreportcard.com/report/github.com/ctfer-io/tofu-provider-ctfd"><img src="https://goreportcard.com/badge/github.com/ctfer-io/tofu-provider-ctfd?style=for-the-badge" alt="go report"></a>
+	<a href="https://coveralls.io/github/ctfer-io/tofu-provider-ctfd?branch=main"><img src="https://img.shields.io/coverallsCoverage/github/ctfer-io/tofu-provider-ctfd?style=for-the-badge" alt="Coverage Status"></a>
 	<br>
-	<a href=""><img src="https://img.shields.io/github/license/pandatix/terraform-provider-ctfd?style=for-the-badge" alt="License"></a>
-	<a href="https://github.com/pandatix/terraform-provider-ctfd/actions?query=workflow%3Aci+"><img src="https://img.shields.io/github/actions/workflow/status/pandatix/terraform-provider-ctfd/ci.yaml?style=for-the-badge&label=CI" alt="CI"></a>
-	<a href="https://github.com/pandatix/terraform-provider-ctfd/actions/workflows/codeql-analysis.yaml"><img src="https://img.shields.io/github/actions/workflow/status/pandatix/terraform-provider-ctfd/codeql-analysis.yaml?style=for-the-badge&label=CodeQL" alt="CodeQL"></a>
+	<a href=""><img src="https://img.shields.io/github/license/ctfer-io/tofu-provider-ctfd?style=for-the-badge" alt="License"></a>
+	<a href="https://github.com/ctfer-io/tofu-provider-ctfd/actions?query=workflow%3Aci+"><img src="https://img.shields.io/github/actions/workflow/status/ctfer-io/tofu-provider-ctfd/ci.yaml?style=for-the-badge&label=CI" alt="CI"></a>
+	<a href="https://github.com/ctfer-io/tofu-provider-ctfd/actions/workflows/codeql-analysis.yaml"><img src="https://img.shields.io/github/actions/workflow/status/ctfer-io/tofu-provider-ctfd/codeql-analysis.yaml?style=for-the-badge&label=CodeQL" alt="CodeQL"></a>
     <br>
-    <a href="https://securityscorecards.dev/viewer/?uri=github.com/pandatix/terraform-provider-ctfd"><img src="https://img.shields.io/ossf-scorecard/github.com/pandatix/terraform-provider-ctfd?label=openssf%20scorecard&style=for-the-badge" alt="OpenSSF Scoreboard"></a>
+    <a href="https://securityscorecards.dev/viewer/?uri=github.com/ctfer-io/tofu-provider-ctfd"><img src="https://img.shields.io/ossf-scorecard/github.com/ctfer-io/tofu-provider-ctfd?label=openssf%20scorecard&style=for-the-badge" alt="OpenSSF Scoreboard"></a>
 </div>
 
 ## Why creating this ?
 
-Terraform is used to manage resources that have lifecycles, to sum it up.
+OpenTofu is used to manage resources that have lifecycles, configurations, to sum it up.
 
-Well, that is the case of CTFd : it handles challenges that could be created, modified and deleted.
-With some work to leverage the unsteady CTFd's API, Terraform is now able to manage them as cloud resources bringing you to opportunity of **CTF as Code**.
+That is the case of CTFd: it handles challenges that could be created, modified and deleted.
+With some work to leverage the unsteady CTFd's API, OpenTofu is now able to manage them as cloud resources bringing you to opportunity of **CTF as Code**.
 
 It avoids shitty scripts, `ctfcli` and other tools that does not solve the problem of reproductibility, ease of deployment and resiliency.
 
 ## How to use it ?
 
-With the **Terraform Provider for CTFd**, you could setup your CTFd challenge using the following configuration.
+With the **OpenTofu Provider for CTFd**, you could setup your CTFd challenge using the following configuration.
 ```hcl
 resource "ctfd_challenge" "my_challenge" {
     name        = "My Challenge"
diff --git a/SECURITY.md b/SECURITY.md
index f79fe32..71229dc 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -1,13 +1,13 @@
 # Reporting Security Issues
 
-Please report any security issues you discovered in the API to lucastesson@protonmail.com.
+Please report any security issues you discovered in the API to ctfer-io@protonmail.com.
 
 We will assess the risk, plus make a fix available before we create a GitHub issue.
 
-In case the vulnerability is into a dependency or Terraform itself, do not report this to us but refer to their policies.
+In case the vulnerability is into a dependency or OpenTofu itself, please refer to their security policy directly.
 
 Thank you for your contribution.
 
 ## Refering to this repository
 
-To refer to this repository using a CPE v2.3, please use `cpe:2.3:a:pandatix:terraform-provider-ctfd:*:*:*:*:*:terraform:*:*` with the `version` set to the tag you are using.
+To refer to this repository using a CPE v2.3, please use `cpe:2.3:a:ctfer-io:tofu-provider-ctfd:*:*:*:*:*:*:*:*` with the `version` set to the tag you are using.
diff --git a/examples/provider-install-verification/main.tf b/examples/provider-install-verification/main.tf
index b04d156..b48b696 100644
--- a/examples/provider-install-verification/main.tf
+++ b/examples/provider-install-verification/main.tf
@@ -1,7 +1,7 @@
 terraform {
     required_providers {
         ctfd = {
-            source = "registry.terraform.io/pandatix/ctfd"
+            source = "registry.terraform.io/ctfer-io/ctfd"
         }
     }
 }
diff --git a/go.mod b/go.mod
index 6e4cf61..a965ef3 100644
--- a/go.mod
+++ b/go.mod
@@ -1,34 +1,62 @@
-module github.com/pandatix/terraform-provider-ctfd
+module github.com/ctfer-io/tofu-provider-ctfd
 
 go 1.21
 
 require (
-	github.com/hashicorp/terraform-plugin-framework v1.3.5
-	github.com/hashicorp/terraform-plugin-log v0.9.0
-	github.com/pandatix/go-ctfd v0.1.9
+	github.com/opentofu/terraform-plugin-framework v1.3.4
+	github.com/opentofu/terraform-plugin-go v0.18.0
+	github.com/opentofu/terraform-plugin-log v0.9.0
+	github.com/opentofu/terraform-plugin-testing v1.5.1
+	github.com/ctfer-io/go-ctfd v0.1.9
 )
 
 require (
+	github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect
+	github.com/agext/levenshtein v1.2.2 // indirect
+	github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
+	github.com/cloudflare/circl v1.3.3 // indirect
 	github.com/fatih/color v1.13.0 // indirect
 	github.com/golang/protobuf v1.5.3 // indirect
+	github.com/google/go-cmp v0.5.9 // indirect
 	github.com/gorilla/schema v1.2.0 // indirect
+	github.com/hashicorp/errwrap v1.0.0 // indirect
+	github.com/hashicorp/go-checkpoint v0.5.0 // indirect
+	github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
+	github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // indirect
 	github.com/hashicorp/go-hclog v1.5.0 // indirect
+	github.com/hashicorp/go-multierror v1.1.1 // indirect
 	github.com/hashicorp/go-plugin v1.4.10 // indirect
 	github.com/hashicorp/go-uuid v1.0.3 // indirect
-	github.com/hashicorp/terraform-plugin-go v0.18.0 // indirect
+	github.com/hashicorp/go-version v1.6.0 // indirect
+	github.com/hashicorp/hc-install v0.5.2 // indirect
+	github.com/hashicorp/hcl/v2 v2.17.0 // indirect
+	github.com/hashicorp/logutils v1.0.0 // indirect
+	github.com/hashicorp/terraform-exec v0.18.1 // indirect
+	github.com/hashicorp/terraform-json v0.17.1 // indirect
+	github.com/hashicorp/terraform-plugin-sdk/v2 v2.28.0 // indirect
 	github.com/hashicorp/terraform-registry-address v0.2.1 // indirect
 	github.com/hashicorp/terraform-svchost v0.1.1 // indirect
-	github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect
+	github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect
 	github.com/mattn/go-colorable v0.1.12 // indirect
 	github.com/mattn/go-isatty v0.0.14 // indirect
+	github.com/mitchellh/copystructure v1.2.0 // indirect
 	github.com/mitchellh/go-testing-interface v1.14.1 // indirect
+	github.com/mitchellh/go-wordwrap v1.0.0 // indirect
+	github.com/mitchellh/mapstructure v1.5.0 // indirect
+	github.com/mitchellh/reflectwalk v1.0.2 // indirect
 	github.com/oklog/run v1.0.0 // indirect
 	github.com/pkg/errors v0.9.1 // indirect
+	github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
 	github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect
 	github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
+	github.com/zclconf/go-cty v1.13.3 // indirect
+	golang.org/x/crypto v0.12.0 // indirect
+	golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819 // indirect
+	golang.org/x/mod v0.11.0 // indirect
 	golang.org/x/net v0.11.0 // indirect
-	golang.org/x/sys v0.9.0 // indirect
-	golang.org/x/text v0.10.0 // indirect
+	golang.org/x/sys v0.11.0 // indirect
+	golang.org/x/text v0.12.0 // indirect
+	google.golang.org/appengine v1.6.7 // indirect
 	google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
 	google.golang.org/grpc v1.56.1 // indirect
 	google.golang.org/protobuf v1.31.0 // indirect
diff --git a/go.sum b/go.sum
index 616303e..2c9ad19 100644
--- a/go.sum
+++ b/go.sum
@@ -1,72 +1,186 @@
+github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
+github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
+github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 h1:wPbRQzjjwFc0ih8puEVAOFGELsn1zoIIYdxvML7mDxA=
+github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g=
+github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
+github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
+github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE=
+github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
+github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec=
+github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
+github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
+github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
+github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
+github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
+github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
+github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
 github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
 github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
+github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
+github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
+github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4=
+github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg=
+github.com/go-git/go-git/v5 v5.6.1 h1:q4ZRqQl4pR/ZJHc1L5CFjGA1a10u76aV1iC+nh+bHsk=
+github.com/go-git/go-git/v5 v5.6.1/go.mod h1:mvyoL6Unz0PiTQrGQfSfiLFhBH1c1e84ylC2MDs4ee8=
+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/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
 github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
 github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc=
 github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=
+github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU=
+github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg=
+github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
+github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
+github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 h1:1/D3zfFHttUKaCaGKZ/dR2roBXv0vKbSCnssIldfQdI=
+github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320/go.mod h1:EiZBMaudVLy8fmjf9Npq1dq9RalhveqZG5w/yz3mHWs=
 github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
 github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
+github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
 github.com/hashicorp/go-plugin v1.4.10 h1:xUbmA4jC6Dq163/fWcp8P3JuHilrHHMLNRxzGQJ9hNk=
 github.com/hashicorp/go-plugin v1.4.10/go.mod h1:6/1TEzT0eQznvI/gV2CM29DLSkAK/e58mUWKVsPaph0=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
 github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
 github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/terraform-plugin-framework v1.3.5 h1:FJ6s3CVWVAxlhiF/jhy6hzs4AnPHiflsp9KgzTGl1wo=
-github.com/hashicorp/terraform-plugin-framework v1.3.5/go.mod h1:2gGDpWiTI0irr9NSTLFAKlTi6KwGti3AoU19rFqU30o=
+github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
+github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/hc-install v0.5.2 h1:SfwMFnEXVVirpwkDuSF5kymUOhrUxrTq3udEseZdOD0=
+github.com/hashicorp/hc-install v0.5.2/go.mod h1:9QISwe6newMWIfEiXpzuu1k9HAGtQYgnSH8H9T8wmoI=
+github.com/hashicorp/hcl/v2 v2.17.0 h1:z1XvSUyXd1HP10U4lrLg5e0JMVz6CPaJvAgxM0KNZVY=
+github.com/hashicorp/hcl/v2 v2.17.0/go.mod h1:gJyW2PTShkJqQBKpAmPO3yxMxIuoXkOF2TpqXzrQyx4=
+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.18.1 h1:LAbfDvNQU1l0NOQlTuudjczVhHj061fNX5H8XZxHlH4=
+github.com/hashicorp/terraform-exec v0.18.1/go.mod h1:58wg4IeuAJ6LVsLUeD2DWZZoc/bYi6dzhLHzxM41980=
+github.com/hashicorp/terraform-json v0.17.1 h1:eMfvh/uWggKmY7Pmb3T85u86E2EQg6EQHgyRwf3RkyA=
+github.com/hashicorp/terraform-json v0.17.1/go.mod h1:Huy6zt6euxaY9knPAFKjUITn8QxUFIe9VuSzb4zn/0o=
+github.com/hashicorp/terraform-plugin-framework v1.3.4 h1:dOTLsALgmQu+PawAvhfGQ04H0MeIz3EZmBw7OFvj7qs=
+github.com/hashicorp/terraform-plugin-framework v1.3.4/go.mod h1:2gGDpWiTI0irr9NSTLFAKlTi6KwGti3AoU19rFqU30o=
 github.com/hashicorp/terraform-plugin-go v0.18.0 h1:IwTkOS9cOW1ehLd/rG0y+u/TGLK9y6fGoBjXVUquzpE=
 github.com/hashicorp/terraform-plugin-go v0.18.0/go.mod h1:l7VK+2u5Kf2y+A+742GX0ouLut3gttudmvMgN0PA74Y=
 github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
 github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow=
+github.com/hashicorp/terraform-plugin-sdk/v2 v2.28.0 h1:gY4SG34ANc6ZSeWEKC9hDTChY0ZiN+Myon17fSA0Xgc=
+github.com/hashicorp/terraform-plugin-sdk/v2 v2.28.0/go.mod h1:deXEw/iJXtJxNV9d1c/OVJrvL7Zh0a++v7rzokW6wVY=
+github.com/hashicorp/terraform-plugin-testing v1.5.1 h1:T4aQh9JAhmWo4+t1A7x+rnxAJHCDIYW9kXyo4sVO92c=
+github.com/hashicorp/terraform-plugin-testing v1.5.1/go.mod h1:dg8clO6K59rZ8w9EshBmDp1CxTIPu3yA4iaDpX1h5u0=
 github.com/hashicorp/terraform-registry-address v0.2.1 h1:QuTf6oJ1+WSflJw6WYOHhLgwUiQ0FrROpHPYFtwTYWM=
 github.com/hashicorp/terraform-registry-address v0.2.1/go.mod h1:BSE9fIFzp0qWsJUUyGquo4ldV9k2n+psif6NYkBRS3Y=
 github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ=
 github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc=
-github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M=
-github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
+github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ=
+github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
+github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
+github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
+github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
+github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
 github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
 github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74=
+github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
+github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
 github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
 github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
 github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
 github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
 github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
 github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
+github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
+github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
 github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
 github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
+github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
+github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
+github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
 github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
 github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
 github.com/pandatix/go-ctfd v0.1.9 h1:4ZiydbZgV2kXNTRnqyJfChFuxUt7W8RRsfw9T0LicmI=
 github.com/pandatix/go-ctfd v0.1.9/go.mod h1:RzuIfvJGweW7/a8uo+STh9e6m2Hbi8o1DskmeHljiK4=
+github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
+github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
+github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
+github.com/skeema/knownhosts v1.1.0 h1:Wvr9V0MxhjRbl3f9nMnKnFfiWTJmtECJ9Njkea3ysW0=
+github.com/skeema/knownhosts v1.1.0/go.mod h1:sKFq3RD6/TKZkSWn8boUbDC7Qkgcv+8XXijpFO6roag=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
 github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
+github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
+github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
+github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
 github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU=
 github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=
 github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
 github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
+github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
+github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
+github.com/zclconf/go-cty v1.13.3 h1:m+b9q3YDbg6Bec5rr+KGy1MzEVzY/jC2X+YX4yqKtHI=
+github.com/zclconf/go-cty v1.13.3/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
+golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
+golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819 h1:EDuYyU/MkFXllv9QF9819VlI9a4tzGuCbhG0ExK9o1U=
+golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
+golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
+golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
 golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
-golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
-golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
+golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
+golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
+google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
 google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
 google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
 google.golang.org/grpc v1.56.1 h1:z0dNfjIl0VpaZ9iSVjA6daGatAYwPGstTjt5vkRMFkQ=
@@ -76,6 +190,10 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
 google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
 google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
+gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/internal/provider/challenge/file_subdata_source.go b/internal/provider/challenge/file_subdata_source.go
index 100fbb5..a70a85d 100644
--- a/internal/provider/challenge/file_subdata_source.go
+++ b/internal/provider/challenge/file_subdata_source.go
@@ -1,8 +1,8 @@
 package challenge
 
-import "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+import "github.com/opentofu/terraform-plugin-framework/datasource/schema"
 
-func fileSubdatasourceAttributes() map[string]schema.Attribute {
+func FileSubdatasourceAttributes() map[string]schema.Attribute {
 	return map[string]schema.Attribute{
 		"id": schema.StringAttribute{
 			Computed: true,
diff --git a/internal/provider/challenge/file_subresource.go b/internal/provider/challenge/file_subresource.go
index 07c213b..55a1c1f 100644
--- a/internal/provider/challenge/file_subresource.go
+++ b/internal/provider/challenge/file_subresource.go
@@ -6,16 +6,16 @@ import (
 	"fmt"
 	"strconv"
 
-	"github.com/hashicorp/terraform-plugin-framework/diag"
-	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
-	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
-	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
-	"github.com/hashicorp/terraform-plugin-framework/types"
-	"github.com/hashicorp/terraform-plugin-log/tflog"
-	"github.com/pandatix/go-ctfd/api"
+	"github.com/ctfer-io/go-ctfd/api"
+	"github.com/opentofu/terraform-plugin-framework/diag"
+	"github.com/opentofu/terraform-plugin-framework/resource/schema"
+	"github.com/opentofu/terraform-plugin-framework/resource/schema/planmodifier"
+	"github.com/opentofu/terraform-plugin-framework/resource/schema/stringplanmodifier"
+	"github.com/opentofu/terraform-plugin-framework/types"
+	"github.com/opentofu/terraform-plugin-log/tflog"
 )
 
-type fileSubresourceModel struct {
+type FileSubresourceModel struct {
 	ID       types.String `tfsdk:"id"`
 	Name     types.String `tfsdk:"name"`
 	Location types.String `tfsdk:"location"`
@@ -24,7 +24,7 @@ type fileSubresourceModel struct {
 	ContentB64 types.String `tfsdk:"contentb64"`
 }
 
-func fileSubresourceAttributes() map[string]schema.Attribute {
+func FileSubresourceAttributes() map[string]schema.Attribute {
 	return map[string]schema.Attribute{
 		"id": schema.StringAttribute{
 			Computed: true,
@@ -61,7 +61,7 @@ func fileSubresourceAttributes() map[string]schema.Attribute {
 }
 
 // Read fetches all the file's information, only requiring the ID to be set.
-func (file *fileSubresourceModel) Read(ctx context.Context, diags diag.Diagnostics, client *api.Client) {
+func (file *FileSubresourceModel) Read(ctx context.Context, diags diag.Diagnostics, client *api.Client) {
 	content, err := client.GetFileContent(&api.File{
 		Location: file.Location.ValueString(),
 	}, api.WithContext(ctx))
@@ -76,7 +76,7 @@ func (file *fileSubresourceModel) Read(ctx context.Context, diags diag.Diagnosti
 	file.PropagateContent(ctx, diags)
 }
 
-func (data *fileSubresourceModel) Create(ctx context.Context, diags diag.Diagnostics, client *api.Client, challengeID string) {
+func (data *FileSubresourceModel) Create(ctx context.Context, diags diag.Diagnostics, client *api.Client, challengeID string) {
 	// Fetch raw or base64 content prior to creating it with raw
 	data.PropagateContent(ctx, diags)
 	if diags.HasError() {
@@ -104,7 +104,7 @@ func (data *fileSubresourceModel) Create(ctx context.Context, diags diag.Diagnos
 	data.Location = types.StringValue(res[0].Location)
 }
 
-func (data *fileSubresourceModel) Delete(ctx context.Context, diags diag.Diagnostics, client *api.Client) {
+func (data *FileSubresourceModel) Delete(ctx context.Context, diags diag.Diagnostics, client *api.Client) {
 	if err := client.DeleteFile(data.ID.ValueString(), api.WithContext(ctx)); err != nil {
 		diags.AddError(
 			"Client Error",
@@ -116,7 +116,7 @@ func (data *fileSubresourceModel) Delete(ctx context.Context, diags diag.Diagnos
 	tflog.Trace(ctx, "deleted a file")
 }
 
-func (data *fileSubresourceModel) PropagateContent(ctx context.Context, diags diag.Diagnostics) {
+func (data *FileSubresourceModel) PropagateContent(ctx context.Context, diags diag.Diagnostics) {
 	// If the other content source is set, get the other from it
 	if len(data.Content.ValueString()) != 0 {
 		cb64 := base64.StdEncoding.EncodeToString([]byte(data.Content.ValueString()))
diff --git a/internal/provider/challenge/flag_subdata_source.go b/internal/provider/challenge/flag_subdata_source.go
index 853ee29..9af71a7 100644
--- a/internal/provider/challenge/flag_subdata_source.go
+++ b/internal/provider/challenge/flag_subdata_source.go
@@ -1,10 +1,10 @@
 package challenge
 
 import (
-	"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+	"github.com/opentofu/terraform-plugin-framework/datasource/schema"
 )
 
-func flagSubdatasourceAttributes() map[string]schema.Attribute {
+func FlagSubdatasourceAttributes() map[string]schema.Attribute {
 	return map[string]schema.Attribute{
 		"id": schema.StringAttribute{
 			Computed: true,
diff --git a/internal/provider/challenge/flag_subresource.go b/internal/provider/challenge/flag_subresource.go
index 11411a8..580d0e7 100644
--- a/internal/provider/challenge/flag_subresource.go
+++ b/internal/provider/challenge/flag_subresource.go
@@ -5,24 +5,24 @@ import (
 	"fmt"
 	"strconv"
 
-	"github.com/hashicorp/terraform-plugin-framework/diag"
-	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
-	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
-	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
-	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
-	"github.com/hashicorp/terraform-plugin-framework/types"
-	"github.com/hashicorp/terraform-plugin-log/tflog"
-	"github.com/pandatix/go-ctfd/api"
+	"github.com/ctfer-io/go-ctfd/api"
+	"github.com/opentofu/terraform-plugin-framework/diag"
+	"github.com/opentofu/terraform-plugin-framework/resource/schema"
+	"github.com/opentofu/terraform-plugin-framework/resource/schema/planmodifier"
+	"github.com/opentofu/terraform-plugin-framework/resource/schema/stringdefault"
+	"github.com/opentofu/terraform-plugin-framework/resource/schema/stringplanmodifier"
+	"github.com/opentofu/terraform-plugin-framework/types"
+	"github.com/opentofu/terraform-plugin-log/tflog"
 )
 
-type flagSubresourceModel struct {
+type FlagSubresourceModel struct {
 	ID      types.String `tfsdk:"id"`
 	Content types.String `tfsdk:"content"`
 	Data    types.String `tfsdk:"data"`
 	Type    types.String `tfsdk:"type"`
 }
 
-func flagSubresourceAttributes() map[string]schema.Attribute {
+func FlagSubresourceAttributes() map[string]schema.Attribute {
 	return map[string]schema.Attribute{
 		"id": schema.StringAttribute{
 			Computed:            true,
@@ -50,7 +50,7 @@ func flagSubresourceAttributes() map[string]schema.Attribute {
 	}
 }
 
-func (data *flagSubresourceModel) Create(ctx context.Context, diags diag.Diagnostics, client *api.Client, challengeID string) {
+func (data *FlagSubresourceModel) Create(ctx context.Context, diags diag.Diagnostics, client *api.Client, challengeID string) {
 	res, err := client.PostFlags(&api.PostFlagsParams{
 		Challenge: challengeID,
 		Content:   data.Content.ValueString(),
@@ -70,7 +70,7 @@ func (data *flagSubresourceModel) Create(ctx context.Context, diags diag.Diagnos
 	data.ID = types.StringValue(strconv.Itoa(res.ID))
 }
 
-func (data *flagSubresourceModel) Update(ctx context.Context, diags diag.Diagnostics, client *api.Client) {
+func (data *FlagSubresourceModel) Update(ctx context.Context, diags diag.Diagnostics, client *api.Client) {
 	res, err := client.PatchFlag(data.ID.ValueString(), &api.PatchFlagParams{
 		Content: data.Content.ValueString(),
 		Data:    data.Data.ValueString(),
@@ -92,7 +92,7 @@ func (data *flagSubresourceModel) Update(ctx context.Context, diags diag.Diagnos
 	data.Type = types.StringValue(res.Type)
 }
 
-func (data *flagSubresourceModel) Delete(ctx context.Context, diags diag.Diagnostics, client *api.Client) {
+func (data *FlagSubresourceModel) Delete(ctx context.Context, diags diag.Diagnostics, client *api.Client) {
 	if err := client.DeleteFlag(data.ID.ValueString(), api.WithContext(ctx)); err != nil {
 		diags.AddError(
 			"Client Error",
diff --git a/internal/provider/challenge/hint_subdata_source.go b/internal/provider/challenge/hint_subdata_source.go
index 1d2207e..7b0bdfe 100644
--- a/internal/provider/challenge/hint_subdata_source.go
+++ b/internal/provider/challenge/hint_subdata_source.go
@@ -1,11 +1,11 @@
 package challenge
 
 import (
-	"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
-	"github.com/hashicorp/terraform-plugin-framework/types"
+	"github.com/opentofu/terraform-plugin-framework/datasource/schema"
+	"github.com/opentofu/terraform-plugin-framework/types"
 )
 
-func hintSubdatasourceAttributes() map[string]schema.Attribute {
+func HintSubdatasourceAttributes() map[string]schema.Attribute {
 	return map[string]schema.Attribute{
 		"id": schema.StringAttribute{
 			Computed: true,
diff --git a/internal/provider/challenge/hint_subresource.go b/internal/provider/challenge/hint_subresource.go
index feb653f..f453768 100644
--- a/internal/provider/challenge/hint_subresource.go
+++ b/internal/provider/challenge/hint_subresource.go
@@ -5,26 +5,26 @@ import (
 	"fmt"
 	"strconv"
 
-	"github.com/hashicorp/terraform-plugin-framework/diag"
-	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
-	"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
-	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
-	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
-	"github.com/hashicorp/terraform-plugin-framework/types"
-	"github.com/hashicorp/terraform-plugin-log/tflog"
-	"github.com/pandatix/go-ctfd/api"
+	"github.com/ctfer-io/go-ctfd/api"
+	"github.com/opentofu/terraform-plugin-framework/diag"
+	"github.com/opentofu/terraform-plugin-framework/resource/schema"
+	"github.com/opentofu/terraform-plugin-framework/resource/schema/int64default"
+	"github.com/opentofu/terraform-plugin-framework/resource/schema/planmodifier"
+	"github.com/opentofu/terraform-plugin-framework/resource/schema/stringplanmodifier"
+	"github.com/opentofu/terraform-plugin-framework/types"
+	"github.com/opentofu/terraform-plugin-log/tflog"
 )
 
 // TODO requirements can be set manually, but can't be automatised. Hint may be a complete resource
 
-type hintSubresourceModel struct {
+type HintSubresourceModel struct {
 	ID           types.String   `tfsdk:"id"`
 	Content      types.String   `tfsdk:"content"`
 	Cost         types.Int64    `tfsdk:"cost"`
 	Requirements []types.String `tfsdk:"requirements"`
 }
 
-func hintSubresourceAttributes() map[string]schema.Attribute {
+func HintSubresourceAttributes() map[string]schema.Attribute {
 	return map[string]schema.Attribute{
 		"id": schema.StringAttribute{
 			Computed:            true,
@@ -48,7 +48,7 @@ func hintSubresourceAttributes() map[string]schema.Attribute {
 	}
 }
 
-func (data *hintSubresourceModel) Create(ctx context.Context, diags diag.Diagnostics, client *api.Client, challengeID string) {
+func (data *HintSubresourceModel) Create(ctx context.Context, diags diag.Diagnostics, client *api.Client, challengeID string) {
 	preq := make([]int, 0, len(data.Requirements))
 	for _, req := range data.Requirements {
 		hintID, _ := strconv.Atoi(req.ValueString())
@@ -76,7 +76,7 @@ func (data *hintSubresourceModel) Create(ctx context.Context, diags diag.Diagnos
 	data.ID = types.StringValue(strconv.Itoa(res.ID))
 }
 
-func (data *hintSubresourceModel) Update(ctx context.Context, diags diag.Diagnostics, client *api.Client) {
+func (data *HintSubresourceModel) Update(ctx context.Context, diags diag.Diagnostics, client *api.Client) {
 	preq := make([]int, 0, len(data.Requirements))
 	for _, req := range data.Requirements {
 		hintID, _ := strconv.Atoi(req.ValueString())
@@ -109,7 +109,7 @@ func (data *hintSubresourceModel) Update(ctx context.Context, diags diag.Diagnos
 	data.Requirements = dPreq
 }
 
-func (data *hintSubresourceModel) Delete(ctx context.Context, diags diag.Diagnostics, client *api.Client) {
+func (data *HintSubresourceModel) Delete(ctx context.Context, diags diag.Diagnostics, client *api.Client) {
 	if err := client.DeleteHint(data.ID.ValueString(), api.WithContext(ctx)); err != nil {
 		diags.AddError(
 			"Client Error",
diff --git a/internal/provider/challenge/requirements_subresource.go b/internal/provider/challenge/requirements_subresource.go
index 7bd10fa..da514ba 100644
--- a/internal/provider/challenge/requirements_subresource.go
+++ b/internal/provider/challenge/requirements_subresource.go
@@ -1,33 +1,36 @@
 package challenge
 
-import "github.com/hashicorp/terraform-plugin-framework/types"
+import (
+	"github.com/ctfer-io/terraform-provider-ctfd/internal/provider/utils"
+	"github.com/opentofu/terraform-plugin-framework/types"
+)
 
 var (
-	behaviorHidden     = types.StringValue("hidden")
-	behaviorAnonymized = types.StringValue("anonymized")
+	BehaviorHidden     = types.StringValue("hidden")
+	BehaviorAnonymized = types.StringValue("anonymized")
 )
 
-type requirementsSubresourceModel struct {
+type RequirementsSubresourceModel struct {
 	Behavior      types.String   `tfsdk:"behavior"`
 	Prerequisites []types.String `tfsdk:"prerequisites"`
 }
 
-func getAnon(str types.String) *bool {
+func GetAnon(str types.String) *bool {
 	switch {
-	case str.Equal(behaviorHidden):
+	case str.Equal(BehaviorHidden):
 		return nil
-	case str.Equal(behaviorAnonymized):
-		return ptr(true)
+	case str.Equal(BehaviorAnonymized):
+		return utils.Ptr(true)
 	}
 	panic("invalid anonymization value: " + str.ValueString())
 }
 
-func fromAnon(b *bool) types.String {
+func FromAnon(b *bool) types.String {
 	if b == nil {
-		return behaviorHidden
+		return BehaviorHidden
 	}
 	if *b {
-		return behaviorAnonymized
+		return BehaviorAnonymized
 	}
 	panic("invalid anonymization value, got boolean false")
 }
diff --git a/internal/provider/challenge/challenge_data_source.go b/internal/provider/challenge_data_source.go
similarity index 82%
rename from internal/provider/challenge/challenge_data_source.go
rename to internal/provider/challenge_data_source.go
index a49fc00..306f142 100644
--- a/internal/provider/challenge/challenge_data_source.go
+++ b/internal/provider/challenge_data_source.go
@@ -1,14 +1,16 @@
-package challenge
+package provider
 
 import (
 	"context"
 	"fmt"
 	"strconv"
 
-	"github.com/hashicorp/terraform-plugin-framework/datasource"
-	"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
-	"github.com/hashicorp/terraform-plugin-framework/types"
-	"github.com/pandatix/go-ctfd/api"
+	"github.com/ctfer-io/go-ctfd/api"
+	"github.com/ctfer-io/terraform-provider-ctfd/internal/provider/challenge"
+	"github.com/ctfer-io/terraform-provider-ctfd/internal/provider/utils"
+	"github.com/opentofu/terraform-plugin-framework/datasource"
+	"github.com/opentofu/terraform-plugin-framework/datasource/schema"
+	"github.com/opentofu/terraform-plugin-framework/types"
 )
 
 var (
@@ -25,6 +27,7 @@ type challengeDataSource struct {
 }
 
 type challengesDataSourceModel struct {
+	ID         types.String             `tfsdk:"id"`
 	Challenges []challengeResourceModel `tfsdk:"challenges"`
 }
 
@@ -35,6 +38,9 @@ func (ch *challengeDataSource) Metadata(ctx context.Context, req datasource.Meta
 func (ch *challengeDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
 	resp.Schema = schema.Schema{
 		Attributes: map[string]schema.Attribute{
+			"id": schema.StringAttribute{
+				Computed: true,
+			},
 			"challenges": schema.ListNestedAttribute{
 				Computed: true,
 				NestedObject: schema.NestedAttributeObject{
@@ -71,7 +77,7 @@ func (ch *challengeDataSource) Schema(ctx context.Context, req datasource.Schema
 						},
 						"flags": schema.ListNestedAttribute{
 							NestedObject: schema.NestedAttributeObject{
-								Attributes: flagSubdatasourceAttributes(),
+								Attributes: challenge.FlagSubdatasourceAttributes(),
 							},
 							Computed: true,
 						},
@@ -85,13 +91,13 @@ func (ch *challengeDataSource) Schema(ctx context.Context, req datasource.Schema
 						},
 						"hints": schema.ListNestedAttribute{
 							NestedObject: schema.NestedAttributeObject{
-								Attributes: hintSubdatasourceAttributes(),
+								Attributes: challenge.HintSubdatasourceAttributes(),
 							},
 							Computed: true,
 						},
 						"files": schema.ListNestedAttribute{
 							NestedObject: schema.NestedAttributeObject{
-								Attributes: fileSubdatasourceAttributes(),
+								Attributes: challenge.FileSubdatasourceAttributes(),
 							},
 							Computed: true,
 						},
@@ -111,7 +117,7 @@ func (ch *challengeDataSource) Configure(ctx context.Context, req datasource.Con
 	if !ok {
 		resp.Diagnostics.AddError(
 			"Unexpected Data Source Configure Type",
-			fmt.Sprintf("Expected *github.com/pandatix/go-ctfd/api.Client, got: %T. Please open an issue at https://github.com/pandatix/terraform-provider-ctfd", req.ProviderData),
+			fmt.Sprintf("Expected *github.com/ctfer-io/go-ctfd/api.Client, got: %T. Please open an issue at https://github.com/ctfer-io/terraform-provider-ctfd", req.ProviderData),
 		)
 		return
 	}
@@ -151,9 +157,9 @@ func (ch *challengeDataSource) Read(ctx context.Context, req datasource.ReadRequ
 			)
 			return
 		}
-		challFiles := make([]fileSubresourceModel, 0, len(files))
+		challFiles := make([]challenge.FileSubresourceModel, 0, len(files))
 		for _, file := range files {
-			f := fileSubresourceModel{
+			f := challenge.FileSubresourceModel{
 				ID:       types.StringValue(strconv.Itoa(file.ID)),
 				Location: types.StringValue(file.Location),
 			}
@@ -171,9 +177,9 @@ func (ch *challengeDataSource) Read(ctx context.Context, req datasource.ReadRequ
 			)
 			return
 		}
-		challFlags := make([]flagSubresourceModel, 0, len(flags))
+		challFlags := make([]challenge.FlagSubresourceModel, 0, len(flags))
 		for _, flag := range flags {
-			challFlags = append(challFlags, flagSubresourceModel{
+			challFlags = append(challFlags, challenge.FlagSubresourceModel{
 				ID:      types.StringValue(strconv.Itoa(flag.ID)),
 				Content: types.StringValue(flag.Content),
 				// XXX this should be properly typed
@@ -219,13 +225,13 @@ func (ch *challengeDataSource) Read(ctx context.Context, req datasource.ReadRequ
 			)
 			return
 		}
-		challHints := make([]hintSubresourceModel, 0, len(hints))
+		challHints := make([]challenge.HintSubresourceModel, 0, len(hints))
 		for _, hint := range hints {
 			hintReq := make([]types.String, 0, len(hint.Requirements.Prerequisites))
 			for _, preq := range hint.Requirements.Prerequisites {
 				hintReq = append(hintReq, types.StringValue(strconv.Itoa(preq)))
 			}
-			challHints = append(challHints, hintSubresourceModel{
+			challHints = append(challHints, challenge.HintSubresourceModel{
 				ID:           types.StringValue(strconv.Itoa(hint.ID)),
 				Content:      types.StringValue(*hint.Content),
 				Cost:         types.Int64Value(int64(hint.Cost)),
@@ -238,10 +244,10 @@ func (ch *challengeDataSource) Read(ctx context.Context, req datasource.ReadRequ
 			Name:        types.StringValue(chall.Name),
 			Category:    types.StringValue(chall.Category),
 			Description: types.StringValue(chall.Description),
-			Value:       toTFInt64(chall.Value),
-			Initial:     toTFInt64(chall.Initial),
-			Decay:       toTFInt64(chall.Decay),
-			Minimum:     toTFInt64(chall.Minimum),
+			Value:       utils.ToTFInt64(chall.Value),
+			Initial:     utils.ToTFInt64(chall.Initial),
+			Decay:       utils.ToTFInt64(chall.Decay),
+			Minimum:     utils.ToTFInt64(chall.Minimum),
 			State:       types.StringValue(chall.State),
 			Type:        types.StringValue(chall.Type),
 			Files:       challFiles,
@@ -251,6 +257,7 @@ func (ch *challengeDataSource) Read(ctx context.Context, req datasource.ReadRequ
 			Hints:       challHints,
 		}
 
+		state.ID = types.StringValue("placeholder")
 		state.Challenges = append(state.Challenges, challState)
 	}
 
diff --git a/internal/provider/challenge_data_source_test.go b/internal/provider/challenge_data_source_test.go
new file mode 100644
index 0000000..1f19c69
--- /dev/null
+++ b/internal/provider/challenge_data_source_test.go
@@ -0,0 +1,20 @@
+package provider_test
+
+import (
+	"testing"
+
+	"github.com/opentofu/terraform-plugin-testing/helper/resource"
+)
+
+func TestAccChallengeDataSource(t *testing.T) {
+	resource.Test(t, resource.TestCase{
+		ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+		Steps: []resource.TestStep{
+			// Read testing
+			{
+				Config: `data "ctfd_challenge" "test" {}`,
+				Check:  resource.C,
+			},
+		},
+	})
+}
diff --git a/internal/provider/challenge/challenge_resource.go b/internal/provider/challenge_resource.go
similarity index 81%
rename from internal/provider/challenge/challenge_resource.go
rename to internal/provider/challenge_resource.go
index 12ac68f..c2b8edc 100644
--- a/internal/provider/challenge/challenge_resource.go
+++ b/internal/provider/challenge_resource.go
@@ -1,23 +1,25 @@
-package challenge
+package provider
 
 import (
 	"context"
 	"fmt"
 	"strconv"
 
-	"github.com/hashicorp/terraform-plugin-framework/path"
-	"github.com/hashicorp/terraform-plugin-framework/resource"
-	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
-	"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
-	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
-	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
-	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
-	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
-	"github.com/hashicorp/terraform-plugin-framework/types"
-	"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
-	"github.com/hashicorp/terraform-plugin-log/tflog"
-	api "github.com/pandatix/go-ctfd/api"
-	"github.com/pandatix/terraform-provider-ctfd/internal/provider/validators"
+	api "github.com/ctfer-io/go-ctfd/api"
+	"github.com/ctfer-io/terraform-provider-ctfd/internal/provider/challenge"
+	"github.com/ctfer-io/terraform-provider-ctfd/internal/provider/utils"
+	"github.com/ctfer-io/terraform-provider-ctfd/internal/provider/validators"
+	"github.com/opentofu/terraform-plugin-framework/path"
+	"github.com/opentofu/terraform-plugin-framework/resource"
+	"github.com/opentofu/terraform-plugin-framework/resource/schema"
+	"github.com/opentofu/terraform-plugin-framework/resource/schema/int64default"
+	"github.com/opentofu/terraform-plugin-framework/resource/schema/planmodifier"
+	"github.com/opentofu/terraform-plugin-framework/resource/schema/stringdefault"
+	"github.com/opentofu/terraform-plugin-framework/resource/schema/stringplanmodifier"
+	"github.com/opentofu/terraform-plugin-framework/schema/validator"
+	"github.com/opentofu/terraform-plugin-framework/types"
+	"github.com/opentofu/terraform-plugin-framework/types/basetypes"
+	"github.com/opentofu/terraform-plugin-log/tflog"
 )
 
 var (
@@ -35,24 +37,24 @@ type challengeResource struct {
 }
 
 type challengeResourceModel struct {
-	ID             types.String                  `tfsdk:"id"`
-	Name           types.String                  `tfsdk:"name"`
-	Category       types.String                  `tfsdk:"category"`
-	Description    types.String                  `tfsdk:"description"`
-	ConnectionInfo types.String                  `tfsdk:"connection_info"`
-	MaxAttempts    types.Int64                   `tfsdk:"max_attempts"`
-	Value          types.Int64                   `tfsdk:"value"`
-	Initial        types.Int64                   `tfsdk:"initial"`
-	Decay          types.Int64                   `tfsdk:"decay"`
-	Minimum        types.Int64                   `tfsdk:"minimum"`
-	State          types.String                  `tfsdk:"state"`
-	Type           types.String                  `tfsdk:"type"`
-	Requirements   *requirementsSubresourceModel `tfsdk:"requirements"`
-	Flags          []flagSubresourceModel        `tfsdk:"flags"`
-	Tags           []types.String                `tfsdk:"tags"`
-	Topics         []types.String                `tfsdk:"topics"`
-	Hints          []hintSubresourceModel        `tfsdk:"hints"`
-	Files          []fileSubresourceModel        `tfsdk:"files"`
+	ID             types.String                            `tfsdk:"id"`
+	Name           types.String                            `tfsdk:"name"`
+	Category       types.String                            `tfsdk:"category"`
+	Description    types.String                            `tfsdk:"description"`
+	ConnectionInfo types.String                            `tfsdk:"connection_info"`
+	MaxAttempts    types.Int64                             `tfsdk:"max_attempts"`
+	Value          types.Int64                             `tfsdk:"value"`
+	Initial        types.Int64                             `tfsdk:"initial"`
+	Decay          types.Int64                             `tfsdk:"decay"`
+	Minimum        types.Int64                             `tfsdk:"minimum"`
+	State          types.String                            `tfsdk:"state"`
+	Type           types.String                            `tfsdk:"type"`
+	Requirements   *challenge.RequirementsSubresourceModel `tfsdk:"requirements"`
+	Flags          []challenge.FlagSubresourceModel        `tfsdk:"flags"`
+	Tags           []types.String                          `tfsdk:"tags"`
+	Topics         []types.String                          `tfsdk:"topics"`
+	Hints          []challenge.HintSubresourceModel        `tfsdk:"hints"`
+	Files          []challenge.FileSubresourceModel        `tfsdk:"files"`
 }
 
 func (r *challengeResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
@@ -126,8 +128,8 @@ func (r *challengeResource) Schema(ctx context.Context, req resource.SchemaReque
 						Default:             stringdefault.StaticString("hidden"),
 						Validators: []validator.String{
 							validators.NewStringEnumValidator([]basetypes.StringValue{
-								behaviorHidden,
-								behaviorAnonymized,
+								challenge.BehaviorHidden,
+								challenge.BehaviorAnonymized,
 							}),
 						},
 					},
@@ -139,7 +141,7 @@ func (r *challengeResource) Schema(ctx context.Context, req resource.SchemaReque
 			},
 			"flags": schema.ListNestedAttribute{
 				NestedObject: schema.NestedAttributeObject{
-					Attributes: flagSubresourceAttributes(),
+					Attributes: challenge.FlagSubresourceAttributes(),
 				},
 				Optional: true,
 			},
@@ -153,14 +155,14 @@ func (r *challengeResource) Schema(ctx context.Context, req resource.SchemaReque
 			},
 			"hints": schema.ListNestedAttribute{
 				NestedObject: schema.NestedAttributeObject{
-					Attributes: hintSubresourceAttributes(),
+					Attributes: challenge.HintSubresourceAttributes(),
 				},
 				Optional: true,
 			},
 			"files": schema.ListNestedAttribute{
 				// TODO find why modifying other fields requires updating those
 				NestedObject: schema.NestedAttributeObject{
-					Attributes: fileSubresourceAttributes(),
+					Attributes: challenge.FileSubresourceAttributes(),
 				},
 				Optional: true,
 			},
@@ -178,7 +180,7 @@ func (r *challengeResource) Configure(ctx context.Context, req resource.Configur
 	if !ok {
 		resp.Diagnostics.AddError(
 			"Unexpected Resource Configure Type",
-			fmt.Sprintf("Expected *github.com/pandatix/go-ctfd/api.Client, got: %T. Please open an issue at https://github.com/pandatix/terraform-provider-ctfd", req.ProviderData),
+			fmt.Sprintf("Expected *github.com/ctfer-io/go-ctfd/api.Client, got: %T. Please open an issue at https://github.com/ctfer-io/terraform-provider-ctfd", req.ProviderData),
 		)
 		return
 	}
@@ -202,7 +204,7 @@ func (r *challengeResource) Create(ctx context.Context, req resource.CreateReque
 			preqs = append(preqs, id)
 		}
 		reqs = &api.Requirements{
-			Anonymize:     getAnon(data.Requirements.Behavior),
+			Anonymize:     challenge.GetAnon(data.Requirements.Behavior),
 			Prerequisites: preqs,
 		}
 	}
@@ -211,11 +213,11 @@ func (r *challengeResource) Create(ctx context.Context, req resource.CreateReque
 		Category:       data.Category.ValueString(),
 		Description:    data.Description.ValueString(),
 		ConnectionInfo: data.ConnectionInfo.ValueStringPointer(),
-		MaxAttempts:    toInt(data.MaxAttempts),
-		Value:          toInt(data.Value),
-		Initial:        toInt(data.Initial),
-		Decay:          toInt(data.Decay),
-		Minimum:        toInt(data.Minimum),
+		MaxAttempts:    utils.ToInt(data.MaxAttempts),
+		Value:          utils.ToInt(data.Value),
+		Initial:        utils.ToInt(data.Initial),
+		Decay:          utils.ToInt(data.Decay),
+		Minimum:        utils.ToInt(data.Minimum),
 		State:          data.State.ValueString(),
 		Type:           data.Type.ValueString(),
 		Requirements:   reqs,
@@ -234,7 +236,7 @@ func (r *challengeResource) Create(ctx context.Context, req resource.CreateReque
 	data.ID = types.StringValue(strconv.Itoa(res.ID))
 
 	// Create files
-	challFiles := make([]fileSubresourceModel, 0, len(data.Files))
+	challFiles := make([]challenge.FileSubresourceModel, 0, len(data.Files))
 	for _, file := range data.Files {
 		file.Create(ctx, resp.Diagnostics, r.client, data.ID.ValueString())
 		challFiles = append(challFiles, file)
@@ -244,7 +246,7 @@ func (r *challengeResource) Create(ctx context.Context, req resource.CreateReque
 	}
 
 	// Create flags
-	challFlags := make([]flagSubresourceModel, 0, len(data.Flags))
+	challFlags := make([]challenge.FlagSubresourceModel, 0, len(data.Flags))
 	for _, flag := range data.Flags {
 		flag.Create(ctx, resp.Diagnostics, r.client, data.ID.ValueString())
 		challFlags = append(challFlags, flag)
@@ -295,7 +297,7 @@ func (r *challengeResource) Create(ctx context.Context, req resource.CreateReque
 	}
 
 	// Create hints
-	challHints := make([]hintSubresourceModel, 0, len(data.Hints))
+	challHints := make([]challenge.HintSubresourceModel, 0, len(data.Hints))
 	for _, hint := range data.Hints {
 		hint.Create(ctx, resp.Diagnostics, r.client, data.ID.ValueString())
 		challHints = append(challHints, hint)
@@ -328,10 +330,10 @@ func (r *challengeResource) Read(ctx context.Context, req resource.ReadRequest,
 	data.Description = types.StringValue(res.Description)
 	data.ConnectionInfo = types.StringValue(res.ConnectionInfo)
 	data.MaxAttempts = types.Int64Value(int64(res.MaxAttempts))
-	data.Value = toTFInt64(res.Value)
-	data.Initial = toTFInt64(res.Initial)
-	data.Decay = toTFInt64(res.Decay)
-	data.Minimum = toTFInt64(res.Minimum)
+	data.Value = utils.ToTFInt64(res.Value)
+	data.Initial = utils.ToTFInt64(res.Initial)
+	data.Decay = utils.ToTFInt64(res.Decay)
+	data.Minimum = utils.ToTFInt64(res.Minimum)
 	data.State = types.StringValue(res.State)
 	data.Type = types.StringValue(res.Type)
 
@@ -343,14 +345,14 @@ func (r *challengeResource) Read(ctx context.Context, req resource.ReadRequest,
 			fmt.Sprintf("Unable to read requirements of challenge %s, got error: %s", data.ID.ValueString(), err),
 		)
 	}
-	reqs := (*requirementsSubresourceModel)(nil)
+	reqs := (*challenge.RequirementsSubresourceModel)(nil)
 	if resReqs != nil {
 		challReqs := make([]types.String, 0, len(resReqs.Prerequisites))
 		for _, req := range resReqs.Prerequisites {
 			challReqs = append(challReqs, types.StringValue(strconv.Itoa(req)))
 		}
-		reqs = &requirementsSubresourceModel{
-			Behavior:      fromAnon(resReqs.Anonymize),
+		reqs = &challenge.RequirementsSubresourceModel{
+			Behavior:      challenge.FromAnon(resReqs.Anonymize),
 			Prerequisites: challReqs,
 		}
 	}
@@ -364,12 +366,12 @@ func (r *challengeResource) Read(ctx context.Context, req resource.ReadRequest,
 			fmt.Sprintf("Unable to read files of challenge %s, got error: %s", data.ID.ValueString(), err),
 		)
 	}
-	challFiles := make([]fileSubresourceModel, 0, len(resFiles))
+	challFiles := make([]challenge.FileSubresourceModel, 0, len(resFiles))
 	for _, file := range resFiles {
-		f := fileSubresourceModel{
+		f := challenge.FileSubresourceModel{
 			ID:       types.StringValue(strconv.Itoa(file.ID)),
 			Location: types.StringValue(file.Location),
-			Name:     types.StringValue(filename(file.Location)),
+			Name:     types.StringValue(utils.Filename(file.Location)),
 		}
 		f.Read(ctx, resp.Diagnostics, r.client)
 		challFiles = append(challFiles, f)
@@ -387,9 +389,9 @@ func (r *challengeResource) Read(ctx context.Context, req resource.ReadRequest,
 		)
 		return
 	}
-	challFlags := make([]flagSubresourceModel, 0, len(resFlags))
+	challFlags := make([]challenge.FlagSubresourceModel, 0, len(resFlags))
 	for _, flag := range resFlags {
-		challFlags = append(challFlags, flagSubresourceModel{
+		challFlags = append(challFlags, challenge.FlagSubresourceModel{
 			ID:      types.StringValue(strconv.Itoa(flag.ID)),
 			Content: types.StringValue(flag.Content),
 			// XXX this should be typed properly
@@ -444,7 +446,7 @@ func (r *challengeResource) Read(ctx context.Context, req resource.ReadRequest,
 		)
 		return
 	}
-	challHints := make([]hintSubresourceModel, 0, len(resHints))
+	challHints := make([]challenge.HintSubresourceModel, 0, len(resHints))
 	for _, hint := range resHints {
 		hintReqs := make([]types.String, 0, len(hint.Requirements.Prerequisites))
 		for _, req := range hint.Requirements.Prerequisites {
@@ -453,7 +455,7 @@ func (r *challengeResource) Read(ctx context.Context, req resource.ReadRequest,
 		if len(hint.Requirements.Prerequisites) == 0 {
 			hintReqs = nil
 		}
-		challHints = append(challHints, hintSubresourceModel{
+		challHints = append(challHints, challenge.HintSubresourceModel{
 			ID:           types.StringValue(strconv.Itoa(hint.ID)),
 			Content:      types.StringValue(*hint.Content),
 			Cost:         types.Int64Value(int64(hint.Cost)),
@@ -488,7 +490,7 @@ func (r *challengeResource) Update(ctx context.Context, req resource.UpdateReque
 			preqs = append(preqs, id)
 		}
 		reqs = &api.Requirements{
-			Anonymize:     getAnon(data.Requirements.Behavior),
+			Anonymize:     challenge.GetAnon(data.Requirements.Behavior),
 			Prerequisites: preqs,
 		}
 	}
@@ -497,11 +499,11 @@ func (r *challengeResource) Update(ctx context.Context, req resource.UpdateReque
 		Category:       data.Category.ValueStringPointer(),
 		Description:    data.Description.ValueStringPointer(),
 		ConnectionInfo: data.ConnectionInfo.ValueStringPointer(),
-		MaxAttempts:    toInt(data.MaxAttempts),
-		Value:          toInt(data.Value),
-		Initial:        toInt(data.Initial),
-		Decay:          toInt(data.Decay),
-		Minimum:        toInt(data.Minimum),
+		MaxAttempts:    utils.ToInt(data.MaxAttempts),
+		Value:          utils.ToInt(data.Value),
+		Initial:        utils.ToInt(data.Initial),
+		Decay:          utils.ToInt(data.Decay),
+		Minimum:        utils.ToInt(data.Minimum),
 		State:          data.State.ValueStringPointer(),
 		Requirements:   reqs,
 	}, api.WithContext(ctx))
@@ -521,7 +523,7 @@ func (r *challengeResource) Update(ctx context.Context, req resource.UpdateReque
 			fmt.Sprintf("Unable to get challenge's files, got error: %s", err),
 		)
 	}
-	files := []fileSubresourceModel{}
+	files := []challenge.FileSubresourceModel{}
 	for _, file := range data.Files {
 		exists := false
 		for _, currentFile := range currentFiles {
@@ -529,7 +531,7 @@ func (r *challengeResource) Update(ctx context.Context, req resource.UpdateReque
 				exists = true
 
 				// Get corresponding file from state
-				var corFile fileSubresourceModel
+				var corFile challenge.FileSubresourceModel
 				for _, fState := range dataState.Files {
 					if file.ID.Equal(fState.ID) {
 						corFile = fState
@@ -562,7 +564,7 @@ func (r *challengeResource) Update(ctx context.Context, req resource.UpdateReque
 			}
 		}
 		if !exists {
-			f := fileSubresourceModel{
+			f := challenge.FileSubresourceModel{
 				ID:       types.StringValue(strconv.Itoa(currentFile.ID)),
 				Location: types.StringValue(currentFile.Location),
 			}
@@ -582,7 +584,7 @@ func (r *challengeResource) Update(ctx context.Context, req resource.UpdateReque
 		)
 		return
 	}
-	flags := []flagSubresourceModel{}
+	flags := []challenge.FlagSubresourceModel{}
 	for _, tfFlag := range data.Flags {
 		exists := false
 		for _, currentFlag := range currentFlags {
@@ -607,7 +609,7 @@ func (r *challengeResource) Update(ctx context.Context, req resource.UpdateReque
 			}
 		}
 		if !exists {
-			f := &flagSubresourceModel{
+			f := &challenge.FlagSubresourceModel{
 				ID: types.StringValue(strconv.Itoa(currentFlag.ID)),
 			}
 			f.Delete(ctx, resp.Diagnostics, r.client)
@@ -701,7 +703,7 @@ func (r *challengeResource) Update(ctx context.Context, req resource.UpdateReque
 		)
 		return
 	}
-	hints := []hintSubresourceModel{}
+	hints := []challenge.HintSubresourceModel{}
 	for _, tfHint := range data.Hints {
 		exists := false
 		for _, currentHint := range currentHints {
@@ -726,7 +728,7 @@ func (r *challengeResource) Update(ctx context.Context, req resource.UpdateReque
 			}
 		}
 		if !exists {
-			h := &hintSubresourceModel{
+			h := &challenge.HintSubresourceModel{
 				ID: types.StringValue(strconv.Itoa(currentHint.ID)),
 			}
 			h.Delete(ctx, resp.Diagnostics, r.client)
diff --git a/internal/provider/provider.go b/internal/provider/provider.go
index 5bb7bdd..b595b64 100644
--- a/internal/provider/provider.go
+++ b/internal/provider/provider.go
@@ -4,15 +4,14 @@ import (
 	"context"
 	"os"
 
-	"github.com/hashicorp/terraform-plugin-framework/datasource"
-	"github.com/hashicorp/terraform-plugin-framework/path"
-	"github.com/hashicorp/terraform-plugin-framework/provider"
-	"github.com/hashicorp/terraform-plugin-framework/provider/schema"
-	"github.com/hashicorp/terraform-plugin-framework/resource"
-	"github.com/hashicorp/terraform-plugin-framework/types"
-	"github.com/hashicorp/terraform-plugin-log/tflog"
-	"github.com/pandatix/go-ctfd/api"
-	"github.com/pandatix/terraform-provider-ctfd/internal/provider/challenge"
+	"github.com/ctfer-io/go-ctfd/api"
+	"github.com/opentofu/terraform-plugin-framework/datasource"
+	"github.com/opentofu/terraform-plugin-framework/path"
+	"github.com/opentofu/terraform-plugin-framework/provider"
+	"github.com/opentofu/terraform-plugin-framework/provider/schema"
+	"github.com/opentofu/terraform-plugin-framework/resource"
+	"github.com/opentofu/terraform-plugin-framework/types"
+	"github.com/opentofu/terraform-plugin-log/tflog"
 )
 
 var _ provider.Provider = &CTFdProvider{}
@@ -157,12 +156,12 @@ func (p *CTFdProvider) Configure(ctx context.Context, req provider.ConfigureRequ
 
 func (p *CTFdProvider) Resources(ctx context.Context) []func() resource.Resource {
 	return []func() resource.Resource{
-		challenge.NewChallengeResource,
+		NewChallengeResource,
 	}
 }
 
 func (p *CTFdProvider) DataSources(ctx context.Context) []func() datasource.DataSource {
 	return []func() datasource.DataSource{
-		challenge.NewChallengeDataSource,
+		NewChallengeDataSource,
 	}
 }
diff --git a/internal/provider/provider_test.go b/internal/provider/provider_test.go
new file mode 100644
index 0000000..14a06ba
--- /dev/null
+++ b/internal/provider/provider_test.go
@@ -0,0 +1,22 @@
+package provider_test
+
+import (
+	"github.com/opentofu/terraform-plugin-framework/providerserver"
+	"github.com/opentofu/terraform-plugin-go/tfprotov6"
+)
+
+const (
+	providerConfig = `
+provider "ctfd" {
+	username = "never gonna give you up"
+	password = "never gonna let you down"
+	host     = "https://example.ctfer.io"
+}
+`
+)
+
+var (
+	testAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){
+		"ctfd": providerserver.NewProtocol6WithError(New("test")()),
+	}
+)
diff --git a/internal/provider/utils.go b/internal/provider/utils.go
index 7a5036f..a405489 100644
--- a/internal/provider/utils.go
+++ b/internal/provider/utils.go
@@ -3,7 +3,7 @@ package provider
 import (
 	"context"
 
-	"github.com/hashicorp/terraform-plugin-log/tflog"
+	"github.com/opentofu/terraform-plugin-log/tflog"
 )
 
 func addSensitive(ctx context.Context, key string, value any) context.Context {
diff --git a/internal/provider/challenge/utils.go b/internal/provider/utils/utils.go
similarity index 64%
rename from internal/provider/challenge/utils.go
rename to internal/provider/utils/utils.go
index 2713752..a02076f 100644
--- a/internal/provider/challenge/utils.go
+++ b/internal/provider/utils/utils.go
@@ -1,13 +1,13 @@
-package challenge
+package utils
 
 import (
 	"strings"
 
-	"github.com/hashicorp/terraform-plugin-framework/types"
+	"github.com/opentofu/terraform-plugin-framework/types"
 )
 
 // return a null types.Int64 if pointer is nil, else its value
-func toTFInt64(i *int) types.Int64 {
+func ToTFInt64(i *int) types.Int64 {
 	if i == nil {
 		return types.Int64Null()
 	}
@@ -15,7 +15,7 @@ func toTFInt64(i *int) types.Int64 {
 }
 
 // return a nil point if types.Int64 is null, else its value
-func toInt(itf types.Int64) *int {
+func ToInt(itf types.Int64) *int {
 	if itf.IsNull() {
 		return nil
 	}
@@ -23,11 +23,11 @@ func toInt(itf types.Int64) *int {
 	return &i
 }
 
-func filename(location string) string {
+func Filename(location string) string {
 	pts := strings.Split(location, "/")
 	return pts[len(pts)-1]
 }
 
-func ptr[T any](t T) *T {
+func Ptr[T any](t T) *T {
 	return &t
 }
diff --git a/internal/provider/validators/string_enum.go b/internal/provider/validators/string_enum.go
index a44ce87..111b490 100644
--- a/internal/provider/validators/string_enum.go
+++ b/internal/provider/validators/string_enum.go
@@ -3,8 +3,8 @@ package validators
 import (
 	"context"
 
-	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
-	"github.com/hashicorp/terraform-plugin-framework/types"
+	"github.com/opentofu/terraform-plugin-framework/schema/validator"
+	"github.com/opentofu/terraform-plugin-framework/types"
 )
 
 // StringEnumValidator valides a string value in an enumeration.
diff --git a/main.go b/main.go
index ed11643..5d0f453 100644
--- a/main.go
+++ b/main.go
@@ -5,8 +5,8 @@ import (
 	"flag"
 	"log"
 
-	"github.com/hashicorp/terraform-plugin-framework/providerserver"
-	"github.com/pandatix/terraform-provider-ctfd/internal/provider"
+	"github.com/ctfer-io/terraform-provider-ctfd/internal/provider"
+	"github.com/opentofu/terraform-plugin-framework/providerserver"
 )
 
 var (
@@ -20,7 +20,7 @@ func main() {
 	flag.Parse()
 
 	opts := providerserver.ServeOpts{
-		Address: "registry.terraform.io/pandatix/ctfd",
+		Address: "registry.terraform.io/ctfer-io/ctfd",
 		Debug:   debug,
 	}